Rust development on nixos

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:

  • buildRustPackage is for expressions which have cargo drive the build.

    • a Rust binary package will build as one gigantic nix derivation which calls cargo on 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 because cargo update accesses the network and cannot be run from inside a nix derivation. So if you want to override some pervasive dependency (like the ring cryptography 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.
      • Once this PR merges it will be possible to do non-manual mass-overrides, but still awkward.
  • buildRustCrate is for expressions which have nix drive the build.

    • Each Rust library (.rlib) gets its own derivation, in which nix calls rustc directly.
    • Builds are incremental – only the libraries which change are rebuilt.
    • Overriding dependencies is relatively easy; it works just like we’re used to with .override since the whole build plan is tree of nix derivations.

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.

2 Likes