Rust for Java Devs: Compiling Code and Using Cargo
As our journey to discover Rust continues, let's see how compilation compares to Java and learn how to use the built-in Cargo build tool.
Join the DZone community and get the full member experience.Join For Free
After my last post seemed to be well-received, I am back with another Rust for Java Devs post. Today, we will look at compiling Rust code and using the basics of Cargo. For a developer, there isn’t much difference between how to compile Rust code compared to Java, but where they vary are their build tools. Rust comes built-in with Cargo to manage projects, whereas Java does not and relies on external build tools like Maven and Gradle. We can then use Cargo to build and run projects instead of directly compiling and executing the created
So let's jump in.
In my previous post Rust for Java Devs: Creating Variables, I showed code examples and what they output, but without any other knowledge, you would not be able to try it yourself because you can’t compile it. I am here to correct that.
Compiling is straightforward and, most likely, you won’t actually need to use it very often — as you will use Cargo instead. Nevertheless, it is still worth knowing how to compile your code manually. To compile your code, run the
rustc command with the name of the file you wish to compile.
rustc main.rs ./main (run on Linux or OSX) ./main.exe (run on Windows)
That's it. The output of the compiled Rust source code is an executable that can then be run when needed.
The Java version of the same process is:
javac main.java java main
As you can see, there isn’t much difference between them in terms of what you need to enter into the command line. Where they do differ is that Rust produces an
.exe file, which is why it does not mention Rust at all and can be executed by anyone, even if they do no have Rust on their machine, whereas the Java version uses another command to run the
.class file it creates and therefore requires Java to be installed on the machine it is run on.
Now that the more fundamental stuff is out of the way, we can look at the build tools that both Rust and Java have available, which are normally used to compile/build and run your code. As mentioned earlier, Rust uses Cargo, which is a build system and package manager that comes out of the box with Rust. Java does not have a inbuilt build tool but can use external tools such as Maven and Gradle. If you are familiar with either of those, I doubt that Cargo will look alien to you, even if the syntax is different.
Let's go through the process of creating and running a Cargo project.
First of all, we need to run the
cargo new command. This includes the name of the project and its type. Add
--bin for a binary executable file or to create a library. Then, there is no need to add anything extra.
cargo new my_rust_project --bin
After running the above command, we will have a new directory created called
my_rust_project that contains a few files inside of it. Firstly, there is the
main.rs file inside the
src directory containing a little hello world program (I assume you will delete this!) where the main executable code will go. By default, Cargo will look for a
main.rs (executable) or
lib.rs (library) file. Next, you will notice that there is a
.gitignore file. Yes, Cargo initialized a Git repository for you and ignored the files in the target directory. Finally, there are the
Cargo.toml files. Below is the generated
[package] name = "my_rust_project" version = "0.1.0" authors = ["Dan Newton <firstname.lastname@example.org>"] [dependencies]
Obviously, your project won't have my name and email in it. Cargo uses TOML (Tom’s Obvious, Minimal Language) instead of XML, which Maven uses, or the Groovy-like DSL that Gradle requires.
Cargo.toml file is pretty empty, as we do not have any dependencies or any other configuration. If we wanted to add a dependency to it, it would look something like below.
[package] name = "my_rust_project" version = "0.1.0" authors = ["Dan Newton <email@example.com>"] [dependencies] rand = "0.3.14"
This will pull in a dependency on the rand crate (a crate is what Rust calls a library) with any version that is compatible with
If this was done in Maven, it would look like this (I haven’t used Gradle myself so I won’t show one for it).
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>my_rust_project</groupId> <artifactId>my_rust_project</artifactId> <version>0.1.0</version> <dependencies> <dependency> <groupId>some_group</groupId> <artifactId>rand</artifactId> <version>0.3.14</version> </dependency> </dependencies> </project>
Finally, there is the
Cargo.lock file. This contains the dependencies that are actually used within your project, as these could differ from what is shown in the
Cargo.toml file. Below is what it will look like after running
[[package]] name = "my_rust_project" version = "0.1.0"
Again this is empty, but we will review this later.
Now that we have gone through the files created for us, we need to know what we can actually do with them. For the scope of this post, we have the following commands:
cargo build or
cargo run. Running either one will build the project, but
cargo run performs an extra step. As the name suggests, it runs the created executable. It might take a while the first time you build the whole project, but Cargo is smart enough to figure out which files have changed and only recompile the changes.
This is where the
Cargo.lock comes back into the game. After running
cargo build or
cargo run (whatever, just build the damn project) any dependencies that are used will be added to the file. Below is what is now contained within
Cargo.lock when we have a dependency on the rand crate.
[[package]] name = "bitflags" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "fuchsia-zircon" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "fuchsia-zircon-sys" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" version = "0.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "my_rust_project" version = "0.1.0" dependencies = [ "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand" version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", ]
There is quite a lot in here now. Because we are using the rand crate, all of its dependencies have also been pulled into our project, which is why the lock file is now so full. You can use the
cargo update command to update your dependencies to newer versions based on what is in your
Cargo.toml file. These will be versions larger than
0.3.0 and smaller than
0.4.0 for the rand crate in this example. To up the version even more, we will need to change the version in
I think we have covered what is needed for a basic understanding of compiling Rust code manually as well as using Cargo as our build tool. I haven’t done much comparing Cargo to Java’s build tools, but I think there is enough information here to allow you to make your own comparison to your preferred tool.
In conclusion, there is not much difference in the process of compiling Rust code vs. Java code, but it is important to note that the outputs of each differ quite considerably. Rust will produce an
.exe whereas Java creates a
.class file, meaning that Rust compiles to an executable that can be run without Rust being locally installed, whereas Java needs to be installed to run its compiled code. Each language has its own build tools, but Rust comes with Cargo ready to go whereas Java uses external tools. Which system is better is up to you, and I’m sure my own opinion will form once I have delved deeper into Rust myself and actually need to put together a more complex build.
If you are new to Rust and want to learn more about it, I suggest viewing the Rust Book, which I think is an excellent resource for getting started with Rust.
Published at DZone with permission of Dan Newton, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.