-
Book Overview & Buying
-
Table Of Contents
Practical System Programming for Rust Developers
By :
You learned in the previous section how Cargo can be used to set up the base project directory structure and scaffolding for a new project, and how to build various types of binary and library crates. We will look at the dependency management features of Cargo in this section.
Rust comes with a built-in standard library consisting of language primitives and commonly used functions, but it is small by design (compared to other languages). Most real-world programs in Rust depend on additional external libraries to improve functionality and developer productivity. Any such external code that is used is a dependency for the program. Cargo makes it easy to specify and manage dependencies.
In the Rust ecosystem, crates.io is the central public package registry for discovering and downloading libraries (called packages or crates in Rust). It is similar to npm in the JavaScript world. Cargo uses crates.io as the default package registry.
Dependencies are specified in the [dependencies] section of Cargo.toml. Let's see an example.
Start a new project with this command:
cargo new deps-example && cd deps-example
In Cargo.toml, make the following entry to include an external library:
[dependencies] chrono = "0.4.0"
Chrono is a datetime library. This is called a dependency because our deps-example crate depends on this external library for its functionality.
When you run cargo build, cargo looks for a crate on crates.io with this name and version. If found, it downloads this crate along with all of its dependencies, compiles them all, and updates a file called Cargo.lock with the exact versions of packages downloaded. The Cargo.lock file is a generated file and not meant for editing.
Each dependency in Cargo.toml is specified in a new line and takes the format <crate-name> = "<semantic-version-number>". Semantic versioning or Semver has the form X.Y.Z, where X is the major version number, Y is the minor version, and Z is the patch version.
There are many ways to specify the location and version of dependencies in Cargo.toml, some of which are summarized here:
crates.io is the default registry, Cargo provides the option to use an alternate registry. The registry name has to be configured in the .cargo/config file, and in Cargo.toml, an entry is to be made with the registry name, as shown in the example here:[dependencies]
cratename = { version = "2.1", registry = "alternate-
registry-name" }[dependencies]
chrono = { git = "https://github.com/chronotope/chrono" ,
branch = "master" }Cargo will get the repo at the branch and location specified, and look for its Cargo.toml file in order to fetch its dependencies.
Once the dependencies are specified in the Cargo.toml file in any of the preceding formats, we can use the external library in the package code as shown in the following example. Add the following code to src/main.rs:
use chrono::Utc;
fn main() {
println!("Hello, time now is {:?}", Utc::now());
}
The use statement tells the compiler to bring the chrono package Utc module into the scope of this program. We can then access the function now() from the Utc module to print out the current date and time. The use statement is not mandatory. An alternative way to print datetime would be as follows:
fn main() {
println!("Hello, time now is {:?}", chrono::Utc::now());
}
This would give the same result. But if you have to use functions from the chrono package multiple times in code, it is more convenient to bring chrono and required modules into scope once using the use statement, and it becomes easier to type.
It is also possible to rename the imported package with the as keyword:
use chrono as time;
fn main() {
println!("Hello, time now is {:?}", time::Utc::now());
}
For more details on managing dependencies, refer to the Cargo docs: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html.
In this section, we have seen how to add dependencies to a package. Any number of dependencies can be added to Cargo.toml and used within the program. Cargo makes the dependency management process quite a pleasant experience.
Let's now look at another useful feature of Cargo – running automated tests.