* Split overview chapter into a chapter on package management and a

chapter on writing Nix expressions.
This commit is contained in:
Eelco Dolstra 2004-10-14 11:55:12 +00:00
parent 98c69e5172
commit febd8bed1b
6 changed files with 384 additions and 455 deletions

View File

@ -10,7 +10,8 @@ man1_MANS = nix-env.1 nix-store.1 nix-instantiate.1 \
nix-collect-garbage.1 nix-push.1 nix-pull.1 \ nix-collect-garbage.1 nix-push.1 nix-pull.1 \
nix-prefetch-url.1 nix-prefetch-url.1
SOURCES = manual.xml introduction.xml installation.xml overview.xml \ SOURCES = manual.xml introduction.xml installation.xml \
package-management.xml writing-nix-expressions.xml \
$(man1_MANS:.1=.xml) \ $(man1_MANS:.1=.xml) \
troubleshooting.xml bugs.xml opt-common.xml opt-common-syn.xml \ troubleshooting.xml bugs.xml opt-common.xml opt-common-syn.xml \
quick-start.xml nix-lang-ref.xml style.css images quick-start.xml nix-lang-ref.xml style.css images

View File

@ -9,7 +9,8 @@
<!ENTITY introduction SYSTEM "introduction.xml"> <!ENTITY introduction SYSTEM "introduction.xml">
<!ENTITY quick-start SYSTEM "quick-start.xml"> <!ENTITY quick-start SYSTEM "quick-start.xml">
<!ENTITY installation SYSTEM "installation.xml"> <!ENTITY installation SYSTEM "installation.xml">
<!ENTITY overview SYSTEM "overview.xml"> <!ENTITY package-management SYSTEM "package-management.xml">
<!ENTITY writing-nix-expressions SYSTEM "writing-nix-expressions.xml">
<!ENTITY opt-common SYSTEM "opt-common.xml"> <!ENTITY opt-common SYSTEM "opt-common.xml">
<!ENTITY opt-common-syn SYSTEM "opt-common-syn.xml"> <!ENTITY opt-common-syn SYSTEM "opt-common-syn.xml">
<!ENTITY nix-env SYSTEM "nix-env.xml"> <!ENTITY nix-env SYSTEM "nix-env.xml">
@ -44,7 +45,8 @@
&introduction; &introduction;
&quick-start; &quick-start;
&installation; &installation;
&overview; &package-management;
&writing-nix-expressions;
<appendix> <appendix>
<title>Command Reference</title> <title>Command Reference</title>

View File

