Can't get `rustPlatform` to work with `src = "."`

I’m trying to package a little utility that I use for personal use (GitHub - samuela/jj). I have the following default.nix:

{ lib, rustPlatform, ... }:

{
  jj = rustPlatform.buildRustPackage rec {
    pname = "jj";
    version = "0.0.0";
    src = ".";
    unpackPhase = "ls -al";
    cargoSha256 = lib.fakeSha256;
  };
}

but then I get an error:

> nix-build -E "with import <nixpkgs> {}; callPackage ./default.nix {}"
warning: unknown setting 'experimental-features'
these derivations will be built:
  /nix/store/y8qqc5k3ygf4j71iwgm7g0xh942vnm8f-jj-0.0.0-vendor.tar.gz.drv
  /nix/store/vp4fbhlvs8shnib1dbps6srvbn5x64kz-jj-0.0.0.drv
warning: unknown setting 'experimental-features'
building '/nix/store/y8qqc5k3ygf4j71iwgm7g0xh942vnm8f-jj-0.0.0-vendor.tar.gz.drv'...
unpacking sources
total 16
drwx------ 2 nixbld nixbld 4096 May 21 23:38 .
drwxr-x--- 9 nixbld nixbld 4096 May 21 23:38 ..
-rw-r--r-- 1 nixbld nixbld 7118 May 21 23:38 env-vars
patching sources
building

ERROR: The Cargo.lock file doesn't exist

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

builder for '/nix/store/y8qqc5k3ygf4j71iwgm7g0xh942vnm8f-jj-0.0.0-vendor.tar.gz.drv' failed with exit code 1
cannot build derivation '/nix/store/vp4fbhlvs8shnib1dbps6srvbn5x64kz-jj-0.0.0.drv': 1 dependencies couldn't be built
error: build of '/nix/store/vp4fbhlvs8shnib1dbps6srvbn5x64kz-jj-0.0.0.drv' failed

It seems like the derivation isn’t correctly copying src into the build environment. It just has the env-vars file… no idea what that is. Does anyone know what’s going on here? Shouldn’t this just work?

Thanks in advance!

you will probably want src = lib.cleanSource ./.; or builtins.path when building locally. example: nix-template/default.nix at 4e147106bfae2364e274da491ae51cc67b7d2d05 · jonringer/nix-template · GitHub

Bonus: when the following PR is merged, you also don’t need cargoSha256 anymore:

https://github.com/NixOS/nixpkgs/pull/122158

4 Likes

To supplement the other answers, I think the problem is src = "." it should be src = ./. (minimal fix).

The first variant is just a string with a single dot, whereas the latter variant makes Nix copy the current directory to the nix store and make src point to that. src will then have the value /nix/store/.... in the builder. What happens with the src = "." variant is that Nix doesn’t copy anything and when the (shell) builder starts src will just refer to the current working directory that happens to be a temporary build tree.

I’ve tried all possible combinations of suggested that I could think of without success:

{ lib, rustPlatform, ... }:

{
  jj = rustPlatform.buildRustPackage rec {
    pname = "jj";
    version = "0.0.0";
    # src = .;                                # error: syntax error, unexpected '.'
    # src = ./.;                              # no source directory in build env
    # src = ".";                              # no source directory in build env
    # src = "./.";                            # no source directory in build env
    # src = lib.cleanSource .;                # error: syntax error, unexpected ';', expecting ID or OR_KW or DOLLAR_CURLY or '"'
    # src = lib.cleanSource ./.;              # no source directory in build env
    # src = lib.cleanSource ".";              # error: string '.' doesn't represent an absolute path
    # src = lib.cleanSource "./.";            # error: string './.' doesn't represent an absolute path
    # src = builtins.path { path = .; };      # error: syntax error, unexpected '.'
    # src = builtins.path { path = ./.; };    # no source directory in build env
    unpackPhase = "ls -al";
    cargoSha256 = lib.fakeSha256;
  };
}

Am I missing something?

Also why the difference between "./path/to/place" and ./path/to/place in nix semantics? That’s pretty confusing to me.

If you use src = ./. and remove your unpackPhase it works fine. unpackPhase is needed to copy the source from the Nix store to the build sandbox.

The first is just a string and doesn’t perform any magic. The second has the following semantics:

  • When used in a regular Nix expression, it evaluates to the full path. This allows you to use it with e.g. import or builtins.readFile to evaluate or read the file, so that a path can be used during evaluation.

  • When used in a string context (using antiquotation), the path is copied to the store and the store path is used in the string. This is useful when you want to use a path during a build. Since Nix builds are sandboxed, the original path cannot be accessed anymore, thus store paths are used.

    Relevant to your question: stdenv.mkDerivation (and buildRustPackage, which is based on stdenv.mkDerivation) serializes (most) top-level attributes to strings. This results in src containing the full store path after evaluation. This is then used by unpackPhase to unpack or copy the sources from the Nix store to the build environment.

Nix repl session which shows how paths function:

$ nix repl
nix-repl> ./Cargo.toml
/home/daniel/git/jj/Cargo.toml

nix-repl> :p builtins.fromTOML (builtins.readFile ./Cargo.toml)
{ dependencies = { rusoto_ec2 = "*"; rusoto_signature = "*"; skim = "*"; tokio = "*"; }; package = { edition = "2018"; name = "jj"; version = "0.0.0"; }; }

nix-repl> "Using antiquotation: ${./Cargo.toml}"
"Using antiquotation: /nix/store/713434097iw776pxp1d98v70j9mb7lbl-Cargo.toml"

nix-repl> "Using antiquotation: ${./.}"          
"Using antiquotation: /nix/store/gsz7h32c8afymvrrk4v3x0njvahwng89-jj"
3 Likes

Thanks! This moves the build further for me. It’s a bit odd to me that specifying unpackPhase breaks it, but I guess that’s part of the weirdness of hooks. Now I just need to figure out how to get this stuff to build with network access…

For preciseness: it’s not a hook. You were overriding the baked-in unpackPhase of stdenv.