Adding breakpointHook
to nativeBuildInputs
of the failing derivation is also a powerful technique ― it allows you to connect with cntr
and explore the environment as it was at the point that the derivation's build failed.
Thanks to jamesbrock on the NixOS Discourse, the short of it is:
Add the breakpointHook
package to the nativeBuildInputs
of a mkDerivation
.
nativeBuildInputs = [ breakpointHook ];
Install cntr
nix-env -i cntr
Run your Nix build command, and when it fails, the breakpointHook will output a message like this:
build failed in installPhase with exit code 1
To attach install cntr and run the following command as root:
cntr attach -t command cntr-/nix/store/6vwxqrwq5h1fd3nw4mc61wgk7rppn2qw-jupyterlab-extended
So we run that command as root. The root user doesn’t have a PATH
to the cntr
command which we installed in our Nix profile, so give it the full path to our single-user-installed cntr.
sudo /home/$USER/.nix-profile/bin/cntr attach -t command cntr-/nix/store/6vwxqrwq5h1fd3nw4mc61wgk7rppn2qw-jupyterlab-extended
And now we’re in the sleeping Nix container.
Note that paths like $out
and $TMPDIR
are available at this stage along with your usual tools, however, they're under the current directory (/var/lib/cntr
), instead of /
.
(You can use them like cd $(echo $out | cut -c2-)
.)
From here, run cntr exec
to fully load the build environment.
/home/$USER/.nix-profile/bin/cntr exec
The $TMPDIR
directory is where Nix has created the temporary directory for the build 10.
cd $TMPDIR
Now we are fully inside the context of the build, and any commands which we enter in the shell will be as if we had entered that command on a line in the phase (for example, buildPhase
) of our derivation when the derivation failed.
Mentioned here in the NixOS Discourse:
I want to also add a few details regarding breakpointHook. It is a really powerful debug hook by @Mic92.
It is enough to put pkgs.breakpointHook into your buildInputs to get it working. In the case of a failure there is an exact “connection” command printed out to the console. You can use this command (cntr) to attach a shell into the build environment. To use it you have to be able to run sudo along with cntr (so you should install cntr package before ;-)).
You can find more interesting details in the @Mic92 NixCon presentation: Jörg 'Mic92' Thalheim - About Nix sandboxes and breakpoints (NixCon 2018)
Here's a link to the relevant section of the manual: https://nixos.org/manual/nixpkgs/stable/#breakpointhook
nix-build
and hence you get the full output with no truncation or aggregation. – Chris Stryczynski Jul 28 '23 at 11:15nix-build
can execute different build phases, for example inpython3.pkgs.buildPythonPackage
. the actual build phases are stored in the variable$phases
, so in the nix-shell, seeecho $phases
. docs: Building a stdenv package in nix-shell, issues: docs: fix nix-shell commands, docs: Building a stdenv package in nix-shell – milahu Jul 28 '23 at 11:54buildPhase
results in:no Makefile, doing nothing
. Other commands seem to fail withmkdir: cannot create directory ‘/nix/store/kk9irdv2ppca45fzwwz7422vsmbpgga1-HaskellNixCabalStarter-0.1.0.0’: Read-only file system
. – Chris Stryczynski Jan 14 '24 at 16:26cmakeConfigurePhase
. theRead-only file system
error is fixed by using different output paths. another problem is thatnix-build
runs the build script withset -e
to stop on the first error, but this would exit the interactive bash shell... see also nixos discourse – milahu Jan 15 '24 at 13:21chromium
packageeval "${unpackPhase:-unpackPhase}"
fails withvariable $src or $srcs should point to the source
butphases="unpackPhase" genericBuild
works... so probablygenericBuild
is better as a generic phase runner – milahu Feb 05 '24 at 12:26