@ -1,450 +0,0 @@
<chapter id='chap-overview'>
<title>Overview</title>
<para>
This chapter provides a guided tour of Nix.
</para>
<!--######################################################################-->
<sect1>
<title>Basic package management</title>
<para>
Let's start from the perspective of an end user. Common operations at
this level are to install and remove packages, ask what packages are
installed or available for installation, and so on. These are operations
on the <emphasis>user environment</emphasis>: the set of packages that a
user <quote>sees</quote>. In a command line Unix environment, this means
the set of programs that are available through the <envar>PATH</envar>
environment variable. (In other environments it might mean the set of
programs available on the desktop, through the start menu, and so on.)
</para>
<para>
The terms <quote>installation</quote> and <quote>uninstallation</quote>
are used in this context to denote the act of adding or removing packages
from the user environment. In Nix, these operations are dissociated from
the physical copying or deleting of files. Installation requires that
the files constituting the package are present, but they may be present
beforehand. Likewise, uninstallation does not actually delete any files;
this is done automatically by running a garbage collector.
</para>
<para>
User environments are manipulated through the <command>nix-env</command>
command. The query operation can be used to see what packages are
currently installed.
</para>
<screen>
$ nix-env -q
MozillaFirebird-0.7
sylpheed-0.9.7
pan-0.14.2</screen>
<para>
(<option>-q</option> is actually short for <option>--query
--installed</option>.) The package names are symbolic: they don't have
any particular significance to Nix (as they shouldn't, since they are not
unique&mdash;there can be many derivations with the same name). Note that
these packages have many dependencies (e.g., Mozilla uses the
<literal>gtk+</literal> package) but these have not been installed in the
user environment, though they are present on the system. Generally,
there is no need to install such packages; only packages containing
programs should be installed.
</para>
<para>
To install packages, a <emphasis>Nix expression</emphasis> is required
that tells Nix how to build that package. There is a <ulink
url='https://svn.cs.uu.nl:12443/dist/trace/trace-nixpkgs-trunk.tar.bz2'>set
of standard of Nix expressions</ulink> for many common packages.
Assuming that you have downloaded and unpacked these, you can view the
set of available packages:
</para>
<screen>
$ nix-env -qaf pkgs/system/i686-linux.nix
gettext-0.12.1
sylpheed-0.9.7
aterm-2.0
gtk+-1.2.10
apache-httpd-2.0.48
pan-0.14.2
...</screen>
<para>
The Nix expression in the file <filename>i686-linux.nix</filename> yields
the set of packages for a Linux system running on x86 hardware. For
other platforms, copy and modify this file for your platform as
appropriate. [TODO: improve this]
</para>
<para>
It is also possible to see the <emphasis>status</emphasis> of available
packages, i.e., whether they are installed into the user environment
and/or present in the system:
</para>
<screen>
$ nix-env -qasf pkgs/system/i686-linux.nix
-P gettext-0.12.1
IP sylpheed-0.9.7
-- aterm-2.0
-P gtk+-1.2.10</screen>
<para>
This reveals that the <literal>sylpheed</literal> package is already
installed, or more precisely, that exactly the same instantiation of
<literal>sylpheed</literal> is installed. This guarantees that the
available package is exactly the same as the installed package with
regard to sources, dependencies, build flags, and so on. Similarly, we
see that the <literal>gettext</literal> and <literal>gtk+</literal>
packages are present but not installed in the user environment, while the
<literal>aterm</literal> package is not installed or present at all (so,
if we were to install it, it would have to be built or downloaded first).
</para>
<para>
The install operation is used install available packages from a Nix
environment. To install the <literal>pan</literal> package (a
newsreader), you would do:
</para>
<screen>
$ nix-env -if pkgs/system/i686-linux.nix pan</screen>
<para>
Since installation may take a long time, depending on whether any
packages need to be built or downloaded, it's a good idea to make
<command>nix-env</command> run verbosely by using the <option>-v</option>
(<option>--verbose</option>) option. This option may be repeated to
increase the level of verbosity. A good value is 3
(<option>-vvv</option>).
</para>
<para>
In fact, if you run this command verbosely you will observe that Nix
starts to build many packages, including large and fundamental ones such
as <literal>glibc</literal> and <literal>gcc</literal>. I.e., you are
performing a source installation. This is generally undesirable, since
installation from sources may require large amounts of disk and CPU
resources. Therefore a <quote>binary</quote> installation is generally
preferable.
</para>
<para>
Rather than provide different mechanisms to create and perform
the installation of binary packages, Nix supports binary deployment
<emphasis>transparently</emphasis> through a generic mechanism of
<emphasis>substitute expressions</emphasis>. If an request is made to
build some Nix expression, Nix will first try to build any substitutes
for that expression. These substitutes presumably perform an identical
build operation with respect to the result, but require less resources.
For instance, a substitute that downloads a pre-built package from the
network requires less CPU and disk resources, and possibly less time.
</para>
<para>
Nix's use of cryptographic hashes makes this entirely safe. It is not
possible, for instance, to accidentally substitute a build of some
package for a Solaris or Windows system for a build on a SuSE/x86 system.
</para>
<para>
While the substitute mechanism is a generic mechanism, Nix provides two
standard tools called <command>nix-pull</command> and
<command>nix-push</command> that maintain and use a shared cache of
prebuilt derivations on some network site (reachable through HTTP). If
you attempt to install some package that someone else has previously
built and <quote>pushed</quote> into the cache, and you have done a
<quote>pull</quote> to register substitutes that download these prebuilt
packages, then the installation will automatically use these.
</para>
<para>
For example, to pull from our <ulink
url='http://losser.st-lab.cs.uu.nl/~eelco/nix-dist/'>cache</ulink> of
prebuilt packages (at the time of writing, for SuSE Linux/x86), use the
following command:
</para>
<screen>
$ nix-pull http://catamaran.labs.cs.uu.nl/dist/nix/nixpkgs-<replaceable>version</replaceable>/MANIFEST
obtaining list of Nix archives at http://catamaran.labs.cs.uu.nl/dist/nix/nixpkgs-<replaceable>version</replaceable>/MANIFEST...
...</screen>
<para>
If <command>nix-pull</command> is run without any arguments, it will pull
from the URLs specified in the file
<filename><replaceable>prefix</replaceable>/etc/nix/prebuilts.conf</filename>.
</para>
<para>
Assuming that the <literal>pan</literal> installation produced no errors,
it can be used immediately, that is, it now appears in a directory in the
<envar>PATH</envar> environment variable. Specifically,
<envar>PATH</envar> includes the entry
<filename><replaceable>prefix</replaceable>/var/nix/profiles/default/bin</filename>,
where
<filename><replaceable>prefix</replaceable>/var/nix/profiles/default</filename>
is just a symlink to the current user environment:
</para>
<screen>
$ ls -l /nix/var/nix/profiles/
...
lrwxrwxrwx 1 eelco ... default-15-link -> /nix/store/1871...12b0-user-environment
lrwxrwxrwx 1 eelco ... default-16-link -> /nix/store/59ba...df6b-user-environment
lrwxrwxrwx 1 eelco ... default -> default-16-link</screen>
<para>
That is, <filename>default</filename> in this example is a link
to <filename>default-16-link</filename>, which is the current
user environment. Before the installation, it pointed to
<filename>default-15-link</filename>. Note that this means that
you can atomically roll-back to the previous user environment by
pointing the symlink <filename>default</filename> at
<filename>default-15-link</filename> again. This also shows
that operations such as installation are atomic in the Nix
system: any arbitrarily complex set of installation,
uninstallation, or upgrade actions eventually boil down to the
single operation of pointing a symlink somewhere else (which can
be implemented atomically in Unix).
</para>
<para>
What's in a user environment? It's just a set of symlinks to the files
that constitute the installed packages. For instance:
</para>
<screen>
$ ls -l /nix/var/nix/profiles/default-16-link/bin
lrwxrwxrwx 1 eelco ... MozillaFirebird -> /nix/store/35f8...4ae6-MozillaFirebird-0.7/bin/MozillaFirebird
lrwxrwxrwx 1 eelco ... svn -> /nix/store/3829...fb5d-subversion-0.32.1/bin/svn
...</screen>
<para>
Note that, e.g., <filename>svn</filename> =
<filename>/nix/var/nix/profiles/default/bin/svn</filename> =
<filename>/nix/var/nix/profiles/default-16-link/bin/svn</filename> =
<filename>/nix/store/59ba...df6b-user-environment/bin/svn</filename> =
<filename>/nix/store/3829...fb5d-subversion-0.32.1/bin/svn</filename>.
</para>
<para>
Naturally, packages can also be uninstalled:
</para>
<screen>
$ nix-env -e pan</screen>
<para>
This means that the package is removed from the user
environment. It is <emphasis>not</emphasis> yet removed from
the system. When a package is uninstalled from a user
environment, it may still be used by other packages, or may
still be present in other user environments. Deleting it under
such conditions would break those other packages or user
environments. To prevent this, packages are only
<quote>physically</quote> deleted by running the Nix garbage
collector, which searches for all packages in the Nix store that
are no longer <quote>reachable</quote> from outside the store.
Thus, uninstalling a package is always safe: it cannot break
other packages.
</para>
<para>
Upgrading packages is easy. Given a Nix expression that
contains newer versions of installed packages (that is, packages
with the same package name, but a higher version number),
<command>nix-env -u</command> will replace the installed package
in the user environment with the newer package. For example,
<screen>
$ nix-env -uf pkgs/system/i686-linux.nix pan</screen>
looks for a newer version of Pan, and installs it if found.
Also useful is the ability to upgrade <emphasis>all</emphasis>
packages:
<screen>
$ nix-env -uf pkgs/system/i686-linux.nix '*'</screen>
The asterisk matches all installed packages<footnote><para>No,
we don't support arbitrary regular
expressions</para></footnote>. Note that <literal>*</literal>
must be quoted to prevent shell globbing.
</para>
</sect1>
<!--######################################################################-->
<sect1>
<title>Writing Nix expressions</title>
<sect2>
<title>A simple Nix expression</title>
<para>
This section shows how to write simple Nix expressions&mdash;the things
that describe how to build a package.
</para>
<example id='ex-hello-nix'>
<title>Nix expression for GNU Hello</title>
<programlisting>
{stdenv, fetchurl, perl}: <co id='ex-hello-nix-co-1' />
derivation { <co id='ex-hello-nix-co-2' />
name = "hello-2.1.1"; <co id='ex-hello-nix-co-3' />
system = stdenv.system; <co id='ex-hello-nix-co-4' />
builder = ./builder.sh; <co id='ex-hello-nix-co-5' />
src = fetchurl { <co id='ex-hello-nix-co-6' />
url = ftp://ftp.nluug.nl/pub/gnu/hello/hello-2.1.1.tar.gz;
md5 = "70c9ccf9fac07f762c24f2df2290784d";
};
stdenv = stdenv; <co id='ex-hello-nix-co-7' />
perl = perl;
}</programlisting>
</example>
<para>
A simple Nix expression is shown in <xref linkend='ex-hello-nix' />. It
describes how to the build the <ulink
url='http://www.gnu.org/directory/GNU/hello.html'>GNU Hello
package</ulink>. This package has several dependencies. First, it
requires a number of other packages, such as a C compiler, standard
Unix shell tools, and Perl. Rather than have this Nix expression refer
to and use specific versions of these packages, it should be generic;
that is, it should be a <emphasis>function</emphasis> that takes the
required packages as inputs and yield a build of the GNU Hello package
as a result. This Nix expression defines a function with three
arguments <xref linkend='ex-hello-nix-co-1' />, namely:
<orderedlist>
<listitem><para><varname>stdenv</varname>, which should be a
<emphasis>standard environment package</emphasis>. The standard
environment is a set of tools and other components that would be
expected in a fairly minimal Unix-like environment: a C compiler
and linker, Unix shell tools, and so on.</para>
</listitem>
<listitem><para><varname>fetchurl</varname>, which should be a
function that given parameters <varname>url</varname> and
<varname>md5</varname>, will fetch a file from the specified
location and check that this file has the given MD5 hash code.
The hash is required because build operations must be
<emphasis>pure</emphasis>: given the same inputs they should
always yield the same output. Since network resources can change
at any time, we must in some way guarantee what the result will
be.</para>
</listitem>
<listitem><para><varname>perl</varname>, which should be a Perl
interpreter.</para>
</listitem>
</orderedlist>
</para>
<para>
The remainder of the file is the body of the function, which happens to
be a <emphasis>derivation</emphasis> <xref
linkend='ex-hello-nix-co-2' />, which is the built-in function
<varname>derivation</varname> applied to a set of attributes that
encode all the necessary information for building the GNU Hello
package.
</para>
<example>
<title>Build script (<filename>builder.sh</filename>) for GNU
Hello</title>
<programlisting>
#! /bin/sh
buildinputs="$perl"
. $stdenv/setup || exit 1
tar xvfz $src || exit 1
cd hello-* || exit 1
./configure --prefix=$out || exit 1
make || exit 1
make install || exit 1</programlisting>
</example>
</sect2>
<sect2>
<title>A more complex Nix expression</title>
<example id='ex-svn-nix'>
<title>Nix expression for Subversion</title>
<programlisting>
{ localServer ? false <co id='ex-svn-nix-co-1' />
, httpServer ? false
, sslSupport ? false
, swigBindings ? false
, stdenv, fetchurl
, openssl ? null, httpd ? null, db4 ? null, expat, swig ? null
}:
assert !isNull expat; <co id='ex-svn-nix-co-2' />
assert localServer -> !isNull db4;
assert httpServer -> !isNull httpd &amp;&amp; httpd.expat == expat; <co id='ex-svn-nix-co-3' />
assert sslSupport -> !isNull openssl &amp;&amp; (httpServer -> httpd.openssl == openssl);
assert swigBindings -> !isNull swig;
derivation {
name = "subversion-0.32.1";
system = stdenv.system;
builder = ./builder.sh;
src = fetchurl {
url = http://svn.collab.net/tarballs/subversion-0.32.1.tar.gz;
md5 = "b06717a8ef50db4b5c4d380af00bd901";
};
localServer = localServer;
httpServer = httpServer;
sslSupport = sslSupport;
swigBindings = swigBindings;
stdenv = stdenv;
openssl = if sslSupport then openssl else null; <co id='ex-svn-nix-co-4' />
httpd = if httpServer then httpd else null;
expat = expat;
db4 = if localServer then db4 else null;
swig = if swigBindings then swig else null;
}</programlisting>
</example>
<para>
This example shows several features. Default parameters <xref
linkend='ex-svn-nix-co-1'/> can be used to simplify call sites: if an
argument that has a default is omitted, its default value is used.
</para>
<para>
You can use <emphasis>assertions</emphasis> to test whether arguments
satisfy certain constraints. The simple assertion <xref
linkend='ex-svn-nix-co-2'/> tests whether the
<varname>expat</varname> argument is not a null value. The more
complex assertion <xref linkend='ex-svn-nix-co-3'/> says that if
Subversion is built with Apache support, then <varname>httpd</varname>
(the Apache package) must not be null and it must have been built using
the same instance of the <varname>expat</varname> library as was passed
to the Subversion expression. This is since the Subversion code is
dynamically linked against the Apache code and they both use Expat,
they must be linked against the same instance&mdash;otherwise a
conflict might occur.
</para>
</sect2>
</sect1>
</chapter>

