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:
- By seeing the feature set you may become aware of additional dependencies
- Some libraries have some defaults enabled that in a context may not be needed. You may want to turn some switches off as a general rule of hygiene.
- By starting with a bare library installation and then adding the features you need, is a good exercise to be aware of how the library works.
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):
- Create a new file
Cargo.org
(-> will be generated from template) - Run
C-c C-v t
(org-babel-tangle
) and aCargo.toml
is generated from theCargo.org