As you can see, there are many options here. It can be difficult to decide! The wiki has a nice comparison table.
Most of these tools end up calling one of two different low-level primitives inside nixpkgs, which have unfortunately-not-very-descriptive names:
-
buildRustPackageis for expressions which havecargodrive the build.- a Rust binary package will build as one gigantic nix derivation which calls
cargoon a tarball which vendors all the source code of all the crate’s dependencies. - There is no sharing of build effort between binary crates that share a common library dependency (i.e. the library is built two or more times).
- Builds are “monolithic” – if you change your source code or any of your crate’s dependencies (including adding a dependency), all of your crate’s dependencies are rebuilt.
- It is currently impossible to override a crate’s dependencies without running
cargo update. This is a problem becausecargo updateaccesses the network and cannot be run from inside a nix derivation. So if you want to override some pervasive dependency (like theringcryptography library) in every rust package on your system you’re looking at doing a whole lot of work by hand, and then redoing that work every every time you pull from nixpkgs.
- a Rust binary package will build as one gigantic nix derivation which calls
-
buildRustCrateis for expressions which havenixdrive the build.- Each Rust library (
.rlib) gets its own derivation, in whichnixcallsrustcdirectly. - Builds are incremental – only the libraries which change are rebuilt.
- Overriding dependencies is relatively easy; it works just like we’re used to with
.overridesince the whole build plan is tree of nix derivations.
- Each Rust library (
It looks like dream2nix uses buildRustPackage.
I looked briefly at naersk and crane; it looks like each of them rolls its own equivalent of buildRustPackage (i.e. they call cargo and let it drive the build). So if you plan on submitting to nixpkgs at some point you would need to change tooling…
It looks like in both cases they are a tiny bit smarter than buildRustPackage, creating two derivations instead of one: one monolithic derivation for all of your crate’s dependencies and a second one for your crate’s source code. So changing your crate’s source code will not trigger a world-rebuild. But changing or adding any of your dependencies will still rebuild all of your dependencies, and cargo is in still driving the build.