Low-level derivations: Difference between revisions
Make the example technically correct |
Second example |
||
Line 26: | Line 26: | ||
# Write the string <code>echo "Hello, World!"</code> to the output file; | # Write the string <code>echo "Hello, World!"</code> to the output file; | ||
# Make the output file executable. | # Make the output file executable. | ||
However, if we try to build this example: | |||
{{code|lang=console|line=no|highlight=3,8| | |||
$ nix-build example.nix | |||
this derivation will be built: | |||
/nix/store/l6s955asmyc22nx7y5pg3ngnzg30r4vb-hello-world.drv | |||
building '/nix/store/l6s955asmyc22nx7y5pg3ngnzg30r4vb-hello-world.drv'... | |||
error: executing '/bin/bash': No such file or directory | |||
error: builder for '/nix/store/l6s955asmyc22nx7y5pg3ngnzg30r4vb-hello-world.drv' failed with exit code 1; | |||
last 1 log lines: | |||
> error: executing '/bin/bash': No such file or directory | |||
For full logs, run: | |||
nix log /nix/store/l6s955asmyc22nx7y5pg3ngnzg30r4vb-hello-world.drv | |||
}} | |||
This failure could potentially be surprising. We don't have any syntactic errors, and the logic of the script sure looks good. Let's dive in into what's happening. First, we can see that the derivation is being built under the <code>/nix/store/l6s955asmyc22nx7y5pg3ngnzg30r4vb-hello-world.drv</code> path in the [[Nix store]]. The hash for the derivation is how Nix is able to guarantee isolation between different invocations of a derivation with different ''inputs''. The hash is essentially generated as a function of the input attrset. | |||
However, the builder failed, because it couldn't find <code>/bin/bash</code>. This happens because the [[Nix ecosystem]] isolates our build environment from the system itself, we cannot use a binary that isn't defined in our derivation, in this case [[bash]] itself! In order to use it, we need to add it as an input to our derivation, by referencing the package directly: | |||
{{File|example.nix|nix|highlight=1-3,7,11|<nowiki> | |||
let | |||
pkgs = import '</nowiki><<nowiki>nixpkgs</nowiki>><nowiki>' | |||
in | |||
derivation { | |||
name = "hello-world"; | |||
system = builtins.currentSystem; | |||
builder = "${pkgs.bash}/bin/bash"; | |||
args = [ | |||
"-c" | |||
'' | |||
echo '#!${pkgs.bash}/bin/bash' </nowiki>><nowiki> $out | |||
echo 'echo "Hello, World!"' </nowiki>>><nowiki> $out | |||
chmod +x $out | |||
'' | |||
]; | |||
}</nowiki>}} | |||
Building the package again, we'll come across another surprising error: | |||
{{code|lines=no|lang=console|highlight=8| | |||
$ nix-build example.nix | |||
this derivation will be built: | |||
/nix/store/kbxagjwnr916bg4ajn5fz13bmc3lmr8v-hello-world.drv | |||
building '/nix/store/kbxagjwnr916bg4ajn5fz13bmc3lmr8v-hello-world.drv'... | |||
bash: line 3: chmod: command not found | |||
error: builder for '/nix/store/kbxagjwnr916bg4ajn5fz13bmc3lmr8v-hello-world.drv' failed with exit code 127; | |||
last 1 log lines: | |||
> bash: line 3: chmod: command not found | |||
For full logs, run: | |||
nix log /nix/store/kbxagjwnr916bg4ajn5fz13bmc3lmr8v-hello-world.drv | |||
}} | |||
Turns out <code>chmod</code> is not part of our build environment either; that's how minimal the low-level derivation environment is! However, before we fix the script in a similar manner, let's observe another important detail: the store path. Compare the build location of this example, and the previous one; the SHAs are different! That is because our derivation has different inputs to the one before, therefore it's built under a different location in the Nix store. And to highlight this, without fixing the script, let's build it again: | |||
{{code|lines=no|lang=console|highlight=3| | |||
$ nix-build example.nix | |||
this derivation will be built: | |||
/nix/store/kbxagjwnr916bg4ajn5fz13bmc3lmr8v-hello-world.drv | |||
building '/nix/store/kbxagjwnr916bg4ajn5fz13bmc3lmr8v-hello-world.drv'... | |||
bash: line 3: chmod: command not found | |||
error: builder for '/nix/store/kbxagjwnr916bg4ajn5fz13bmc3lmr8v-hello-world.drv' failed with exit code 127; | |||
last 1 log lines: | |||
> bash: line 3: chmod: command not found | |||
For full logs, run: | |||
nix log /nix/store/kbxagjwnr916bg4ajn5fz13bmc3lmr8v-hello-world.drv | |||
}} | |||
The SHA is the same, because our inputs haven't changed. This is the essence to why derivations are ''pure functions'' of their inputs. |