Learning Nix - Nixpkgs standard environment
25/04/2023
Explaining the build process with
nixpkgs.stdenv
In the previous post, we saw the basic syntax of Nix and learned about derivations.
The built-in function derivation makes it possible to define a derivation, given at least a name, a system and an executable to build the package.
In practice however, you still need the builder logic, for instance: unpack the source, then ./configure; make; make install.
For a lot of packages, this builder logic will be similar, hence the stdenv package.
The setup.sh script
Most of the logic necessary to build and install autotools packages is inside this script.
First, it clears the PATH and fills it with a couple of useful tools 1, such as the GNU coreutils, tar, make, grep, etc.
Then, it defines the following bash functions:
unpackPhase: Unpack the source files (specified by thesrcorsrcsenvironment variables) into the current directory. Thesrcmay refer either to a directory (which will be copied) or a compressed file (e.g..tar.gz) which will be extracted.patchPhase: Apply patches (if any) using the unixpatchutility. Patches are provided by thepatcheslist.configurePhase: Prepare the sources tree or building. By default, this can call./configurewith a bunch of flags.buildPhase: Actually compile the package, if a Makefile can be found, otherwise does nothing.installPhase: Install the packages under$out(typically/nix/store/<package-hash>/out). By default, creates the$outdirectory and callmake install.fixupPhase: Perform Nix-specific post-processing actions on the files installed under$out. For instance, prevent unnecessary runtime dependencies with thepatchelfcommand, or patch shebangs in shell scripts to use Nix store packages. See the doc for more info.
Finally, it defines the genericBuild function which calls all these phases successively, plus any pre/post hooks defined for each phase 2.
This script is an output of the stdenv derivation, which means that you can use it to reproduce the build environment, and debug your package step-by-step manually.
- simply run
source $stdenv/setupin an env where stdenv is defined- this can be a derivation coming from mkDerivation (which seems to add it automatically)
- this can simply be a derivation where stdenv is defined as an attr
- this is what default-builder.sh, the builder defined by default by mkDerivation, does (in the nix-build command)
- this is also what is done (more or less?? depending on the –pure option?) by nix-shell
The stdenv.mkDerivation function
In practice, most packages do not directly use the derivation function but rather the mkDerivation function, defined in the stdenv package.
This wrapper around the builtin derivation conveniently sets some attributes of the output derivation:
- It sets
stdenvderivation to use the systemstdenvderivation - It sets
buildertostdenv.shell, which is set tobashby default - It sets
argsto["-e" ./default-builder.sh]by default, which basically doessource $stdenv/setup && genericBuild(see source code). Another build script can be configured by callingmkDerivationwithbuilder = ./my-builder.shfor instance. ⚠️ This is not thebuilderderivation attribute ! - It adds a
overrideAttrsattribute to the derivation produced (cf Overrides section below). - It makes it possible to call it with or without args?
Also, it sets the name and system attributes (using provided pname/version or name, and stdenv.buildPlatform.system).
-
At time of writing, this list of tools is more or less defined in
common-path.nix, and passed tosetup.shvia theinitialPathenv variable (see e.g.stdenv/nix/default.nix). ↩ -
A couple additional functions are defined, even though they are disabled by default:
checkPhaseto run tests (callsmake check),installCheckPhaseto run tests against the installed directories (callsmake installcheck), anddistPhaseto produce a source distribution of the package (callsmake dist). These phases can be activated by settingdoCheck,doInstallCheckordoDistto true, if the Makefile exists. ↩