View File

@ -0,0 +1,229 @@
<chapter id='chap-package-management'><title>Package Management</title>
<para>Let's start from the perspective of an end user. Common
operations at this level are to install and remove packages, ask what
packages are installed or available for installation, and so on.
These are operations on the <emphasis>user environment</emphasis>: the
set of packages that a user <quote>sees</quote>. In a command line
Unix environment, this means the set of programs that are available
through the <envar>PATH</envar> environment variable. (In other
environments it might mean the set of programs available on the
desktop, through the start menu, and so on.)</para>
<para>The terms <quote>installation</quote> and
<quote>uninstallation</quote> are used in this context to denote the
act of adding or removing packages from the user environment. In Nix,
these operations are dissociated from the physical copying or deleting
of files. Installation requires that the files constituting the
package are present, but they may be present beforehand. Likewise,
uninstallation does not actually delete any files; this is done
automatically by running a garbage collector.</para>
<para>User environments are manipulated through the
<command>nix-env</command> command. The query operation can be used
to see what packages are currently installed.</para>
<screen>
$ nix-env -q
MozillaFirebird-0.7
sylpheed-0.9.7
pan-0.14.2</screen>
<para>(<option>-q</option> is actually short for <option>--query
--installed</option>.) The package names are symbolic: they don't
have any particular significance to Nix (as they shouldn't, since they
are not unique&mdash;there can be many derivations with the same
name). Note that these packages have many dependencies (e.g., Mozilla
uses the <literal>gtk+</literal> package) but these have not been
installed in the user environment, though they are present on the
system. Generally, there is no need to install such packages; only
packages containing programs should be installed.</para>
<para>To install packages, a <emphasis>Nix expression</emphasis> is
required that tells Nix how to build that package. There is a <ulink
url='https://svn.cs.uu.nl:12443/dist/trace/trace-nixpkgs-trunk.tar.bz2'>set
of standard of Nix expressions</ulink> for many common packages.
Assuming that you have downloaded and unpacked these, you can view the
set of available packages:</para>
<screen>
$ nix-env -qaf pkgs/system/i686-linux.nix
gettext-0.12.1
sylpheed-0.9.7
aterm-2.0
gtk+-1.2.10
apache-httpd-2.0.48
pan-0.14.2
...</screen>
<para>The Nix expression in the file
<filename>i686-linux.nix</filename> yields the set of packages for a
Linux system running on x86 hardware. For other platforms, copy and
modify this file for your platform as appropriate. [TODO: improve
this]</para>
<para>It is also possible to see the <emphasis>status</emphasis> of
available packages, i.e., whether they are installed into the user
environment and/or present in the system:</para>
<screen>
$ nix-env -qasf pkgs/system/i686-linux.nix
-P gettext-0.12.1
IP sylpheed-0.9.7
-- aterm-2.0
-P gtk+-1.2.10</screen>
<para>This reveals that the <literal>sylpheed</literal> package is
already installed, or more precisely, that exactly the same
instantiation of <literal>sylpheed</literal> is installed. This
guarantees that the available package is exactly the same as the
installed package with regard to sources, dependencies, build flags,
and so on. Similarly, we see that the <literal>gettext</literal> and
<literal>gtk+</literal> packages are present but not installed in the
user environment, while the <literal>aterm</literal> package is not
installed or present at all (so, if we were to install it, it would
have to be built or downloaded first).</para>
<para>The install operation is used install available packages from a
Nix environment. To install the <literal>pan</literal> package (a
newsreader), you would do:</para>
<screen>
$ nix-env -if pkgs/system/i686-linux.nix pan</screen>
<para>Since installation may take a long time, depending on whether
any packages need to be built or downloaded, it's a good idea to make
<command>nix-env</command> run verbosely by using the
<option>-v</option> (<option>--verbose</option>) option. This option
may be repeated to increase the level of verbosity. A good value is 3
(<option>-vvv</option>).</para>
<para>In fact, if you run this command verbosely you will observe that
Nix starts to build many packages, including large and fundamental
ones such as <literal>glibc</literal> and <literal>gcc</literal>.
I.e., you are performing a source installation. This is generally
undesirable, since installation from sources may require large amounts
of disk and CPU resources. Therefore a <quote>binary</quote>
installation is generally preferable.</para>
<para>Rather than provide different mechanisms to create and perform
the installation of binary packages, Nix supports binary deployment
<emphasis>transparently</emphasis> through a generic mechanism of
<emphasis>substitute expressions</emphasis>. If an request is made to
build some Nix expression, Nix will first try to build any substitutes
for that expression. These substitutes presumably perform an
identical build operation with respect to the result, but require less
resources. For instance, a substitute that downloads a pre-built
package from the network requires less CPU and disk resources, and
possibly less time.</para>
<para>Nix's use of cryptographic hashes makes this entirely safe. It
is not possible, for instance, to accidentally substitute a build of
some package for a Solaris or Windows system for a build on a SuSE/x86
system.</para>
<para>While the substitute mechanism is a generic mechanism, Nix
provides two standard tools called <command>nix-pull</command> and
<command>nix-push</command> that maintain and use a shared cache of
prebuilt derivations on some network site (reachable through HTTP).
If you attempt to install some package that someone else has
previously built and <quote>pushed</quote> into the cache, and you
have done a <quote>pull</quote> to register substitutes that download
these prebuilt packages, then the installation will automatically use
these.</para>
<para>For example, to pull from our <ulink
url='http://losser.st-lab.cs.uu.nl/~eelco/nix-dist/'>cache</ulink> of
prebuilt packages (at the time of writing, for SuSE Linux/x86), use
the following command:</para>
<screen>
$ nix-pull http://catamaran.labs.cs.uu.nl/dist/nix/nixpkgs-<replaceable>version</replaceable>/MANIFEST
obtaining list of Nix archives at http://catamaran.labs.cs.uu.nl/dist/nix/nixpkgs-<replaceable>version</replaceable>/MANIFEST...
...</screen>
<para>If <command>nix-pull</command> is run without any arguments, it
will pull from the URLs specified in the file
<filename><replaceable>prefix</replaceable>/etc/nix/prebuilts.conf</filename>.</para>
<para>Assuming that the <literal>pan</literal> installation produced
no errors, it can be used immediately, that is, it now appears in a
directory in the <envar>PATH</envar> environment variable.
Specifically, <envar>PATH</envar> includes the entry
<filename><replaceable>prefix</replaceable>/var/nix/profiles/default/bin</filename>,
where
<filename><replaceable>prefix</replaceable>/var/nix/profiles/default</filename>
is just a symlink to the current user environment:</para>
<screen>
$ ls -l /nix/var/nix/profiles/
...
lrwxrwxrwx 1 eelco ... default-15-link -> /nix/store/1871...12b0-user-environment
lrwxrwxrwx 1 eelco ... default-16-link -> /nix/store/59ba...df6b-user-environment
lrwxrwxrwx 1 eelco ... default -> default-16-link</screen>
<para>That is, <filename>default</filename> in this example is a link
to <filename>default-16-link</filename>, which is the current user
environment. Before the installation, it pointed to
<filename>default-15-link</filename>. Note that this means that you
can atomically roll-back to the previous user environment by pointing
the symlink <filename>default</filename> at
<filename>default-15-link</filename> again. This also shows that
operations such as installation are atomic in the Nix system: any
arbitrarily complex set of installation, uninstallation, or upgrade
actions eventually boil down to the single operation of pointing a
symlink somewhere else (which can be implemented atomically in Unix).</para>
<para>What's in a user environment? It's just a set of symlinks to the
files that constitute the installed packages. For instance:</para>
<screen>
$ ls -l /nix/var/nix/profiles/default-16-link/bin
lrwxrwxrwx 1 eelco ... MozillaFirebird -> /nix/store/35f8...4ae6-MozillaFirebird-0.7/bin/MozillaFirebird
lrwxrwxrwx 1 eelco ... svn -> /nix/store/3829...fb5d-subversion-0.32.1/bin/svn
...</screen>
<para>Note that, e.g., <filename>svn</filename> =
<filename>/nix/var/nix/profiles/default/bin/svn</filename> =
<filename>/nix/var/nix/profiles/default-16-link/bin/svn</filename> =
<filename>/nix/store/59ba...df6b-user-environment/bin/svn</filename> =
<filename>/nix/store/3829...fb5d-subversion-0.32.1/bin/svn</filename>.</para>
<para>Naturally, packages can also be uninstalled:</para>
<screen>
$ nix-env -e pan</screen>
<para>This means that the package is removed from the user
environment. It is <emphasis>not</emphasis> yet removed from the
system. When a package is uninstalled from a user environment, it may
still be used by other packages, or may still be present in other user
environments. Deleting it under such conditions would break those
other packages or user environments. To prevent this, packages are
only <quote>physically</quote> deleted by running the Nix garbage
collector, which searches for all packages in the Nix store that are
no longer <quote>reachable</quote> from outside the store. Thus,
uninstalling a package is always safe: it cannot break other
packages.</para>
<para>Upgrading packages is easy. Given a Nix expression that
contains newer versions of installed packages (that is, packages with
the same package name, but a higher version number), <command>nix-env
-u</command> will replace the installed package in the user
environment with the newer package. For example,
<screen>
$ nix-env -uf pkgs/system/i686-linux.nix pan</screen>
looks for a newer version of Pan, and installs it if found. Also
useful is the ability to upgrade <emphasis>all</emphasis> packages:
<screen>
$ nix-env -uf pkgs/system/i686-linux.nix '*'</screen>
The asterisk matches all installed packages<footnote><para>No, we
don't support arbitrary regular expressions</para></footnote>. Note
that <literal>*</literal> must be quoted to prevent shell
globbing.</para>
</chapter>

