The standard build environment in the Nix Packages collection provides an environment for building Unix packages that does a lot of common build tasks automatically. In fact, for Unix packages that use the standard ./configure; make; make install build interface, you don’t need to write a build script at all; the standard environment does everything automatically. If stdenv doesn’t do what you need automatically, you can easily customise or override the various build phases.
To build a package with the standard environment, you use the function stdenv.mkDerivation, instead of the primitive built-in function derivation, e.g.
stdenv.mkDerivation {
name = "libfoo-1.2.3";
src = fetchurl {
url = http://example.org/libfoo-1.2.3.tar.bz2;
md5 = "e1ec107956b6ddcb0b8b0679367e9ac9";
};
}
(stdenv needs to be in scope, so if you write this in a separate Nix expression from pkgs/all-packages.nix, you need to pass it as a function argument.) Specifying a name and a src is the absolute minimum you need to do. Many packages have dependencies that are not provided in the standard environment. It’s usually sufficient to specify those dependencies in the buildInputs attribute:
stdenv.mkDerivation {
name = "libfoo-1.2.3";
...
buildInputs = [libbar perl ncurses];
}
This attribute ensures that the bin subdirectories of these packages appear in the PATH environment variable during the build, that their include subdirectories are searched by the C compiler, and so on. (See ? for details.)
Often it is necessary to override or modify some aspect of the build. To make this easier, the standard environment breaks the package build into a number of phases, all of which can be overriden or modified individually: unpacking the sources, applying patches, configuring, building, and installing. (There are some others; see ?.) For instance, a package that doesn’t supply a makefile but instead has to be compiled “manually” could be handled like this:
stdenv.mkDerivation {
name = "fnord-4.5";
...
buildPhase = ''
gcc foo.c -o foo
'';
installPhase = ''
mkdir -p $out/bin
cp foo $out/bin
'';
}
(Note the use of ''-style string literals, which are very convenient for large multi-line script fragments because they don’t need escaping of " and \, and because indentation is intelligently removed.)
There are many other attributes to customise the build. These are listed in ?.
While the standard environment provides a generic builder, you can still supply your own build script:
stdenv.mkDerivation {
name = "libfoo-1.2.3";
...
builder = ./builder.sh;
}
where the builder can do anything it wants, but typically starts with
source $stdenv/setup
to let stdenv set up the environment (e.g., process the buildInputs). If you want, you can still use stdenv’s generic builder:
source $stdenv/setup
buildPhase() {
echo "... this is my custom build phase ..."
gcc foo.c -o foo
}
installPhase() {
mkdir -p $out/bin
cp foo $out/bin
}
genericBuild
The standard environment provides the following packages:
On Linux, stdenv also includes the patchelf utility.
The generic builder has a number of phases. Package builds are split into phases to make it easier to override specific parts of the build (e.g., unpacking the sources or installing the binaries). Furthermore, it allows a nicer presentation of build logs in the Nix build farm.
Each phase can be overriden in its entirety either by setting the environment variable Phase to a string containing some shell commands to be executed, or by redefining the shell function Phase. The former is convenient to override a phase from the derivation, while the latter is convenient from a build script.
There are a number of variables that control what phases are executed and in what order:
Specifies the phases. You can change the order in which phases are executed, or add new phases, by setting this variable. If it’s not set, the default value is used, which is ``$prePhases unpackPhase patchPhase $preConfigurePhases
configurePhase $preBuildPhases buildPhase checkPhase $preInstallPhases installPhase fixupPhase $preDistPhases distPhase $postPhases``.
Usually, if you just want to add a few phases, it’s more convenient to set one of the variables below (such as preInstallPhases), as you then don’t specify all the normal phases.
The unpack phase is responsible for unpacking the source code of the package. The default implementation of unpackPhase unpacks the source files listed in the src environment variable to the current directory. It supports the following files by default:
Additional file types can be supported by setting the unpackCmd variable (see below).
The patch phase applies the list of patches defined in the patches variable.
The configure phase prepares the source tree for building. The default configurePhase runs ./configure (typically an Autoconf-generated script) if it exists.
The build phase is responsible for actually building the package (e.g. compiling it). The default buildPhase simply calls make if a file named Makefile, makefile or GNUmakefile exists in the current directory (or the makefile is explicitly set); otherwise it does nothing.
A shell array containing additional arguments passed to make. You must use this instead of makeFlags if the arguments contain spaces, e.g.
makeFlagsArray=(CFLAGS="-O0 -g" LDFLAGS="-lfoo -lbar")
Note that shell arrays cannot be passed through environment variables, so you cannot set makeFlagsArray in a derivation attribute (because those are passed through environment variables): you have to define them in shell code.
You can set flags for make through the makeFlags variable.
Before and after running make, the hooks preBuild and postBuild are called, respectively.
The check phase checks whether the package was built correctly by running its test suite. The default checkPhase calls make check, but only if the doCheck variable is enabled.
If set to a non-empty string, the check phase is executed, otherwise it is skipped (default). Thus you should set
doCheck = true;
in the derivation to enable checks.
The install phase is responsible for installing the package in the Nix store under out. The default installPhase creates the directory $out and calls make install.
The make targets that perform the installation. Defaults to install. Example:
installTargets = "install-bin install-doc";
The fixup phase performs some (Nix-specific) post-processing actions on the files installed under $out by the install phase. The default fixupPhase does the following:
List of directories to search for libraries and executables from which only debugging-related symbols should be stripped. It defaults to ``lib bin
sbin``.
The distribution phase is intended to produce a source distribution of the package. The default distPhase first calls make dist, then it copies the resulting source tarballs to $out/tarballs/. This phase is only executed if the attribute doDist is set.
The standard environment provides a number of useful functions.
Performs string substitution on the contents of infile, writing the result to outfile. The substitutions in subs are of the following form:
Example:
substitute ./foo.in ./foo.out \
--replace /usr/bin/bar $bar/bin/bar \
--replace "a string containing spaces" "some other text" \
--subst-var someVar
substitute is implemented using the replace command. Unlike with the sed command, you don’t have to worry about escaping special characters. It supports performing substitutions on binary files (such as executables), though there you’ll probably want to make sure that the replacement string is as long as the replaced string.
Replaces every occurence of @@, where varName is any environment variable, in infile, writing the result to outfile. For instance, if infile has the contents
#! @bash@/bin/sh
PATH=@coreutils@/bin
echo @foo@
and the environment contains bash=/nix/store/bmwp0q28cf21...-bash-3.2-p39 and coreutils=/nix/store/68afga4khv0w...-coreutils-6.12, but does not contain the variable foo, then the output will be
#! /nix/store/bmwp0q28cf21...-bash-3.2-p39/bin/sh
PATH=/nix/store/68afga4khv0w...-coreutils-6.12/bin
echo @foo@
That is, no substitution is performed for undefined variables.
Strips the directory and hash part of a store path, and prints (on standard output) only the name part. For instance, ``stripHash
/nix/store/68afga4khv0w...-coreutils-6.12`` print
coreutils-6.12.
The following packages provide a setup hook:
Adds the lib/python2.5/site-packages subdirectory of each build input to the PYTHONPATH environment variable.
Note
This should be generalised: the Python version shouldn’t be hard-coded.
[measures taken to prevent dependencies on packages outside the store, and what you can do to prevent them]
GCC doesn’t search in locations such as /usr/include. In fact, attempts to add such directories through the -I flag are filtered out. Likewise, the linker (from GNU binutils) doesn’t search in standard locations such as /usr/lib. Programs built on Linux are linked against a GNU C Library that likewise doesn’t search in the default system locations.
[1] | It clears the sys_lib_search_path variables in the Libtool script to prevent Libtool from using libraries in /usr/lib and such. |