Cargo usage tips

3 minute read Published: 2022-07-26

Cargo is the package manager to install libraries in a Rust project, it's the equivalent of pip for Python, npm for NodeJS and so on. Using cargo is easy but its ergonomics can be improved a little bit.

This is a short note for the purpose of creating a reference for my future self.

One of the useful properties of library dependency management in Rust is that you can choose which optional features to use, among the set of optional features that the library developer has decided to expose. Optional features are implemented with feature flags that enable certain codepaths.

When adding a library to a project, now cargo shows the various features that can be activated for that library. Being aware of how a library has been thought out is interesting and also important:

The following is an opinionated way I'm testing to handle dependencies in a Rust project.

First step, check the library features invoking cargo with the --dry-run parameter. Example using the hyper crate (an http client/server library):

$ cargo add hyper --dry-run
    Updating crates.io index
      Adding hyper v0.14.20 to dependencies.
             Features:
             - __internal_happy_eyeballs_tests
             - client
             - ffi
             - full
             - h2
             - http1
             - http2
             - libc
             - nightly
             - runtime
             - server
             - socket2
             - stream
             - tcp
warning: aborting add due to dry run

This is the overview of features exposed to me.

Then install the library handpicking just the needed features:

$ cargo add hyper --no-default-features --features http1
    Updating crates.io index
      Adding hyper v0.14.20 to dependencies.
             Features:
             + http1
             - __internal_happy_eyeballs_tests
             - client
             ...

The result in the file Cargo.toml will be:

[dependencies]
hyper = { version = "0.14.20", default-features = false, features = ["http1"] }

§ Updating a library

Updating a library in a project bares a lot of responsibility. One thing that should easy are minor and patch upgrades (semantic versioning).

To check if semver-compatible upgrades are available, run:

cargo update -p <pkg-name>

This will update only the Cargo.lock file so we can inspect what is being changed. If we are happy with the changes, we can run:

cargo upgrade --to-lockfile

And also the Cargo.toml will be updated.

§ A Cargo.toml template

I often start from the same Cargo.toml template, so it was worth building a template. I did it With an Emacs snippet (documented here):