2004-10-14 14:55:12 +03:00
|
|
|
<chapter id='chap-writing-nix-expressions'><title>Writing Nix Expressions</title>
|
|
|
|
|
2004-11-04 22:21:08 +02:00
|
|
|
<para>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.</para>
|
|
|
|
|
|
|
|
|
2004-10-14 14:55:12 +03:00
|
|
|
<sect1><title>A simple Nix expression</title>
|
|
|
|
|
2004-11-04 22:21:08 +02:00
|
|
|
<para>This section shows how to add and test the <ulink
|
|
|
|
url='http://www.gnu.org/software/hello/hello.html'>GNU Hello
|
|
|
|
package</ulink> to the Nix Packages collection. Hello is a program
|
|
|
|
that prints out the text <quote>Hello, world!</quote>.</para>
|
|
|
|
|
|
|
|
<para>To add a component to the Nix Packages collection, you generally
|
|
|
|
need to do three things:
|
|
|
|
|
|
|
|
<orderedlist>
|
|
|
|
|
|
|
|
<listitem><para>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.</para></listitem>
|
|
|
|
|
|
|
|
<listitem><para>Write a <emphasis>builder</emphasis>. This is a
|
|
|
|
shell script<footnote><para>In fact, it can be written in any
|
|
|
|
language, but typically it's a <command>bash</command> shell
|
|
|
|
script.</para></footnote> that actually builds the component from
|
|
|
|
the inputs.</para></listitem>
|
|
|
|
|
|
|
|
<listitem><para>Add the component to the file
|
|
|
|
<filename>pkgs/system/all-packages-generic.nix</filename>. The Nix
|
|
|
|
expression written in the first step is a
|
|
|
|
<emphasis>function</emphasis>; 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.</para></listitem>
|
|
|
|
|
|
|
|
</orderedlist>
|
|
|
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
|
|
|
|
<sect2><title>The Nix expression</title>
|
2004-10-14 14:55:12 +03:00
|
|
|
|
2004-11-05 15:10:08 +02:00
|
|
|
<example id='ex-hello-nix'><title>Nix expression for GNU Hello
|
|
|
|
(<filename>default.nix</filename>)</title>
|
2004-10-14 14:55:12 +03:00
|
|
|
<programlisting>
|
|
|
|
{stdenv, fetchurl, perl}: <co id='ex-hello-nix-co-1' />
|
|
|
|
|
2004-11-04 22:21:08 +02:00
|
|
|
stdenv.mkDerivation { <co id='ex-hello-nix-co-2' />
|
2004-10-14 14:55:12 +03:00
|
|
|
name = "hello-2.1.1"; <co id='ex-hello-nix-co-3' />
|
2004-11-04 22:21:08 +02:00
|
|
|
builder = ./builder.sh; <co id='ex-hello-nix-co-4' />
|
|
|
|
src = fetchurl { <co id='ex-hello-nix-co-5' />
|
2004-10-14 14:55:12 +03:00
|
|
|
url = ftp://ftp.nluug.nl/pub/gnu/hello/hello-2.1.1.tar.gz;
|
|
|
|
md5 = "70c9ccf9fac07f762c24f2df2290784d";
|
|
|
|
};
|
2004-11-04 22:21:08 +02:00
|
|
|
inherit perl; <co id='ex-hello-nix-co-6' />
|
2004-10-14 14:55:12 +03:00
|
|
|
}</programlisting>
|
|
|
|
</example>
|
|
|
|
|
2004-11-04 22:21:08 +02:00
|
|
|
<para><xref linkend='ex-hello-nix' /> shows a Nix expression for GNU
|
|
|
|
Hello. It's actually already in the Nix Packages collection in
|
|
|
|
<filename>pkgs/applications/misc/hello/ex-1/default.nix</filename>.
|
|
|
|
It is customary to place each package in a separate directory and call
|
|
|
|
the single Nix expression in that directory
|
|
|
|
<filename>default.nix</filename>. The file has the following elements
|
|
|
|
(referenced from the figure by number):
|
|
|
|
|
|
|
|
<calloutlist>
|
|
|
|
|
|
|
|
<callout arearefs='ex-hello-nix-co-1'>
|
|
|
|
|
|
|
|
<para>This states that the expression is a
|
|
|
|
<emphasis>function</emphasis> that expects to be called with three
|
|
|
|
arguments: <varname>stdenv</varname>, <varname>fetchurl</varname>,
|
|
|
|
and <varname>perl</varname>. They are needed to build Hello, but
|
|
|
|
we don't know how to build them here; that's why they are function
|
|
|
|
arguments. <varname>stdenv</varname> is a component that is used
|
|
|
|
by almost all Nix Packages components; it provides a
|
|
|
|
<quote>standard</quote> 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
|
|
|
|
<command>cp</command>, <command>grep</command>,
|
|
|
|
<command>tar</command>, etc. (See
|
|
|
|
<filename>pkgs/stdenv/nix/path.nix</filename> to see what's in
|
|
|
|
<command>stdenv</command>.) <varname>fetchurl</varname> is a
|
|
|
|
function that downloads files. <varname>perl</varname> is the
|
|
|
|
Perl interpreter.</para>
|
|
|
|
|
|
|
|
<para>Nix functions generally have the form <literal>{x, y, ...,
|
|
|
|
z}: e</literal> where <varname>x</varname>, <varname>y</varname>,
|
|
|
|
etc. are the names of the expected arguments, and where
|
|
|
|
<replaceable>e</replaceable> 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.</para>
|
2004-10-14 14:55:12 +03:00
|
|
|
|
2004-11-04 22:21:08 +02:00
|
|
|
</callout>
|
|
|
|
|
|
|
|
<callout arearefs='ex-hello-nix-co-2'>
|
|
|
|
|
|
|
|
<para>So we have to build a component. Building something from
|
|
|
|
other stuff is called a <emphasis>derivation</emphasis> in Nix (as
|
|
|
|
opposed to sources, which are built by humans instead of
|
|
|
|
computers). We perform a derivation by calling
|
|
|
|
<varname>stdenv.mkDerivation</varname>.
|
|
|
|
<varname>mkDerivation</varname> is a function provided by
|
|
|
|
<varname>stdenv</varname> that builds a component from a set of
|
|
|
|
<emphasis>attributes</emphasis>. An attribute set is just a list
|
|
|
|
of key/value pairs where the value is an arbitrary Nix expression.
|
|
|
|
They take the general form
|
|
|
|
<literal>{<replaceable>name1</replaceable> =
|
|
|
|
<replaceable>expr1</replaceable>; <replaceable>...</replaceable>
|
|
|
|
<replaceable>name1</replaceable> =
|
|
|
|
<replaceable>expr1</replaceable>;</literal>.</para>
|
|
|
|
|
|
|
|
</callout>
|
|
|
|
|
|
|
|
<callout arearefs='ex-hello-nix-co-3'>
|
|
|
|
|
|
|
|
<para>The attribute <varname>name</varname> specifies the symbolic
|
|
|
|
name and version of the component. Nix doesn't really care about
|
|
|
|
these things, but they are used by for instance <command>nix-env
|
|
|
|
-q</command> to show a <quote>human-readable</quote> name for
|
|
|
|
components. This attribute is required by
|
|
|
|
<varname>mkDerivation</varname>.</para>
|
|
|
|
|
|
|
|
</callout>
|
|
|
|
|
|
|
|
<callout arearefs='ex-hello-nix-co-4'>
|
|
|
|
|
|
|
|
<para>The attribute <varname>builder</varname> specifies the
|
|
|
|
builder. This attribute can sometimes be omitted, in which case
|
|
|
|
<varname>mkDerivation</varname> will fill in a default builder
|
|
|
|
(which does a <literal>configure; make; make install</literal>, 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
|
|
|
|
<command>./builder.sh</command> refers to the shell script shown
|
|
|
|
in <xref linkend='ex-hello-builder' />, discussed below.</para>
|
|
|
|
|
|
|
|
</callout>
|
|
|
|
|
|
|
|
<callout arearefs='ex-hello-nix-co-5'>
|
|
|
|
|
|
|
|
<para>The builder has to know what the sources of the component
|
|
|
|
are. Here, the attribute <varname>src</varname> is bound to the
|
|
|
|
result of a call to the <command>fetchurl</command> 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.</para>
|
|
|
|
|
|
|
|
<para>Instead of <varname>src</varname> any other name could have
|
|
|
|
been used, and in fact there can be any number of sources (bound
|
|
|
|
to different attributes). However, <varname>src</varname> is
|
|
|
|
customary, and it's also expected by the default builder (which we
|
|
|
|
don't use in this example).</para>
|
|
|
|
|
|
|
|
</callout>
|
|
|
|
|
|
|
|
<callout arearefs='ex-hello-nix-co-6'>
|
|
|
|
|
|
|
|
<para>Since the derivation requires Perl, we have to pass the
|
|
|
|
value of the <varname>perl</varname> function argument to the
|
|
|
|
builder. All attributes in the set are actually passed as
|
|
|
|
environment variables to the builder, so declaring an attribute
|
|
|
|
|
|
|
|
<programlisting>
|
|
|
|
perl = perl;</programlisting>
|
|
|
|
|
|
|
|
will do the trink: it binds an attribute <varname>perl</varname>
|
|
|
|
to the function argument which also happens to be called
|
|
|
|
<varname>perl</varname>. However, it looks a bit silly, so there
|
|
|
|
is a shorter syntax. The <literal>inherit</literal> keyword
|
|
|
|
causes the specified attributes to be bound to whatever variables
|
|
|
|
with the same name happen to be in scope.</para>
|
|
|
|
|
|
|
|
</callout>
|
|
|
|
|
|
|
|
</calloutlist>
|
|
|
|
|
2004-10-14 14:55:12 +03:00
|
|
|
</para>
|
|
|
|
|
2004-11-04 22:21:08 +02:00
|
|
|
</sect2>
|
2004-10-14 14:55:12 +03:00
|
|
|
|
2004-11-04 22:21:08 +02:00
|
|
|
|
|
|
|
<sect2><title>The builder</title>
|
|
|
|
|
2004-11-05 15:10:08 +02:00
|
|
|
<example id='ex-hello-builder'><title>Build script for GNU Hello
|
|
|
|
(<filename>builder.sh</filename>)</title>
|
2004-10-14 14:55:12 +03:00
|
|
|
<programlisting>
|
2004-11-05 15:10:08 +02:00
|
|
|
. $stdenv/setup <co id='ex-hello-builder-co-1' />
|
2004-10-14 14:55:12 +03:00
|
|
|
|
2004-11-05 15:10:08 +02:00
|
|
|
PATH=$perl/bin:$PATH <co id='ex-hello-builder-co-2' />
|
2004-10-14 14:55:12 +03:00
|
|
|
|
2004-11-05 15:10:08 +02:00
|
|
|
tar xvfz $src <co id='ex-hello-builder-co-3' />
|
2004-11-04 22:21:08 +02:00
|
|
|
cd hello-*
|
2004-11-05 15:10:08 +02:00
|
|
|
./configure --prefix=$out <co id='ex-hello-builder-co-4' />
|
|
|
|
make <co id='ex-hello-builder-co-5' />
|
2004-11-04 22:21:08 +02:00
|
|
|
make install</programlisting>
|
2004-10-14 14:55:12 +03:00
|
|
|
</example>
|
|
|
|
|
2004-11-04 22:21:08 +02:00
|
|
|
<para><xref linkend='ex-hello-builder' /> shows the builder referenced
|
|
|
|
from Hello's Nix expression (stored in
|
2004-11-05 15:10:08 +02:00
|
|
|
<filename>pkgs/applications/misc/hello/ex-1/builder.sh</filename>).
|
|
|
|
The builder can actually be made a lot shorter by using the
|
|
|
|
<emphasis>generic builder</emphasis> functions provided by
|
|
|
|
<varname>stdenv</varname>, but here we write out the build steps to
|
|
|
|
elucidate what a builder does. It performs the following
|
|
|
|
steps:</para>
|
2004-10-14 14:55:12 +03:00
|
|
|
|
2004-11-05 15:10:08 +02:00
|
|
|
<calloutlist>
|
|
|
|
|
|
|
|
<callout arearefs='ex-hello-builder-co-1'>
|
|
|
|
|
|
|
|
<para>When Nix runs a builder, it initially completely clears the
|
|
|
|
environment. For instance, the <envar>PATH</envar> variable is
|
|
|
|
empty<footnote><para>Actually, it's initialised to
|
|
|
|
<filename>/path-not-set</filename> to prevent Bash from setting it
|
|
|
|
to a default value.</para></footnote>. This is done to prevent
|
|
|
|
undeclared inputs from being used in the build process. If for
|
|
|
|
example the <envar>PATH</envar> contained
|
|
|
|
<filename>/usr/bin</filename>, then you might accidentally use
|
|
|
|
<filename>/usr/bin/gcc</filename>.</para>
|
|
|
|
|
|
|
|
<para>So the first step is to set up the environment. This is
|
|
|
|
done by calling the <filename>setup</filename> script of the
|
|
|
|
standard environment. The environment variable
|
|
|
|
<envar>stdenv</envar> points to the location of the standard
|
|
|
|
environment being used. (It wasn't specified explicitly as an
|
|
|
|
attribute in <xref linkend='ex-hello-nix' />, but
|
|
|
|
<varname>mkDerivation</varname> adds it automatically.)</para>
|
|
|
|
|
|
|
|
</callout>
|
|
|
|
|
|
|
|
<callout arearefs='ex-hello-builder-co-2'>
|
|
|
|
|
|
|
|
<para>Since Hello needs Perl, we have to make sure that Perl is in
|
|
|
|
the <envar>PATH</envar>. The <envar>perl</envar> environment
|
|
|
|
variable points to the location of the Perl component (since it
|
|
|
|
was passed in as an attribute to the derivation), so
|
|
|
|
<filename><replaceable>$perl</replaceable>/bin</filename> is the
|
|
|
|
directory containing the Perl interpreter.</para>
|
|
|
|
|
|
|
|
</callout>
|
|
|
|
|
|
|
|
<callout arearefs='ex-hello-builder-co-3'>
|
|
|
|
|
|
|
|
<para>Now we have to unpack the sources. The
|
|
|
|
<varname>src</varname> attribute was bound to the result of
|
|
|
|
fetching the Hello source tarball from the network, so the
|
|
|
|
<envar>src</envar> environment variable points to the location in
|
|
|
|
the Nix store to which the tarball was downloaded. After
|
|
|
|
unpacking, we <command>cd</command> to the resulting source
|
|
|
|
directory.</para>
|
|
|
|
|
|
|
|
<para>The whole build is performed in a temporary directory
|
|
|
|
created in <varname>/tmp</varname>, by the way. This directory is
|
|
|
|
removed after the builder finishes, so there is no need to clean
|
|
|
|
up the sources afterwards. Also, the temporary directory is
|
|
|
|
always newly created, so you don't have to worry about files from
|
|
|
|
previous builds interfering with the current build.</para>
|
|
|
|
|
|
|
|
</callout>
|
|
|
|
|
|
|
|
<callout arearefs='ex-hello-builder-co-4'>
|
|
|
|
|
|
|
|
<para>GNU Hello is a typical Autoconf-based package, so we first
|
|
|
|
have to run its <filename>configure</filename> script. In Nix
|
|
|
|
every component is stored in a separate location in the Nix store,
|
|
|
|
for instance
|
|
|
|
<filename>/nix/store/9a54ba97fb71b65fda531012d0443ce2-hello-2.1.1</filename>.
|
|
|
|
Nix computes this path by cryptographically hashing all attributes
|
|
|
|
of the derivation. The path is passed to the builder through the
|
|
|
|
<envar>out</envar> environment variable. So here we give
|
|
|
|
<filename>configure</filename> the parameter
|
|
|
|
<literal>--prefix=$out</literal> to cause Hello to be installed in
|
|
|
|
the expected location.</para>
|
|
|
|
|
|
|
|
</callout>
|
|
|
|
|
|
|
|
<callout arearefs='ex-hello-builder-co-5'>
|
|
|
|
|
|
|
|
<para>Finally we build Hello (<literal>make</literal>) and install
|
|
|
|
it into the location specified by <envar>out</envar>
|
|
|
|
(<literal>make install</literal>).</para>
|
|
|
|
|
|
|
|
</callout>
|
|
|
|
|
|
|
|
</calloutlist>
|
2004-10-14 14:55:12 +03:00
|
|
|
|
2004-11-04 22:21:08 +02:00
|
|
|
<para>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>-e</option> option,
|
|
|
|
which causes the script to be aborted if any command fails without an
|
|
|
|
error check.</para>
|
2004-10-14 14:55:12 +03:00
|
|
|
|
2004-11-04 22:21:08 +02:00
|
|
|
</sect2>
|
2004-10-14 14:55:12 +03:00
|
|
|
|
|
|
|
|
2004-11-05 15:10:08 +02:00
|
|
|
<sect2><title>Composition</title>
|
|
|
|
|
|
|
|
<example id='ex-hello-composition'><title>Composing GNU Hello
|
|
|
|
(<filename>all-packages-generic.nix</filename>)</title>
|
|
|
|
<programlisting>
|
|
|
|
...
|
|
|
|
|
|
|
|
rec { <co id='ex-hello-composition-co-1' />
|
|
|
|
|
|
|
|
hello = (import ../applications/misc/hello/ex-1 <co id='ex-hello-composition-co-2' />) { <co id='ex-hello-composition-co-3' />
|
|
|
|
inherit fetchurl stdenv perl;
|
|
|
|
};
|
|
|
|
|
|
|
|
perl = (import ../development/interpreters/perl) { <co id='ex-hello-composition-co-4' />
|
|
|
|
inherit fetchurl stdenv;
|
|
|
|
};
|
|
|
|
|
|
|
|
fetchurl = (import ../build-support/fetchurl) {
|
|
|
|
inherit stdenv; ...
|
|
|
|
};
|
|
|
|
|
|
|
|
stdenv = ...;
|
|
|
|
|
|
|
|
}
|
|
|
|
</programlisting>
|
|
|
|
</example>
|
|
|
|
|
|
|
|
<para>The Nix expression in <xref linkend='ex-hello-nix' /> is a
|
|
|
|
function; it is missing some arguments that have to be filled in
|
|
|
|
somewhere. In the Nix Packages collection this is done in the file
|
|
|
|
<filename>pkgs/system/all-packages-generic.nix</filename>, where all
|
|
|
|
Nix expressions for components are imported and called with the
|
|
|
|
appropriate arguments. <xref linkend='ex-hello-composition' /> shows
|
|
|
|
some fragments of
|
|
|
|
<filename>all-packages-generic.nix</filename>.</para>
|
|
|
|
|
|
|
|
<calloutlist>
|
|
|
|
|
|
|
|
<callout arearefs='ex-hello-composition-co-1'>
|
|
|
|
|
|
|
|
<para>This file defines a set of attributes, all of which are
|
|
|
|
concrete derivations (i.e., not functions). In fact, we define a
|
|
|
|
<emphasis>mutually recursive</emphasis> set of attributes. That
|
|
|
|
is, the attributes can refer to each other. This is precisely
|
|
|
|
what we want since we want to <quote>plug</quote> the
|
|
|
|
various components into each other.</para>
|
|
|
|
|
|
|
|
</callout>
|
|
|
|
|
|
|
|
<callout arearefs='ex-hello-composition-co-2'>
|
|
|
|
|
|
|
|
<para>Here we <emphasis>import</emphasis> the Nix expression for
|
|
|
|
GNU Hello. The import operation just loads and returns the
|
|
|
|
specified Nix expression. In fact, we could just have put the
|
|
|
|
contents of <xref linkend='ex-hello-nix' /> in
|
|
|
|
<filename>all-packages-generic.nix</filename> at this point. That
|
|
|
|
would be completely equivalent, but it would make the file rather
|
|
|
|
bulky.</para>
|
|
|
|
|
|
|
|
<para>Note that we refer to
|
|
|
|
<filename>../applications/misc/hello/ex-1</filename>, not
|
|
|
|
<filename>../applications/misc/hello/ex-1/default.nix</filename>.
|
|
|
|
When you try to import a directory, Nix automatically appends
|
|
|
|
<filename>/default.nix</filename> to the file name.</para>
|
|
|
|
|
|
|
|
</callout>
|
|
|
|
|
|
|
|
<callout arearefs='ex-hello-composition-co-3'>
|
|
|
|
|
|
|
|
<para>This is where the actual composition takes place. Here we
|
|
|
|
<emphasis>call</emphasis> the function imported from
|
|
|
|
<filename>../applications/misc/hello/ex-1</filename> with an
|
|
|
|
attribute set containing the things that the function expects,
|
|
|
|
namely <varname>fetchurl</varname>, <varname>stdenv</varname>, and
|
|
|
|
<varname>perl</varname>. We use inherit again to use the
|
|
|
|
attributes defined in the surrounding scope (we could also have
|
|
|
|
written <literal>fetchurl = fetchurl;</literal>, etc.).</para>
|
|
|
|
|
|
|
|
<para>The result of this function call is an actual derivation
|
|
|
|
that can be built by Nix (since when we fill in the arguments of
|
|
|
|
the function, what we get is its body, which is the call to
|
|
|
|
<varname>stdenv.mkDerivation</varname> in <xref
|
|
|
|
linkend='ex-hello-nix ' />).</para>
|
|
|
|
|
|
|
|
</callout>
|
|
|
|
|
|
|
|
<callout arearefs='ex-hello-composition-co-4'>
|
|
|
|
|
|
|
|
<para>Likewise, we have to instantiate Perl,
|
|
|
|
<varname>fetchurl</varname>, and the standard environment.</para>
|
|
|
|
|
|
|
|
</callout>
|
|
|
|
|
|
|
|
</calloutlist>
|
|
|
|
|
|
|
|
</sect2>
|
|
|
|
|
|
|
|
|
|
|
|
<sect2><title>Testing</title>
|
|
|
|
|
|
|
|
<para>You can now try to build Hello. The simplest way to do that is
|
|
|
|
by using <command>nix-env</command>:
|
|
|
|
|
|
|
|
<screen>
|
|
|
|
$ nix-env -f pkgs/system/i686-linux.nix -i hello
|
|
|
|
installing `hello-2.1.1'
|
|
|
|
building path `/nix/store/632d2b22514dcebe704887c3da15448d-hello-2.1.1'
|
|
|
|
hello-2.1.1/
|
|
|
|
hello-2.1.1/intl/
|
|
|
|
hello-2.1.1/intl/ChangeLog
|
|
|
|
<replaceable>...</replaceable>
|
|
|
|
</screen>
|
|
|
|
|
|
|
|
This will build Hello and install it into your profile. The file
|
|
|
|
<filename>i686-linux</filename> is just a simple Nix expression that
|
|
|
|
imports <filename>all-packages-generic.nix</filename> and instantiates
|
|
|
|
it for Linux on the x86 platform.</para>
|
|
|
|
|
|
|
|
<para>Note that the <literal>hello</literal> argument here refers to
|
|
|
|
the symbolic name given to the Hello derivation (the
|
|
|
|
<varname>name</varname> attribute in <xref linkend='ex-hello-nix' />),
|
|
|
|
<emphasis>not</emphasis> the <varname>hello</varname> attribute in
|
|
|
|
<filename>all-packages-generic.nix</filename>.
|
|
|
|
<command>nix-env</command> simply walks through all derivations
|
|
|
|
defined in the latter file, looking for one with a
|
|
|
|
<varname>name</varname> attribute matching the command-line
|
|
|
|
argument.</para>
|
|
|
|
|
|
|
|
<para>You can test whether it works:
|
|
|
|
|
|
|
|
<screen>
|
|
|
|
$ hello
|
|
|
|
Hello, world!</screen>
|
|
|
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>Generally, however, using <command>nix-env</command> is not the
|
|
|
|
best way to test components, since you may not want to install them
|
|
|
|
into your profile right away (they might not work properly, after
|
|
|
|
all). A better way is to write a short file containging the
|
|
|
|
following:
|
|
|
|
|
|
|
|
<programlisting>
|
|
|
|
(import pkgs/system/i686-linux.nix).hello</programlisting>
|
|
|
|
|
2004-11-05 23:11:01 +02:00
|
|
|
Call it <filename>test.nix</filename>. You can then build it without
|
2004-11-05 15:10:08 +02:00
|
|
|
installing it using the command <command>nix-build</command>:
|
|
|
|
|
|
|
|
<screen>
|
|
|
|
$ nix-build ./test.nix
|
|
|
|
...
|
|
|
|
/nix/store/632d2b22514dcebe704887c3da15448d-hello-2.1.1</screen>
|
|
|
|
|
|
|
|
<command>nix-build</command> will build the derivation and print the
|
|
|
|
output path. It also creates a symlink to the output path called
|
|
|
|
<filename>result</filename> in the current directory. This is
|
|
|
|
convenient for testing the component:
|
|
|
|
|
|
|
|
<screen>
|
|
|
|
$ ./result/bin/hello
|
|
|
|
Hello, world!</screen>
|
|
|
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>Nix has a transactional semantics. Once a build finishes
|
|
|
|
succesfully, Nix makes a note of this in its database: it registers
|
|
|
|
that the path denoted by <envar>out</envar> is now
|
|
|
|
<quote>valid</quote>. If you try to build the derivation again, Nix
|
|
|
|
will see that the path is already valid and finish immediately. If a
|
|
|
|
build fails, either because it returns a non-zero exit code, because
|
|
|
|
Nix or the builder are killed, or because the machine crashes, then
|
|
|
|
the output path will not be registered as valid. If you try to build
|
|
|
|
the derivation again, Nix will remove the output path if it exists
|
|
|
|
(e.g., because the builder died half-way through <literal>make
|
|
|
|
install</literal>) and try again. Note that there is no
|
|
|
|
<quote>negative caching</quote>: Nix doesn't remember that a build
|
|
|
|
failed, and so a failed build can always be repeated. This is because
|
|
|
|
Nix cannot distinguish between permanent failures (e.g., a compiler
|
|
|
|
error due to a syntax error in the source) and transient failures
|
|
|
|
(e.g., a disk full condition).</para>
|
|
|
|
|
|
|
|
<para>Nix also performs locking. If you run multiple Nix builds
|
|
|
|
simultaneously, and they try to build the same derivation, the first
|
|
|
|
Nix instance that gets there will perform the build, while the others
|
|
|
|
block (or perform other derivations if available) until the build
|
|
|
|
finishes. So it is always safe to run multiple instances of Nix in
|
|
|
|
parallel (contrary to, say, <command>make</command>).</para>
|
|
|
|
|
|
|
|
<para>If you have a system with multiple CPUs, you may want to have
|
|
|
|
Nix build different derivations in parallel (insofar as possible).
|
|
|
|
Just pass the option <option>-j <replaceable>N</replaceable></option>,
|
|
|
|
where <replaceable>N</replaceable> is the maximum number of jobs to be
|
|
|
|
run in parallel. Typically this should be the number of CPUs.</para>
|
|
|
|
|
|
|
|
</sect2>
|
|
|
|
|
|
|
|
|
2004-11-05 17:39:30 +02:00
|
|
|
<sect2><title>The generic builder</title>
|
|
|
|
|
2004-11-05 23:11:01 +02:00
|
|
|
<para>Recall from <xref linkend='ex-hello-builder' /> that the builder
|
|
|
|
looked something like this:
|
|
|
|
|
|
|
|
<programlisting>
|
|
|
|
PATH=$perl/bin:$PATH
|
|
|
|
tar xvfz $src
|
|
|
|
cd hello-*
|
|
|
|
./configure --prefix=$out
|
|
|
|
make
|
|
|
|
make install</programlisting>
|
|
|
|
|
|
|
|
The builders for almost all Unix packages look like this — set up some
|
|
|
|
environment variables, unpack the sources, configure, build, and
|
|
|
|
install. For this reason the standard environment provides some Bash
|
|
|
|
functions that automate the build process. A builder using the
|
|
|
|
generic build facilities in shown in <xref linkend='ex-hello-builder2'
|
|
|
|
/>.</para>
|
|
|
|
|
|
|
|
<example id='ex-hello-builder2'><title>Build script using the generic
|
|
|
|
build functions</title>
|
|
|
|
<programlisting>
|
|
|
|
buildInputs="$perl" <co id='ex-hello-builder2-co-1' />
|
|
|
|
|
|
|
|
. $stdenv/setup <co id='ex-hello-builder2-co-2' />
|
|
|
|
|
|
|
|
genericBuild <co id='ex-hello-builder2-co-3' /></programlisting>
|
|
|
|
</example>
|
|
|
|
|
|
|
|
<calloutlist>
|
|
|
|
|
|
|
|
<callout arearefs='ex-hello-builder2-co-1'>
|
|
|
|
|
|
|
|
<para>The <envar>buildInputs</envar> variable tells
|
|
|
|
<filename>setup</filename> to use the indicated components as
|
|
|
|
<quote>inputs</quote>. This means that if a component provides a
|
|
|
|
<filename>bin</filename> subdirectory, it's added to
|
|
|
|
<envar>PATH</envar>; if it has a <filename>include</filename>
|
|
|
|
subdirectory, it's added to GCC's header search path; and so
|
|
|
|
on.</para>
|
|
|
|
|
|
|
|
</callout>
|
|
|
|
|
|
|
|
<callout arearefs='ex-hello-builder2-co-2'>
|
|
|
|
|
|
|
|
<para>The function <function>genericBuild</function> is defined in
|
|
|
|
the file <literal>$stdenv/setup</literal>.</para>
|
|
|
|
|
|
|
|
</callout>
|
|
|
|
|
|
|
|
<callout arearefs='ex-hello-builder2-co-3'>
|
|
|
|
|
|
|
|
<para>The final step calls the shell function
|
|
|
|
<function>genericBuild</function>, which performs the steps that
|
|
|
|
were done explicitly in <xref linkend='ex-hello-builder' />. The
|
|
|
|
generic builder is smart enough to figure out whether to unpack
|
|
|
|
the sources using <command>gzip</command>,
|
|
|
|
<command>bzip2</command>, etc. It can be customised in many ways;
|
|
|
|
see <xref linkend='sec-standard-environment' />.</para>
|
|
|
|
|
|
|
|
</callout>
|
|
|
|
|
|
|
|
</calloutlist>
|
|
|
|
|
|
|
|
<para>Discerning readers will note that the
|
|
|
|
<envar>buildInputs</envar> could just as well have been set in the Nix
|
|
|
|
expression, like this:
|
|
|
|
|
|
|
|
<programlisting>
|
|
|
|
buildInputs = [perl];</programlisting>
|
|
|
|
|
|
|
|
The <varname>perl</varname> attribute can then be removed, and the
|
|
|
|
builder becomes even shorter:
|
|
|
|
|
|
|
|
<programlisting>
|
|
|
|
. $stdenv/setup
|
2004-11-05 23:12:23 +02:00
|
|
|
genericBuilder</programlisting>
|
2004-11-05 23:11:01 +02:00
|
|
|
|
|
|
|
In fact, <varname>mkDerivation</varname> provides a default builder
|
|
|
|
that looks exactly like that, so it is actually possible to omit the
|
|
|
|
builder for Hello entirely.</para>
|
2004-11-05 17:39:30 +02:00
|
|
|
|
|
|
|
</sect2>
|
|
|
|
|
|
|
|
|
|
|
|
</sect1>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<sect1><title>The Nix expression language</title>
|
|
|
|
|
|
|
|
<para>The Nix expression language is a pure, lazy, functional
|
|
|
|
language. Purity means that operations in the language don't have
|
|
|
|
side-effects (for instance, there is no variable assignment).
|
|
|
|
Laziness means that arguments to functions are evaluated only when
|
|
|
|
they are needed. Functional means that functions are
|
|
|
|
<quote>normal</quote> values that can be passed around and
|
|
|
|
manipulated in interesting ways.</para>
|
|
|
|
|
|
|
|
<para>The language is not a full-featured, general purpose language.
|
|
|
|
It's main job is to describe components, compositions of components,
|
|
|
|
and the variability within components. For this a functional language
|
|
|
|
is perfectly suited.</para>
|
|
|
|
|
|
|
|
<para>This section presents the various features of the
|
|
|
|
language.</para>
|
|
|
|
|
|
|
|
|
|
|
|
<simplesect><title>Simple values</title>
|
|
|
|
|
|
|
|
<para>Nix has the following basic datatypes:
|
|
|
|
|
|
|
|
<itemizedlist>
|
|
|
|
|
|
|
|
<listitem><para><emphasis>Strings</emphasis>, enclosed between
|
|
|
|
double quotes, e.g., <literal>"foo bar"</literal>.</para></listitem>
|
|
|
|
|
|
|
|
<listitem><para><emphasis>Integers</emphasis>, e.g.,
|
|
|
|
<literal>123</literal>.</para></listitem>
|
|
|
|
|
|
|
|
<listitem><para><emphasis>URIs</emphasis> as defined in appendix B
|
|
|
|
of <ulink url='http://www.ietf.org/rfc/rfc2396.txt'>RFC
|
|
|
|
2396</ulink>, e.g.,
|
|
|
|
<literal>https://svn.cs.uu.nl:12443/dist/trace/trace-nix-trunk.tar.bz2</literal>.</para></listitem>
|
|
|
|
|
|
|
|
<listitem><para><emphasis>Paths</emphasis>, e.g.,
|
|
|
|
<filename>/bin/sh</filename> or <filename>./builder.sh</filename>.
|
|
|
|
A path must contain at least one slash to be recognised as such; for
|
|
|
|
instance, <filename>builder.sh</filename> is not a
|
|
|
|
path<footnote><para>It's parsed as an expression that selects the
|
|
|
|
attribute <varname>sh</varname> from the variable
|
|
|
|
<varname>builder</varname>.</para></footnote>. If the filename is
|
|
|
|
relative, i.e., if it does not begin with a slash, it is made
|
|
|
|
absolute at parse time relative to the directory of the Nix
|
|
|
|
expression that contained it. For instance, if a Nix expression in
|
|
|
|
<filename>/foo/bar/bla.nix</filename> refers to
|
|
|
|
<filename>../xyzzy/fnord.nix</filename>, the absolutised path is
|
|
|
|
<filename>/foo/xyzzy/fnord.nix</filename>.</para></listitem>
|
|
|
|
|
|
|
|
</itemizedlist>
|
|
|
|
|
|
|
|
</para>
|
|
|
|
|
|
|
|
</simplesect>
|
|
|
|
|
|
|
|
|
|
|
|
<simplesect><title>Lists</title>
|
|
|
|
|
|
|
|
<para>Lists are formed by enclosing a whitespace-separated list of
|
|
|
|
values between square bracktes. For example,
|
|
|
|
|
|
|
|
<programlisting>
|
|
|
|
[ 123 ./foo.nix "abc" (f {x=y;}) ]</programlisting>
|
|
|
|
|
|
|
|
defines a list of four elements, the last being the result of a call
|
|
|
|
to the function <varname>f</varname>. Note that function calls have
|
|
|
|
to be enclosed in parentheses. If they had been omitted, e.g.,
|
|
|
|
|
|
|
|
<programlisting>
|
|
|
|
[ 123 ./foo.nix "abc" f {x=y;} ]</programlisting>
|
|
|
|
|
|
|
|
the result would be a list of five elements, the fourth one being a
|
|
|
|
function and the fifth being an attribute set.</para>
|
|
|
|
|
|
|
|
</simplesect>
|
|
|
|
|
|
|
|
|
|
|
|
<simplesect><title>Attribute sets</title>
|
|
|
|
|
|
|
|
<para>Attribute sets are really the core of the language, since
|
|
|
|
ultimately it's all about creating derivations, which are really just
|
|
|
|
sets of attributes to be passed to build scripts.</para>
|
|
|
|
|
|
|
|
<para>Attribute sets are just a list of name/value pairs enclosed in
|
|
|
|
curly brackets, where each value is an arbitrary expression terminated
|
|
|
|
by a semicolon. For example:
|
|
|
|
|
|
|
|
<programlisting>
|
|
|
|
{ x = 123;
|
|
|
|
text = "Hello";
|
|
|
|
y = f { bla = 456; };
|
|
|
|
}</programlisting>
|
|
|
|
|
|
|
|
This defines an attribute set with attributes named
|
|
|
|
<varname>x</varname>, <varname>test</varname>, <varname>y</varname>.
|
|
|
|
The order of the attributes is irrelevant. An attribute name may only
|
|
|
|
occur once.</para>
|
|
|
|
|
|
|
|
<para>Attributes can be selected from an attribute set using the
|
|
|
|
<literal>.</literal> operator. For instance,
|
|
|
|
|
|
|
|
<programlisting>
|
|
|
|
{ a = "Foo"; b = "Bar"; }.a</programlisting>
|
|
|
|
|
|
|
|
evaluates to <literal>"Foo"</literal>.</para>
|
|
|
|
|
|
|
|
</simplesect>
|
|
|
|
|
|
|
|
|
|
|
|
<simplesect><title>Recursive attribute sets</title>
|
|
|
|
|
|
|
|
<para>Recursive attribute sets are just normal attribute sets, but the
|
|
|
|
attributes can refer to each other. For example,
|
|
|
|
|
|
|
|
<programlisting>
|
|
|
|
rec {
|
|
|
|
x = y;
|
|
|
|
y = 123;
|
|
|
|
}.x
|
|
|
|
</programlisting>
|
|
|
|
|
|
|
|
evaluates to <literal>123</literal>. Note that without
|
|
|
|
<literal>rec</literal> the binding <literal>x = y;</literal> would
|
|
|
|
refer to the variable <varname>y</varname> in the surrounding scope,
|
|
|
|
if one exists, and would be invalid if no such variable exists. That
|
|
|
|
is, in a normal (non-recursive) attribute set, attributes are not
|
|
|
|
added to the lexical scope; in a recursive set, they are.</para>
|
|
|
|
|
|
|
|
<para>Recursive attribute sets of course introduce the danger of
|
|
|
|
infinite recursion. For example,
|
|
|
|
|
|
|
|
<programlisting>
|
|
|
|
rec {
|
|
|
|
x = y;
|
|
|
|
y = x;
|
|
|
|
}.x</programlisting>
|
|
|
|
|
|
|
|
does not terminate<footnote><para>Actually, Nix detects infinite
|
|
|
|
recursion in this case and aborts (<quote>infinite recursion
|
|
|
|
encountered</quote>).</para></footnote>.</para>
|
|
|
|
|
|
|
|
</simplesect>
|
|
|
|
|
|
|
|
<!--
|
|
|
|
<para>It is often convenient to copy variables from the surrounding
|
|
|
|
scope (e.g., when you want to propagate attributes). This can be
|
|
|
|
shortened using the <literal>inherit</literal> keyword. For instance,
|
|
|
|
-->
|
|
|
|
|
|
|
|
|
2004-11-05 23:11:01 +02:00
|
|
|
<simplesect><title>Let expressions</title>
|
2004-11-05 17:39:30 +02:00
|
|
|
|
|
|
|
<para>TODO</para>
|
|
|
|
|
|
|
|
</simplesect>
|
|
|
|
|
|
|
|
|
|
|
|
<simplesect><title>Inheriting attributes</title>
|
|
|
|
|
|
|
|
<para>TODO</para>
|
|
|
|
|
|
|
|
</simplesect>
|
|
|
|
|
|
|
|
|
|
|
|
<simplesect><title>Functions</title>
|
|
|
|
|
|
|
|
<para>TODO</para>
|
|
|
|
|
|
|
|
<para>Higher-order functions; map</para>
|
|
|
|
|
|
|
|
</simplesect>
|
|
|
|
|
|
|
|
|
|
|
|
<simplesect><title>Conditionals</title>
|
|
|
|
|
|
|
|
<para>TODO</para>
|
|
|
|
|
|
|
|
</simplesect>
|
|
|
|
|
|
|
|
|
2004-11-05 23:11:01 +02:00
|
|
|
<simplesect><title>With expressions</title>
|
2004-11-05 17:39:30 +02:00
|
|
|
|
|
|
|
<para>TODO</para>
|
|
|
|
|
|
|
|
</simplesect>
|
|
|
|
|
|
|
|
|
|
|
|
<simplesect><title>Operators</title>
|
|
|
|
|
|
|
|
<para>TODO</para>
|
|
|
|
|
|
|
|
</simplesect>
|
|
|
|
|
|
|
|
|
|
|
|
<simplesect><title>Derivations</title>
|
|
|
|
|
|
|
|
<para>TODO</para>
|
|
|
|
|
|
|
|
</simplesect>
|
|
|
|
|
|
|
|
|
|
|
|
<simplesect><title>Miscelleneous built-in functions</title>
|
|
|
|
|
|
|
|
<para>TODO</para>
|
|
|
|
|
|
|
|
</simplesect>
|
|
|
|
|
|
|
|
|
|
|
|
</sect1>
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-11-05 23:11:01 +02:00
|
|
|
<sect1 id='sec-standard-environment'><title>The standard environment</title>
|
2004-11-05 17:39:30 +02:00
|
|
|
|
|
|
|
<para>TODO</para>
|
|
|
|
|
2004-10-14 14:55:12 +03:00
|
|
|
</sect1>
|
|
|
|
|
|
|
|
|
|
|
|
</chapter>
|