Photo by Brunno Tozzo on Unsplash

Rust — Package Management

Gian Lorenzetto, PhD
CodeX
Published in
4 min readSep 9, 2021

--

This is the second part in my Getting Started with Rust series. This post will focus on the cargo cli tool and Rust’s package management system, including:

  • Searching for crates
  • Using crates in your own project
  • Configuring crate feature toggles
  • Installing (and using) a binary crate called cargo-watch.

For the basics of cargo and getting started with Rust, check out my first article Rust — A Beginner Cheat Sheet

Crates

Rust packages are called crates. You can find the full registry of crates at crates.io.

You can search for crates using the cargo cli tool. For example, to search for crates related to sql —

$ cargo search sql

The result of running the search command is a list of crate names and versions realted to your seach term —

Using Crates

In order to use crates you add them to your Cargo.toml file. Let’s take a look at the default Cargo.toml that is created with $ cargo new {project_name}

[package]
name = "hello_world"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html[dependencies]

In order to use the sql crate from our search above, edit yout Cargo.toml to look like the following —

[package]
name = "hello_world"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html[dependencies]
sql = "0.4.3" <-- Add dependency here

Note that Cargo dependencies are fully compatible with SemVer syntax, allowing for selective updating, as required.

Crates, Git and Feature Toggles

Cargo is pretty powerful when it comes to fetching crates for you. You can specify the location of a crate in several different ways.

The standard way (as above, but note the SemVer syntax) —

[dependencies]
bracket-lib = “~0.8.1”

You can specify a Git repo —

[dependencies]
bracket-lib = { git = "https://github.com/thebracket/bracket-lib" }

You can even specify feature toggles! In the below example, the bracket-lib crate will be used, but with the default rendering engine disabled and the vulkan engine used instead —

[dependencies]
bracket-lib = {
git = "https://github.com/thebracket/bracket-lib",
default-features = false,
features = [ "amethyst_engine_vulkan" ]

}

Source and Binary Crates

If you’re coming from a C# or NPM background, you might be interested to note the console output the next time you run $ cargo build after adding a crate—

Compiling sql v0.4.3
Compiling hello_world v0.1.0 (/Users/gian/hello_world)
Finished dev [unoptimized + debuginfo] target(s) in 0.99s

Most Rust crates are source code based and when you add them to your local project, cargo helpfully goes off and fetches the source for you and then will compile the crate for your local platform.

You’ll see cargo recompile ALL your crates if you specifiy a different target platform. See the previous article for an example targeting WebAssembly.

Cargo does support installing binary crates. These are crates that specifcy an executable. So cargo fetches, compiles and then installs the resulting executable.

To install a binary crate you use cargo directly —

$ cargo install {crate_name}

Notethis was a little confusing to me to begin with. Installing crates with cargo install is only supported for binary crates. You don’t use this command to install / add regular crates (as you would with say dotnet add).

Let’s look at an example called cargo-watch.

Cargo-watch

For most crates, you will add them by hand to the Cargo.toml directly. You may want to use the cargo search command to find the latest version, or go straight to crates.io, but you won’t use cargo install.

However, if the crate you want to install is a binary crate, then you can simply use cargo install directly and the crate will be fetched, compiled and installed ready for you to use.

Note — unlike other crates, installing a binary crate only needs to happen once (unless you’re updating the version of the binary crate itself). There’s no harm in trying, but you’ll get something like —

Updating crates.io index
Ignored package `cargo-watch v7.8.1` is already installed, use --force to override

Let’s try it out with cargo-watch, a nifty binary crate that installs an executable utility that watches for file changes in your project and lets you specify a command to run.

Install cargo-watch with —

$ cargo install cargo-watch

Once the command completes (successfully) you will immediately be able to access the cargo-watch cli tool —

$ cargo-watch -x build

This command will start a process to watch for changes to files in your project and in this case automatically run cargo build when a change is detected.

You can chain multiple commands together like so —

$ cargo-watch -x fmt -x test

This command assumes you have the Rust linter installed from the previous article but it will trigger the linter and then run any tests every time a file changes!

There’s plenty more you can do with cargo-watch, so go check out the cargo-watch crate documention.

Summary

Rust crates aren’t particular different from most other packaging systems, but there are few things to be aware of as noted above.

The cargo-watch crate is a good example of a binary crate, and also a really handy utility for when you’re developing in something like VSCode and want immediate feedback on code changes etc.

There are A LOT of crates available and more coming all the time, so go check out crates.io and stay rusty :)

Next up I’m going to tackle Rust modules — this is possibly the aspect of Rust I’ve found the most confusing (outside the borrow checker, but that’s for a future article ;)

--

--