Nix-build does not build anything (lazy evaluation in the way?). Recommendations?

I have three simple files in a folder:

./default.nix

{pkgs ? import <nixpkgs> {}}: {
  nodejs = import ./nodejs { inherit pkgs; };
}

./nodejs/default.nix

{pkgs ? import <nixpkgs> {}}: {
  "13.6.0" = pkgs.callPackage ./nodejs.nix {
    inherit pkgs;
    version = "13.6.0";
    sha256 = "00f01315a867da16d1638f7a02966c608e344ac6c5b7d04d1fdae3138fa9d798";
  };
}

./nodejs/nodejs.nix

{ pkgs ? import <nixpkgs> {}, version, sha256 }:
  let
    inherit (pkgs) stdenv autoPatchelfHook platforms fetchurl;
    inherit (stdenv) mkDerivation lib;
  in mkDerivation {
    inherit version;
    name = "nodejs-${version}";
    src = fetchurl {
      url = "https://nodejs.org/dist/v${version}/node-v${version}-linux-x64.tar.xz";
      inherit sha256;
    };
    nativeBuildInputs = with pkgs; [autoPatchelfHook];
    buildInputs = with pkgs; [glib];
    installPhase = ''
      mkdir -p $out
      cp -R ./ $out/
    '';
    meta = {
      description = "Event-driven I/O framework for the V8 JavaScript engine";
      homepage = https://nodejs.org;
      license = lib.licenses.mit;
      platforms = lib.platforms.linux;
    };
  }

Now when I run nix-build in this folder, nothing happens. I am guessing this is because of the lazy nature of the nix language, and the fact that I’m not accessing the "13.6.0" key anywhere in order to evaluate that callPackage expression.

However, if I modify the code so that ./nodejs/default.nix looks like the following, then it does build a result link after a bunch of output:

{pkgs ? import <nixpkgs> {}}:
  pkgs.callPackage ./nodejs.nix {
    inherit pkgs;
    version = "13.6.0";
    sha256 = "00f01315a867da16d1638f7a02966c608e344ac6c5b7d04d1fdae3138fa9d798";
  }

So, it seems that the lazy feature is getting in the way of how I was imagining to organize my local packages.

What do you recommend? How would you organize this so laziness doesn’t get in the way? Suppose you want to run a shell with Node 13.6.0 available, how would you do it? Imagine that there are multiple keys like "12.3.0", '“13.4.0”`, etc.

nix-build will build either a top-level derivation, a list of derivations or an attribute set of derivations. However, it will not traverse the attrset recursively. Here you have something like this:

{
  nodejs = {
    "13.6.0" = <derivation>;
  };
}

Knowing that, either run nix-build -A nodejs, or make the attrset a bit more shallow.

1 Like

To add to this, it is also possible to make Nix descend into the attribute set using pkgs.recurseIntoAttrs function:

https://github.com/NixOS/nixpkgs/blob/201d9b8916dd04d1c2eaa6c306a7a603d4859ae3/pkgs/top-level/all-packages.nix#L67

That is you would do the following in default.nix:

{pkgs ? import <nixpkgs> {}}: {
  nodejs = pkgs.recurseIntoAttrs (import ./nodejs { inherit pkgs; });
}
1 Like

Does recurseIntoAttrs affect nix-build? I thought it only affected nix-env package lookup by name, and nix search.

And I thought it as only working with Hydra. But apparently it does work for a regular nix-build, I tried it out yesterday with:

let
  pkgs = import <nixpkgs> {};
in
  {
    test = pkgs.recurseIntoAttrs {
      inherit (pkgs) hello;
    };
  }
1 Like

@jtojnar I can’t seem to get it to work, no build. This is what I have:

./default.nix

{pkgs ? import <nixpkgs> {}}: {
  nodejs = pkgs.recurseIntoAttrs (import ./nodejs { inherit pkgs; });
}

./nodejs/default.nix

{pkgs ? import <nixpkgs> {}}: {
  "13.6.0" = pkgs.callPackage ./nodejs.nix {
    inherit pkgs;
    version = "13.6.0";
    sha256 = "00f01315a867da16d1638f7a02966c608e344ac6c5b7d04d1fdae3138fa9d798";
  };
}

And the same ./nodejs/nodejs.nix file as above. I also tried

{pkgs ? import <nixpkgs> {}}: pkgs.recurseIntoAttrs {
  nodejs = (import ./nodejs { inherit pkgs; });
}

but still the same. What’d I miss?

I also tried that but still no build. Hmmm :thinking:

EDIT, this works: nix-build -A nodejs.'"13.6.0"'

I think the issue is that there is one more level of attrset returned by the “13.6.0” level.

How do I make this work in a shell.nix? For example, I have this (based on the above files):

let
  pkgs = import <nixpkgs> {};
in
  pkgs.mkShell {
    buildInputs = with pkgs; [
        hello
        (import ~/src/trusktr+nixpkgs/nodejs/default.nix {pkgs})."13.6.0"
    ];
  }

but when I run nix-shell, I have hello but not the expected node command.