Writing Nix Expressions This chapter shows you how to write Nix expressions, which are the things that tell Nix how to build components. It starts with a simple example (a Nix expression for GNU Hello), and then moves on to a more in-depth look at the Nix expression language. A simple Nix expression This section shows how to add and test the GNU Hello package to the Nix Packages collection. Hello is a program that prints out the text Hello, world!. To add a component to the Nix Packages collection, you generally need to do three things: Write a Nix expression for the component. This is a file that describes all the inputs involved in building the component, such as dependencies (other components required by the component), sources, and so on. Write a builder. This is a shell scriptIn fact, it can be written in any language, but typically it's a bash shell script. that actually builds the component from the inputs. Add the component to the file pkgs/system/all-packages-generic.nix. The Nix expression written in the first step is a function; it requires other components in order to build it. In this step you put it all together, i.e., you call the function with the right arguments to build the actual component. The Nix expression Nix expression for GNU Hello {stdenv, fetchurl, perl}: stdenv.mkDerivation { name = "hello-2.1.1"; builder = ./builder.sh; src = fetchurl { url = ftp://ftp.nluug.nl/pub/gnu/hello/hello-2.1.1.tar.gz; md5 = "70c9ccf9fac07f762c24f2df2290784d"; }; inherit perl; } shows a Nix expression for GNU Hello. It's actually already in the Nix Packages collection in pkgs/applications/misc/hello/ex-1/default.nix. It is customary to place each package in a separate directory and call the single Nix expression in that directory default.nix. The file has the following elements (referenced from the figure by number): This states that the expression is a function that expects to be called with three arguments: stdenv, fetchurl, and perl. They are needed to build Hello, but we don't know how to build them here; that's why they are function arguments. stdenv is a component that is used by almost all Nix Packages components; it provides a standard environment consisting of the things you would expect in a basic Unix environment: a C/C++ compiler (GCC, to be precise), the Bash shell, fundamental Unix tools such as cp, grep, tar, etc. (See pkgs/stdenv/nix/path.nix to see what's in stdenv.) fetchurl is a function that downloads files. perl is the Perl interpreter. Nix functions generally have the form {x, y, ..., z}: e where x, y, etc. are the names of the expected arguments, and where e is the body of the function. So here, the entire remainder of the file is the body of the function; when given the required arguments, the body should describe how to build an instance of the Hello component. So we have to build a component. Building something from other stuff is called a derivation in Nix (as opposed to sources, which are built by humans instead of computers). We perform a derivation by calling stdenv.mkDerivation. mkDerivation is a function provided by stdenv that builds a component from a set of attributes. An attribute set is just a list of key/value pairs where the value is an arbitrary Nix expression. They take the general form {name1 = expr1; ... name1 = expr1;. The attribute name specifies the symbolic name and version of the component. Nix doesn't really care about these things, but they are used by for instance nix-env -q to show a human-readable name for components. This attribute is required by mkDerivation. The attribute builder specifies the builder. This attribute can sometimes be omitted, in which case mkDerivation will fill in a default builder (which does a configure; make; make install, in essence). Hello is sufficiently simple that the default builder would suffice, but in this case, we will show an actual builder for educational purposes. The value ./builder.sh refers to the shell script shown in , discussed below. The builder has to know what the sources of the component are. Here, the attribute src is bound to the result of a call to the fetchurl function. Given a URL and a MD5 hash of the expected contents of the file at that URL, this function actually builds a derivation that downloads the file and checks its hash. So the sources are a dependency that like all other dependencies is built before Hello itself is built. Instead of src any other name could have been used, and in fact there can be any number of sources (bound to different attributes). However, src is customary, and it's also expected by the default builder (which we don't use in this example). Since the derivation requires Perl, we have to pass the value of the perl function argument to the builder. All attributes in the set are actually passed as environment variables to the builder, so declaring an attribute perl = perl; will do the trink: it binds an attribute perl to the function argument which also happens to be called perl. However, it looks a bit silly, so there is a shorter syntax. The inherit keyword causes the specified attributes to be bound to whatever variables with the same name happen to be in scope. The builder Build script for GNU Hello . $stdenv/setup PATH=$perl/bin:$PATH tar xvfz $src cd hello-* ./configure --prefix=$out make make install shows the builder referenced from Hello's Nix expression (stored in pkgs/applications/misc/hello/ex-1/builder.sh). TODO If you are wondering about the absence of error checking on the result of various commands called in the builder: this is because the shell script is evaluated with Bash's option, which causes the script to be aborted if any command fails without an error check.