Difficulty using `buildRustPackage` with a `src` containing multiple cargo workspaces

Context

I have a repository structured like the following:

repo
├── workspace-a
├── workspace-b
└── workspace-c

Where each workspace has its own Cargo.lock and multiple crates.

The crate I would like to build a package for is repo/workspace-a/foo. The foo crate depends on multiple crates from all three workspaces using the [path] attribute to refer to them.

The Error

I’m running into some odd errors when attempting to use the rustPlatform.buildRustPackage function to build a nix package for my foo crate.

My nix expr looks something like this:

{ stdenv, rustPlatform, ... }:
rustPlatform.buildRustPackage rec {
  pname = "foo";
  version = "0.1.0";
  src = fetchGit {
    url = "ssh://git@github.com/owner/repo.git";
    rev = "8b1128c4d827e17f6d794f9f8a885240ce83630b";
  };
  cargoSha256 = "17ldqr5asrdcsh4l29m3b5r37r5d0b3npq1lrgjmxb6vlx6a36qh";
}

Where the cargoSha256 is currently made up. I’m expecting to get an error where nix tells me that it found a different hash from the one provided at which point I’ll add the proper hash, but I haven’t managed to get this far yet.

After building with:

nix-build -E '(import <nixpkgs> {}).callPackage ./foo.nix {}'

And the output I get is along these lines:

these derivations will be built:
  /nix/store/iqms4hbij486rjccrq7dwjr5s18q6978-foo-0.1.0-vendor.tar.gz.drv
  /nix/store/h1xp9mwcgbf6l2fjwrkrkzh6nd4sp124-foo-0.1.0.drv
building '/nix/store/iqms4hbij486rjccrq7dwjr5s18q6978-foo-0.1.0-vendor.tar.gz.drv'...
unpacking sources
unpacking source archive /nix/store/2hpv2w99kpqja78wwi6k0ja9fh2nkw5d-source
source root is source
patching sources
building

ERROR: The Cargo.lock file doesn't exist

Cargo.lock is needed to make sure that cargoSha256 doesn't change
when the registry is updated.

builder for '/nix/store/iqms4hbij486rjccrq7dwjr5s18q6978-foo-0.1.0-vendor.tar.gz.drv' failed with exit code 1
cannot build derivation '/nix/store/h1xp9mwcgbf6l2fjwrkrkzh6nd4sp124-foo-0.1.0.drv': 1 dependencies couldn't be built
error: build of '/nix/store/h1xp9mwcgbf6l2fjwrkrkzh6nd4sp124-foo-0.1.0.drv' failed

I have ensured that each of the workspaces has their respective Cargo.lock file in the repository at the specified commit, so I don’t believe this to be the problem.

Solution Attempt

My first suspicion was that the builder possibly could not find the necessary package within the repository, so I tried changing the sourceRoot directory to the workspace containing foo. Despite knowing that this would omit some of the other crate dependencies I needed within the repo, I thought the nix builder might at least find the Cargo.lock in the workspace this time, however I got an earlier error this time:

these derivations will be built:                                                                                                                                                                                                               
  /nix/store/3aw08jgr6g82l626ilvzmjfkwldh7yz9-foo-0.1.0-vendor.tar.gz.drv                                                                                                                                                                 
  /nix/store/2pb3hgil3lq23hjhfgzyivnck8jddcja-foo-0.1.0.drv                                                                                                                                                                               
building '/nix/store/3aw08jgr6g82l626ilvzmjfkwldh7yz9-foo-0.1.0-vendor.tar.gz.drv'...                                                                                                                                                    
unpacking sources                                                                                                                                                                                                                              
unpacking source archive /nix/store/2hpv2w99kpqja78wwi6k0ja9fh2nkw5d-source                                                                                                                                                                    
source root is /nix/store/2hpv2w99kpqja78wwi6k0ja9fh2nkw5d-source                                                                                                                                                                              
chmod: changing permissions of '/nix/store/2hpv2w99kpqja78wwi6k0ja9fh2nkw5d-source': Operation not permitted                                                                                                                                   
chmod: changing permissions of '/nix/store/2hpv2w99kpqja78wwi6k0ja9fh2nkw5d-source/.github': Operation not permitted                                                                                                                           
chmod: changing permissions of '/nix/store/2hpv2w99kpqja78wwi6k0ja9fh2nkw5d-source/.github/workflows': Operation not permitted                               
# lots more errors like this for every file in the repo, then
builder for '/nix/store/snld264c3lgp4w456al9kfswg54pknbv-foo-0.1.0-vendor.tar.gz.drv' failed with exit code 1
cannot build derivation '/nix/store/w7bs9ssjyz7lx4s863rdjqqzb66ag4km-foo-0.1.0.drv': 1 dependencies couldn't be built
error: build of '/nix/store/w7bs9ssjyz7lx4s863rdjqqzb66ag4km-foo-0.1.0.drv' failed

I’m unsure what to make of all the chmod attempts, but it seems like this is also the wrong approach.

Questions

Is there some way that I can specify the location of the crate foo and/or its Cargo.lock file within the $src repo that will still allow the crate to refer to its dependencies from the other two workspaces? I noticed that there is a cargoBuildFlags attribute and thought that perhaps I could use it to specify the --manifest-path ${src}/workspace-a/foo/Cargo.toml, however the error above appears to occur before the cargo build even begins.

Or perhaps it is possible that the ERROR: The Cargo.lock file doesn't exist could have a different cause altogether?

Any advice appreciated!

PS

Apologies for the placeholder names! The actual repo I’m building is a private Rust project, otherwise I’d link directly to it.

sourceRoot should work, looks like your issue is that it’s trying to write to the src derivation

chmod: changing permissions of '/nix/store/2hpv2w99kpqja78wwi6k0ja9fh2nkw5d-source': Operation not permitted

which isn’t allowed (it’s read only). Normally, this isn’t an issue as the workflow is usually:

unpackPhase # dumps src into /build, which is writable
cd $sourceRoot # sourceRoot is inherited from unpackPhase, which gets it from src

Thanks for the response!

Ahhh interesting, do you have any intuition on why it might be trying to write to the src derivation? For reference, this is exactly how I was pointing it to the subdir:

sourceRoot = "${src}/workspace-a/foo";

Perhaps I should be using some /build output related path instead?

when doing interpolation with a derivation, you will get the store path, so your sourceRoot expands to:

sourceRoot = "/nix/store/<hash>-source/workspace-a/foo";

which will be read only. you want something like:

  src = fetchGit {
    name = "foo";
    ...
  };

  sourceRoot = "foo/workspace-a/bar";
2 Likes

Thanks @jonringer, this was the hint I needed!

Starting the string with source appears to start from the default source location. So, the following appears to be working in my case (at least so far - I have a new round of errors):

sourceRoot = "source/workspace-a";
2 Likes

for fetchFromGitHub (and probably others) that is the case, it has the default name = "source", so your sourceRoot by default will point to source.

other fetchers such as fetchurl will take the base name. E.g. my-package-3.0.4.tar.gzsourceRoot=mypackage-3.0.4

2 Likes