Nix: Using rustPlatform.buildRustPackage with Git Dependencies (it's kind of a pain)

I’m not sure if something changed with the way Nix’s rust build system works in 23.05, but I’m pretty sure something did because this project didn’t suddenly switch to git dependencies since I last built it with git; it was already using them. Anyways whether it’s new or not, you need to specify a hash for each of the git dependencies which works but is annoying to actually do. Here’s how.

Alright so when you normally build a rust project using rustPlatform.buildRustPackage you specify a cargoSha256. This is the hash of a derivation containing the source code of all the dependencies of the project, separate from the project source itself. If all your dependencies are normal crates then you just set that to empty string, run a build, replace it with whatever the real hash is and you’re done.

When you have git dependencies you don’t use cargoSha256. Instead you need to define cargoLock, like this:

rustPlatform.buildRustPackage {
  # This isn't a complete package definition because I'm only including the
  # parts relevant to this post. See
  # https://github.com/NixOS/nixpkgs/blob/master/doc/languages-frameworks/rust.section.md

  # in this example you have the source locally, relative to the nix file.
  # for example, when writing a nix flake
  src = ./.;
  
  # again, you have the source locally, so you can refer to the Cargo.lock
  # directly. I'm not sure how you do this with builds that pull the source
  # down from a remote honestly, probably referencing the Cargo.lock from the
  # source somehow.
  cargoLock.lockFile = ./Cargo.lock;

  # Here's the annoying bit
  cargoLock.outputHashes = {
    "capstone-0.10.0" = "sha256-x0p005W6u3QsTKRupj9HEg+dZB3xCXlKb9VCKv+LJ0U=";
    "hidapi-1.4.1" = "sha256-2SBQu94ArGGwPU3wJYV0vwwVOXMCCq+jbeBHfKuE+pA=";
    "hif-0.3.1" = "sha256-o3r1akaSARfqIzuP86SJc6/s0b2PIkaZENjYO3DPAUo=";
    "humpty-0.1.3" = "sha256-efeb+RaAjQs9XU3KkfVo8mVK2dGyv+2xFKSVKS0vyTc=";
    "idol-0.3.0" = "sha256-s6ZM/EyBE1eOySPah5GtT0/l7RIQKkeUPybMmqUpmt8=";
    "idt8a3xxxx-0.1.0" = "sha256-S36fS9hYTIn57Tt9msRiM7OFfujJEf8ED+9R9p0zgK4=";
    "libusb1-sys-0.5.0" = "sha256-7Bb1lpZvCb+OrKGYiD6NV+lMJuxFbukkRXsufaro5OQ=";
    "pmbus-0.1.0" = "sha256-20peEHZl6aXcLhw/OWb4RHAXWRNqoMcDXXglwNP+Gpc=";
    "probe-rs-0.12.0" = "sha256-uS+Hh2dKUXDgwqS9MdV6CmONO8i2pOeR5LBenliiEe0=";
    "spd-0.1.0" = "sha256-X6XUx+huQp77XF5EZDYYqRqaHsdDSbDMK8qcuSGob3E=";
    "tlvc-0.2.0" = "sha256-HiqDRqmKOTxz6UQSXNMOZdWdc5W+cFGuKBkNrqFvIIE=";
    "vsc7448-info-0.1.0" = "sha256-otNLdfGIzuyu03wEb7tzhZVVMdS0of2sU/AKSNSsoho=";
  };
}

Ok so how do you figure out what to put in outputHashes? It’s simple, but tedious. At first, just set it to {}, containing nothing, and then run your nix build. The build will fail, and give you a <crate>-<version> pair:

error: No hash was found while vendoring the git dependency capstone-0.10.0.
You can add a hash through the `outputHashes` argument of `importCargoLock`:

outputHashes = {
  "capstone-0.10.0" = "<hash>";
};

If you use `buildRustPackage`, you can add this attribute to the `cargoLock`
attribute set.

Ok, so whatever pair it gave you, put it in with an empty string or lib.fakeSha256 as the hash.

  cargoLock.outputHashes = {
    "capstone-0.10.0" = lib.fakeSha256;
    # or if you want less typing, "capstone-0.10.0" = "";
  };

Now repeat the process. Each time you re-run your nix build it will give you a new error with a new package. Eventually, you will have all the git dependencies:

  cargoLock.outputHashes = {
    "capstone-0.10.0" = lib.fakeSha256;
    "hidapi-1.4.1" = lib.fakeSha256;
    "hif-0.3.1" = lib.fakeSha256;
    "humpty-0.1.3" = lib.fakeSha256;
    "idol-0.3.0" = lib.fakeSha256;
    "idt8a3xxxx-0.1.0" = lib.fakeSha256;
    "libusb1-sys-0.5.0" = lib.fakeSha256;
    "pmbus-0.1.0" = lib.fakeSha256;
    "probe-rs-0.12.0" = lib.fakeSha256;
    "spd-0.1.0" = lib.fakeSha256;
    "tlvc-0.2.0" = lib.fakeSha256;
    "vsc7448-info-0.1.0" = lib.fakeSha256;
  };

At this point, you will start getting new error messages for incorrect hashes:

error: hash mismatch in fixed-output derivation '/nix/store/vp1w3i1xpsji7lvd2ij49myjbibmddqb-capstone-rs-77296e0.drv':
         specified: sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
            got:    sha256-x0p005W6u3QsTKRupj9HEg+dZB3xCXlKb9VCKv+LJ0U=
error: 1 dependencies of derivation '/nix/store/bvb8wznxhpja68kak39s4a7c8n2q77fk-capstone-0.10.0.drv' failed to build
error: 1 dependencies of derivation '/nix/store/2gmfryjwzcplz3aysxc2nqwypq6839kb-cargo-vendor-dir.drv' failed to build
error: 1 dependencies of derivation '/nix/store/rig877k0ab9xiwfs73caqas2jb52ckv6-humility-20230708.drv' failed to build

Insert the correct hash:

  cargoLock.outputHashes = {
    "capstone-0.10.0" = "sha256-x0p005W6u3QsTKRupj9HEg+dZB3xCXlKb9VCKv+LJ0U=";
    "hidapi-1.4.1" = lib.fakeSha256;
    "hif-0.3.1" = lib.fakeSha256;
    "humpty-0.1.3" = lib.fakeSha256;
    "idol-0.3.0" = lib.fakeSha256;
    "idt8a3xxxx-0.1.0" = lib.fakeSha256;
    "libusb1-sys-0.5.0" = lib.fakeSha256;
    "pmbus-0.1.0" = lib.fakeSha256;
    "probe-rs-0.12.0" = lib.fakeSha256;
    "spd-0.1.0" = lib.fakeSha256;
    "tlvc-0.2.0" = lib.fakeSha256;
    "vsc7448-info-0.1.0" = lib.fakeSha256;
  };

Now repeat the process. Once again, you need to re-run the build one by one until you have the hashes for all of the packages. BE CAREFUL You might not get the hash errors in the same order you got the <crate>-<version> pairs. Pay close attention to the error message to make sure you’re adding the right has to the right crate. I accidentally ended up mismatching some of the hashes because I figured I’d get the errors in the same order.

Anyways, after all that is done you’ll have an outputHashes like I showed in the example.

  cargoLock.outputHashes = {
    "capstone-0.10.0" = "sha256-x0p005W6u3QsTKRupj9HEg+dZB3xCXlKb9VCKv+LJ0U=";
    "hidapi-1.4.1" = "sha256-2SBQu94ArGGwPU3wJYV0vwwVOXMCCq+jbeBHfKuE+pA=";
    "hif-0.3.1" = "sha256-o3r1akaSARfqIzuP86SJc6/s0b2PIkaZENjYO3DPAUo=";
    "humpty-0.1.3" = "sha256-efeb+RaAjQs9XU3KkfVo8mVK2dGyv+2xFKSVKS0vyTc=";
    "idol-0.3.0" = "sha256-s6ZM/EyBE1eOySPah5GtT0/l7RIQKkeUPybMmqUpmt8=";
    "idt8a3xxxx-0.1.0" = "sha256-S36fS9hYTIn57Tt9msRiM7OFfujJEf8ED+9R9p0zgK4=";
    "libusb1-sys-0.5.0" = "sha256-7Bb1lpZvCb+OrKGYiD6NV+lMJuxFbukkRXsufaro5OQ=";
    "pmbus-0.1.0" = "sha256-20peEHZl6aXcLhw/OWb4RHAXWRNqoMcDXXglwNP+Gpc=";
    "probe-rs-0.12.0" = "sha256-uS+Hh2dKUXDgwqS9MdV6CmONO8i2pOeR5LBenliiEe0=";
    "spd-0.1.0" = "sha256-X6XUx+huQp77XF5EZDYYqRqaHsdDSbDMK8qcuSGob3E=";
    "tlvc-0.2.0" = "sha256-HiqDRqmKOTxz6UQSXNMOZdWdc5W+cFGuKBkNrqFvIIE=";
    "vsc7448-info-0.1.0" = "sha256-otNLdfGIzuyu03wEb7tzhZVVMdS0of2sU/AKSNSsoho=";
  };

And now you’re done wrangling dependencies. The Cargo.lock file you gave to cargoLock.lockFile specifies the hashes of all the normal crates, and you’ve manually specified the hashes of all your git dependencies.