View File

@ -2,8 +2,7 @@
<para>This chapter is for impatient people who don't like reading <para>This chapter is for impatient people who don't like reading
documentation. For more in-depth information you are kindly referred documentation. For more in-depth information you are kindly referred
to <xref linkend='chap-installation' /> and <xref to the following chapters.</para>
linkend='chap-overview' />.</para>
<orderedlist> <orderedlist>

View File

@ -0,0 +1,148 @@
<chapter id='chap-writing-nix-expressions'><title>Writing Nix Expressions</title>
<sect1><title>A simple Nix expression</title>
<para>This section shows how to write simple Nix expressions&mdash;the
things that describe how to build a package.</para>
<example id='ex-hello-nix'><title>Nix expression for GNU Hello</title>
<programlisting>
{stdenv, fetchurl, perl}: <co id='ex-hello-nix-co-1' />
derivation { <co id='ex-hello-nix-co-2' />
name = "hello-2.1.1"; <co id='ex-hello-nix-co-3' />
system = stdenv.system; <co id='ex-hello-nix-co-4' />
builder = ./builder.sh; <co id='ex-hello-nix-co-5' />
src = fetchurl { <co id='ex-hello-nix-co-6' />
url = ftp://ftp.nluug.nl/pub/gnu/hello/hello-2.1.1.tar.gz;
md5 = "70c9ccf9fac07f762c24f2df2290784d";
};
stdenv = stdenv; <co id='ex-hello-nix-co-7' />
perl = perl;
}</programlisting>
</example>
<para>A simple Nix expression is shown in <xref linkend='ex-hello-nix'
/>. It describes how to the build the <ulink
url='http://www.gnu.org/directory/GNU/hello.html'>GNU Hello
package</ulink>. This package has several dependencies. First, it
requires a number of other packages, such as a C compiler, standard
Unix shell tools, and Perl. Rather than have this Nix expression
refer to and use specific versions of these packages, it should be
generic; that is, it should be a <emphasis>function</emphasis> that
takes the required packages as inputs and yield a build of the GNU
Hello package as a result. This Nix expression defines a function
with three arguments <xref linkend='ex-hello-nix-co-1' />, namely:
<orderedlist>
<listitem><para><varname>stdenv</varname>, which should be a
<emphasis>standard environment package</emphasis>. The standard
environment is a set of tools and other components that would be
expected in a fairly minimal Unix-like environment: a C compiler
and linker, Unix shell tools, and so on.</para></listitem>
<listitem><para><varname>fetchurl</varname>, which should be a
function that given parameters <varname>url</varname> and
<varname>md5</varname>, will fetch a file from the specified
location and check that this file has the given MD5 hash code.
The hash is required because build operations must be
<emphasis>pure</emphasis>: given the same inputs they should
always yield the same output. Since network resources can change
at any time, we must in some way guarantee what the result will
be.</para></listitem>
<listitem><para><varname>perl</varname>, which should be a Perl
interpreter.</para></listitem>
</orderedlist>
</para>
<para>The remainder of the file is the body of the function, which
happens to be a <emphasis>derivation</emphasis> <xref
linkend='ex-hello-nix-co-2' />, which is the built-in function
<varname>derivation</varname> applied to a set of attributes that
encode all the necessary information for building the GNU Hello
package.</para>
<example><title>Build script (<filename>builder.sh</filename>) for GNU
Hello</title>
<programlisting>
#! /bin/sh
buildinputs="$perl"
. $stdenv/setup || exit 1
tar xvfz $src || exit 1
cd hello-* || exit 1
./configure --prefix=$out || exit 1
make || exit 1
make install || exit 1</programlisting>
</example>
</sect1>
<sect1><title>A more complex Nix expression</title>
<example id='ex-svn-nix'><title>Nix expression for Subversion</title>
<programlisting>
{ localServer ? false <co id='ex-svn-nix-co-1' />
, httpServer ? false
, sslSupport ? false
, swigBindings ? false
, stdenv, fetchurl
, openssl ? null, httpd ? null, db4 ? null, expat, swig ? null
}:
assert !isNull expat; <co id='ex-svn-nix-co-2' />
assert localServer -> !isNull db4;
assert httpServer -> !isNull httpd &amp;&amp; httpd.expat == expat; <co id='ex-svn-nix-co-3' />
assert sslSupport -> !isNull openssl &amp;&amp; (httpServer -> httpd.openssl == openssl);
assert swigBindings -> !isNull swig;
derivation {
name = "subversion-0.32.1";
system = stdenv.system;
builder = ./builder.sh;
src = fetchurl {
url = http://svn.collab.net/tarballs/subversion-0.32.1.tar.gz;
md5 = "b06717a8ef50db4b5c4d380af00bd901";
};
localServer = localServer;
httpServer = httpServer;
sslSupport = sslSupport;
swigBindings = swigBindings;
stdenv = stdenv;
openssl = if sslSupport then openssl else null; <co id='ex-svn-nix-co-4' />
httpd = if httpServer then httpd else null;
expat = expat;
db4 = if localServer then db4 else null;
swig = if swigBindings then swig else null;
}</programlisting>
</example>
<para>This example shows several features. Default parameters <xref
linkend='ex-svn-nix-co-1'/> can be used to simplify call sites: if an
argument that has a default is omitted, its default value is
used.</para>
<para>You can use <emphasis>assertions</emphasis> to test whether
arguments satisfy certain constraints. The simple assertion <xref
linkend='ex-svn-nix-co-2'/> tests whether the <varname>expat</varname>
argument is not a null value. The more complex assertion <xref
linkend='ex-svn-nix-co-3'/> says that if Subversion is built with
Apache support, then <varname>httpd</varname> (the Apache package)
must not be null and it must have been built using the same instance
of the <varname>expat</varname> library as was passed to the
Subversion expression. This is since the Subversion code is
dynamically linked against the Apache code and they both use Expat,
they must be linked against the same instance&mdash;otherwise a
conflict might occur.</para>
</sect1>
</chapter>