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!
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.