Rust projects are generally managed with Cargo, but it has the disadvantage of having to recompile all dependencies once per project, taking up a lot of hard disk space, and not being able to share the build cache across projects. After some research, there are several Nix-based Rust build tools:
- cargo2nix: https://github.com/cargo2nix/cargo2nix
- carnix: no longer updated
- crane: https://github.com/ipetkov/crane
- crate2nix: https://github.com/kolloch/crate2nix
- naersk: https://github.com/nix-community/naersk
- nocargo: https://github.com/oxalica/nocargo
I’ll try out each of these tools below.
Some of the commands that appear below are referenced in the documentation for the corresponding project.
cargo2nix
- Development Shell - knowing all the dependencies means easy creation of complete shells. Run nix develop or direnv allow in this repo and see!
- Caching - CI & CD pipelines move faster when purity guarantees allow skipping more work!
- Reproducibility - Pure builds. Access to all of nixpkgs for repeatable environment setup across multiple distributions and platforms
Installation
cargo2nix provides flakes support and does not need to be installed separately.
Usage
cargo2nix is relatively easy to run, just run nix run
directly using the flakes feature.
|
|
It generates a Cargo.nix file, and you need to write a flake.nix
to use with it, here is jiegec/webhookd
as an example.
|
|
Then compile.
Principle
cargo2nix parses Cargo.lock, generates Cargo.nix file, and finally wraps it into flake.nix.
crane
- Source fetching: automatically done using a Cargo.lock file
- Incremental: build your workspace dependencies just once, then quickly lint, build, and test changes to your project without slowing down
- Composable: split builds and tests into granular steps. Gate CI without burdening downstream consumers building from source.
Installation
crane does not need to be installed, just use flakes.
Usage
When using crane, write flake.nix
directly in the project.
|
|
This works without the need to use the tool to generate the corresponding Cargo.nix from Cargo.lock.
However, since webhookd relies on the native library, you will need to add the native dependencies manually.
|
|
Build.
Principle
crane does an incremental compilation by downloading all the dependencies and building them once with cargo, and then building the resulting target directory as target.tar.zst
, and then adding the project source code again. However, its purpose is not quite the same as other projects, and it does not take into account cross-project dependency caching.
crate2nix
- Same dependency tree as cargo: It uses cargo_metadata to obtain the dependency tree from cargo. Therefore, it will use the exact same library versions as cargo and respect any locked down version in Cargo.lock.
- Smart caching: It uses smart crate by crate caching so that nix rebuilds exactly the crates that need to be rebuilt. Compare that to docker layers…
- Nix ecosystem goodness: You can use all things that make the nix/NixOS ecosystem great, e.g. distributed/remote builds, build minimal docker images, deploy your binary as a service to the cloud with NixOps, …
- Out of the box support for libraries with non-rust dependencies: It builds on top of the buildRustCrate function from NixOS so that native dependencies of many rust libraries are already correctly fetched when needed. If your library with native dependencies is not yet supported, you can customize defaultCrateOverrides / crateOverrides, see below.
- Easy to understand nix template: The actual nix code is generated via templates/build.nix.tera so you can fix/improve the nix code without knowing rust if all the data is already there.
Installation
First install crate2nix, since its stable version 0.10.0 is already last year’s version, I directly used the master branch. If you are installing directly, you can use the following command.
|
|
But I am managing it with flakes + home-manager, so here is how I actually configured it.
- add crate2nix to flake.nix to inputs and set
crate2nix.flake = false
- pass crate2nix from inputs to the actual home manager configuration, then add
callPackage crate2nix {}
tohome.packages
Usage
Next, find a Rust project and run crate2nix generate
in it.
Build.
|
|
The result of the compilation can be seen under result/bin
.
I compiled jiegec/webhookd
and got an error during the compilation.
The previous cargo2nix did not have this problem, supposedly because cargo2nix introduced the Security dependency for us, see overrides.nix.
According to the crate2nix documentation, additional native dependencies need to be added.
|
|
Then build.
This will work fine.
Principle
The principle is to use the cargo_metadata
library to get the information of each crate from Cargo.lock and then translate it to Cargo.nix
, after which nix compiles the contents of each crate. So at first, you still need to create a project with Cargo, add dependencies, and generate Cargo.lock
; then you can use crate2nix generate
to synchronize the dependency information to the Cargo.nix
file, and build it without Cargo’s participation, directly rustc.
naersk
Installation
Requires installation of niv:
|
|
Usage
In the project directory, first import naersk with niv
.
Then write a default.nix
.
Build.
Principle
The principle of naersk is similar to crane: download all the dependencies, create a project with only dependencies, then precompile with cargo, compile the target directory into target.tar.zst
; then compile the whole project based on the precompiled results.
nocargo
- No IFDs (import-from-derivation). See meme.
- No cargo dependency during building. Only rustc.
- No need for hash prefetching or code generation1.
- Crate level caching, globally shared.
- nixpkgs integration for non-Rust dependencies.
The README also mentions a comparison of nocargo, cargo2nix, naersk and buildRustPackage.
Usage
nocargo is currently only supported on x86_64-linux platforms.
In a Cargo project, run the following command.
|
|
It generates the flake.nix
file as follows.
|
|
Build.
A compile error occurs, indicating that the crates.io index version is not up to date.
|
|
Follow the instructions in flake.nix
to use the latest crates.io index.
|
|
Continue building and you’re done.
|
|
Summary
As you can see, the different tools above use different approaches, if you want to compare.
- Nix drv granularity: per dependency (cargo2nix, crate2nix, nocargo), all dependencies (crane, naersk). The advantage of the former is that the dependencies will be shared across projects and further can be passed to the binary cache.
- Whether to generate nix files with full dependency information: yes (cargo2nix, crate2nix), no (crane, naersk, nocargo). If generated, the information in Cargo.lock and Cargo.nix in the repository is duplicated, so if Cargo.lock is modified, you need to resync Cargo.nix.