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 thesrc
orsrcs
environment variables) into the current directory. Thesrc
may 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 unixpatch
utility. Patches are provided by thepatches
list.configurePhase
: Prepare the sources tree or building. By default, this can call./configure
with 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$out
directory and callmake install
.fixupPhase
: Perform Nix-specific post-processing actions on the files installed under$out
. For instance, prevent unnecessary runtime dependencies with thepatchelf
command, 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/setup
in 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
stdenv
derivation to use the systemstdenv
derivation - It sets
builder
tostdenv.shell
, which is set tobash
by default - It sets
args
to["-e" ./default-builder.sh]
by default, which basically doessource $stdenv/setup && genericBuild
(see source code). Another build script can be configured by callingmkDerivation
withbuilder = ./my-builder.sh
for instance. ⚠️ This is not thebuilder
derivation attribute ! - It adds a
overrideAttrs
attribute 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.sh
via theinitialPath
env variable (see e.g.stdenv/nix/default.nix
). ↩ -
A couple additional functions are defined, even though they are disabled by default:
checkPhase
to run tests (callsmake check
),installCheckPhase
to run tests against the installed directories (callsmake installcheck
), anddistPhase
to produce a source distribution of the package (callsmake dist
). These phases can be activated by settingdoCheck
,doInstallCheck
ordoDist
to true, if the Makefile exists. ↩