C++ nix-build from local project

This has to be obvious/easy, buy I’ve spent hours try to figure it out … I’m not smrt.

What ridiculously simple thing am I missing here?

I have a local C++ sample project (reading Nix Pills) like:

hello-01-make
|-- Makefile
|-- builder.sh
|-- default.nix
`-- src
    `-- hello.cpp

default.nix:

with (import <nixpkgs> {});
derivation {
  name = "jra-hello";
  builder = "${bash}/bin/bash";
  args = [ ./builder.sh ];
  inherit gcc coreutils gnumake;
  src = /home/jra/prj/nix-hello/hello-01-make;
  system = builtins.currentSystem;
}

builder.sh

export PATH="$coreutils/bin:$gcc/bin:$gnumake/bin"
cp -r /home/jra/prj/nix-hello/hello-01-make .
cd hello-01-make
make
mkdir -p $out/bin
cp hello $out/bin/jra-hello

and this from nix-build:

$ nix-build
these derivations will be built:
  /nix/store/xmz2kv7ffy18bsvk1073cvb5jnwg2al1-jra-hello.drv
building '/nix/store/xmz2kv7ffy18bsvk1073cvb5jnwg2al1-jra-hello.drv'...
src is:  /nix/store/z81rfk37dgjqy5d7q69ml6xn9hhw5akc-hello-01-make
total 0
cp: cannot stat '/home/jra/prj/nix-hello/hello-01-make': No such file or directory
total 0
/nix/store/4dn3krg0xal04j2v0wxz8nz72ryc3a28-builder.sh: line 7: cd: hello-01-make: No such file or directory
total 0
make: *** No targets specified and no makefile found.  Stop.
make: *** No rule to make target 'install'.  Stop.
cp: cannot stat 'hello': No such file or directory
builder for '/nix/store/xmz2kv7ffy18bsvk1073cvb5jnwg2al1-jra-hello.drv' failed with exit code 1
error: build of '/nix/store/xmz2kv7ffy18bsvk1073cvb5jnwg2al1-jra-hello.drv' failed

With the caveat that I have neither tried to step through the pills nor used the derivation function directly, I think you may be getting turned around here:

The build process should already be copying your src = ...; into the nix store, and ~publishing it to your builder as $src. I think using something like cp -r $src/* . (which will copy the contents of this source into the build directory) might get you back on track.

2 Likes

YES!

I didn’t get this was happening. I had tried about one million variations thinking I was trying to copy from the original location. I’m sure Nix Pills explained this, repeatedly, but I’m pretty good at ignoring critical information.

What is the idiomatic way to work with local projects?

Should it be like:

src = .;  # I don't think this is permitted
src = ../hello-01-make  # this seems to work

Also, how do I “install” it so it is in my path? After building:

$ result/bin/jra-hello  # ok, this works, but ...
Hello World!
$ which jra-hello
/usr/bin/which: no jra-hello in ...
$ nix-env -iA jra-hello
error: attribute 'jra-hello' in selection path 'jra-hello' not found

Nix paths must contain a slash (/), so you need to do

  src = ./.;

But, any change in the current directory will trigger a rebuild. To prevent this, you may want to filter the source and include only the files necessary to build the derivation with nix-filter.

According to this stackoverflow answer, to imperatively install a derivation from a file you can do:

nix-env -i -f default.nix

You can also do something like this to declaratively install it:

let
  myDrv = import "<project-root>/default.nix";
in
{
  environment = {
    systemPackages = with pkgs; [
      myDrv
      ...
    ];
  };
}