diff options
author | Eelco Dolstra <edolstra@gmail.com> | 2021-09-15 20:33:44 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-09-15 20:33:44 +0200 |
commit | 79152e307e7eef667c3de9c21571d017654a7c32 (patch) | |
tree | 67fd413bcf0b42c5ada7eddc41a04f7bd99df3a8 /doc/manual/src/expressions | |
parent | 7349f257da8278af9aae35544b15c9a204e2a57b (diff) | |
parent | 3b82c1a5fef521ebadea5df12384390c8c24100c (diff) |
Merge pull request #5212 from mkenigs/auto-uid-allocation
Merge master into #3600
Diffstat (limited to 'doc/manual/src/expressions')
-rw-r--r-- | doc/manual/src/expressions/advanced-attributes.md | 257 | ||||
-rw-r--r-- | doc/manual/src/expressions/arguments-variables.md | 80 | ||||
-rw-r--r-- | doc/manual/src/expressions/build-script.md | 70 | ||||
-rw-r--r-- | doc/manual/src/expressions/builtin-constants.md | 20 | ||||
-rw-r--r-- | doc/manual/src/expressions/builtins-prefix.md | 16 | ||||
-rw-r--r-- | doc/manual/src/expressions/builtins-suffix.md | 1 | ||||
-rw-r--r-- | doc/manual/src/expressions/derivations.md | 161 | ||||
-rw-r--r-- | doc/manual/src/expressions/expression-language.md | 12 | ||||
-rw-r--r-- | doc/manual/src/expressions/expression-syntax.md | 93 | ||||
-rw-r--r-- | doc/manual/src/expressions/generic-builder.md | 66 | ||||
-rw-r--r-- | doc/manual/src/expressions/language-constructs.md | 350 | ||||
-rw-r--r-- | doc/manual/src/expressions/language-operators.md | 28 | ||||
-rw-r--r-- | doc/manual/src/expressions/language-values.md | 251 | ||||
-rw-r--r-- | doc/manual/src/expressions/simple-building-testing.md | 61 | ||||
-rw-r--r-- | doc/manual/src/expressions/simple-expression.md | 23 | ||||
-rw-r--r-- | doc/manual/src/expressions/writing-nix-expressions.md | 12 |
16 files changed, 1501 insertions, 0 deletions
diff --git a/doc/manual/src/expressions/advanced-attributes.md b/doc/manual/src/expressions/advanced-attributes.md new file mode 100644 index 000000000..5b208df67 --- /dev/null +++ b/doc/manual/src/expressions/advanced-attributes.md @@ -0,0 +1,257 @@ +# Advanced Attributes + +Derivations can declare some infrequently used optional attributes. + + - `allowedReferences`\ + The optional attribute `allowedReferences` specifies a list of legal + references (dependencies) of the output of the builder. For example, + + ```nix + allowedReferences = []; + ``` + + enforces that the output of a derivation cannot have any runtime + dependencies on its inputs. To allow an output to have a runtime + dependency on itself, use `"out"` as a list item. This is used in + NixOS to check that generated files such as initial ramdisks for + booting Linux don’t have accidental dependencies on other paths in + the Nix store. + + - `allowedRequisites`\ + This attribute is similar to `allowedReferences`, but it specifies + the legal requisites of the whole closure, so all the dependencies + recursively. For example, + + ```nix + allowedRequisites = [ foobar ]; + ``` + + enforces that the output of a derivation cannot have any other + runtime dependency than `foobar`, and in addition it enforces that + `foobar` itself doesn't introduce any other dependency itself. + + - `disallowedReferences`\ + The optional attribute `disallowedReferences` specifies a list of + illegal references (dependencies) of the output of the builder. For + example, + + ```nix + disallowedReferences = [ foo ]; + ``` + + enforces that the output of a derivation cannot have a direct + runtime dependencies on the derivation `foo`. + + - `disallowedRequisites`\ + This attribute is similar to `disallowedReferences`, but it + specifies illegal requisites for the whole closure, so all the + dependencies recursively. For example, + + ```nix + disallowedRequisites = [ foobar ]; + ``` + + enforces that the output of a derivation cannot have any runtime + dependency on `foobar` or any other derivation depending recursively + on `foobar`. + + - `exportReferencesGraph`\ + This attribute allows builders access to the references graph of + their inputs. The attribute is a list of inputs in the Nix store + whose references graph the builder needs to know. The value of + this attribute should be a list of pairs `[ name1 path1 name2 + path2 ... ]`. The references graph of each *pathN* will be stored + in a text file *nameN* in the temporary build directory. The text + files have the format used by `nix-store --register-validity` + (with the deriver fields left empty). For example, when the + following derivation is built: + + ```nix + derivation { + ... + exportReferencesGraph = [ "libfoo-graph" libfoo ]; + }; + ``` + + the references graph of `libfoo` is placed in the file + `libfoo-graph` in the temporary build directory. + + `exportReferencesGraph` is useful for builders that want to do + something with the closure of a store path. Examples include the + builders in NixOS that generate the initial ramdisk for booting + Linux (a `cpio` archive containing the closure of the boot script) + and the ISO-9660 image for the installation CD (which is populated + with a Nix store containing the closure of a bootable NixOS + configuration). + + - `impureEnvVars`\ + This attribute allows you to specify a list of environment variables + that should be passed from the environment of the calling user to + the builder. Usually, the environment is cleared completely when the + builder is executed, but with this attribute you can allow specific + environment variables to be passed unmodified. For example, + `fetchurl` in Nixpkgs has the line + + ```nix + impureEnvVars = [ "http_proxy" "https_proxy" ... ]; + ``` + + to make it use the proxy server configuration specified by the user + in the environment variables `http_proxy` and friends. + + This attribute is only allowed in *fixed-output derivations* (see + below), where impurities such as these are okay since (the hash + of) the output is known in advance. It is ignored for all other + derivations. + + > **Warning** + > + > `impureEnvVars` implementation takes environment variables from + > the current builder process. When a daemon is building its + > environmental variables are used. Without the daemon, the + > environmental variables come from the environment of the + > `nix-build`. + + - `outputHash`; `outputHashAlgo`; `outputHashMode`\ + These attributes declare that the derivation is a so-called + *fixed-output derivation*, which means that a cryptographic hash of + the output is already known in advance. When the build of a + fixed-output derivation finishes, Nix computes the cryptographic + hash of the output and compares it to the hash declared with these + attributes. If there is a mismatch, the build fails. + + The rationale for fixed-output derivations is derivations such as + those produced by the `fetchurl` function. This function downloads a + file from a given URL. To ensure that the downloaded file has not + been modified, the caller must also specify a cryptographic hash of + the file. For example, + + ```nix + fetchurl { + url = "http://ftp.gnu.org/pub/gnu/hello/hello-2.1.1.tar.gz"; + sha256 = "1md7jsfd8pa45z73bz1kszpp01yw6x5ljkjk2hx7wl800any6465"; + } + ``` + + It sometimes happens that the URL of the file changes, e.g., because + servers are reorganised or no longer available. We then must update + the call to `fetchurl`, e.g., + + ```nix + fetchurl { + url = "ftp://ftp.nluug.nl/pub/gnu/hello/hello-2.1.1.tar.gz"; + sha256 = "1md7jsfd8pa45z73bz1kszpp01yw6x5ljkjk2hx7wl800any6465"; + } + ``` + + If a `fetchurl` derivation was treated like a normal derivation, the + output paths of the derivation and *all derivations depending on it* + would change. For instance, if we were to change the URL of the + Glibc source distribution in Nixpkgs (a package on which almost all + other packages depend) massive rebuilds would be needed. This is + unfortunate for a change which we know cannot have a real effect as + it propagates upwards through the dependency graph. + + For fixed-output derivations, on the other hand, the name of the + output path only depends on the `outputHash*` and `name` attributes, + while all other attributes are ignored for the purpose of computing + the output path. (The `name` attribute is included because it is + part of the path.) + + As an example, here is the (simplified) Nix expression for + `fetchurl`: + + ```nix + { stdenv, curl }: # The curl program is used for downloading. + + { url, sha256 }: + + stdenv.mkDerivation { + name = baseNameOf (toString url); + builder = ./builder.sh; + buildInputs = [ curl ]; + + # This is a fixed-output derivation; the output must be a regular + # file with SHA256 hash sha256. + outputHashMode = "flat"; + outputHashAlgo = "sha256"; + outputHash = sha256; + + inherit url; + } + ``` + + The `outputHashAlgo` attribute specifies the hash algorithm used to + compute the hash. It can currently be `"sha1"`, `"sha256"` or + `"sha512"`. + + The `outputHashMode` attribute determines how the hash is computed. + It must be one of the following two values: + + - `"flat"`\ + The output must be a non-executable regular file. If it isn’t, + the build fails. The hash is simply computed over the contents + of that file (so it’s equal to what Unix commands like + `sha256sum` or `sha1sum` produce). + + This is the default. + + - `"recursive"`\ + The hash is computed over the NAR archive dump of the output + (i.e., the result of [`nix-store + --dump`](../command-ref/nix-store.md#operation---dump)). In + this case, the output can be anything, including a directory + tree. + + The `outputHash` attribute, finally, must be a string containing + the hash in either hexadecimal or base-32 notation. (See the + [`nix-hash` command](../command-ref/nix-hash.md) for information + about converting to and from base-32 notation.) + + - `__contentAddressed` + If this **experimental** attribute is set to true, then the derivation + outputs will be stored in a content-addressed location rather than the + traditional input-addressed one. + This only has an effect if the `ca-derivation` experimental feature is enabled. + + Setting this attribute also requires setting `outputHashMode` and `outputHashAlgo` like for *fixed-output derivations* (see above). + + - `passAsFile`\ + A list of names of attributes that should be passed via files rather + than environment variables. For example, if you have + + ```nix + passAsFile = ["big"]; + big = "a very long string"; + ``` + + then when the builder runs, the environment variable `bigPath` + will contain the absolute path to a temporary file containing `a + very long string`. That is, for any attribute *x* listed in + `passAsFile`, Nix will pass an environment variable `xPath` + holding the path of the file containing the value of attribute + *x*. This is useful when you need to pass large strings to a + builder, since most operating systems impose a limit on the size + of the environment (typically, a few hundred kilobyte). + + - `preferLocalBuild`\ + If this attribute is set to `true` and [distributed building is + enabled](../advanced-topics/distributed-builds.md), then, if + possible, the derivaton will be built locally instead of forwarded + to a remote machine. This is appropriate for trivial builders + where the cost of doing a download or remote build would exceed + the cost of building locally. + + - `allowSubstitutes`\ + If this attribute is set to `false`, then Nix will always build this + derivation; it will not try to substitute its outputs. This is + useful for very trivial derivations (such as `writeText` in Nixpkgs) + that are cheaper to build than to substitute from a binary cache. + + > **Note** + > + > You need to have a builder configured which satisfies the + > derivation’s `system` attribute, since the derivation cannot be + > substituted. Thus it is usually a good idea to align `system` with + > `builtins.currentSystem` when setting `allowSubstitutes` to + > `false`. For most trivial derivations this should be the case. diff --git a/doc/manual/src/expressions/arguments-variables.md b/doc/manual/src/expressions/arguments-variables.md new file mode 100644 index 000000000..12198c879 --- /dev/null +++ b/doc/manual/src/expressions/arguments-variables.md @@ -0,0 +1,80 @@ +# Arguments and Variables + +The [Nix expression for GNU Hello](expression-syntax.md) 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 +`pkgs/top-level/all-packages.nix`, where all Nix expressions for +packages are imported and called with the appropriate arguments. Here +are some fragments of `all-packages.nix`, with annotations of what +they mean: + +```nix +... + +rec { ① + + hello = import ../applications/misc/hello/ex-1 ② { ③ + inherit fetchurl stdenv perl; + }; + + perl = import ../development/interpreters/perl { ④ + inherit fetchurl stdenv; + }; + + fetchurl = import ../build-support/fetchurl { + inherit stdenv; ... + }; + + stdenv = ...; + +} +``` + +1. This file defines a set of attributes, all of which are concrete + derivations (i.e., not functions). In fact, we define a *mutually + recursive* set of attributes. That is, the attributes can refer to + each other. This is precisely what we want since we want to “plug” + the various packages into each other. + +2. Here we *import* 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 the Nix expression + for GNU Hello in `all-packages.nix` at this point. That would be + completely equivalent, but it would make `all-packages.nix` rather + bulky. + + Note that we refer to `../applications/misc/hello/ex-1`, not + `../applications/misc/hello/ex-1/default.nix`. When you try to + import a directory, Nix automatically appends `/default.nix` to the + file name. + +3. This is where the actual composition takes place. Here we *call* the + function imported from `../applications/misc/hello/ex-1` with a set + containing the things that the function expects, namely `fetchurl`, + `stdenv`, and `perl`. We use inherit again to use the attributes + defined in the surrounding scope (we could also have written + `fetchurl = fetchurl;`, etc.). + + 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 `stdenv.mkDerivation` + in the [Nix expression for GNU Hello](expression-syntax.md)). + + > **Note** + > + > Nixpkgs has a convenience function `callPackage` that imports and + > calls a function, filling in any missing arguments by passing the + > corresponding attribute from the Nixpkgs set, like this: + > + > ```nix + > hello = callPackage ../applications/misc/hello/ex-1 { }; + > ``` + > + > If necessary, you can set or override arguments: + > + > ```nix + > hello = callPackage ../applications/misc/hello/ex-1 { stdenv = myStdenv; }; + > ``` + +4. Likewise, we have to instantiate Perl, `fetchurl`, and the standard + environment. diff --git a/doc/manual/src/expressions/build-script.md b/doc/manual/src/expressions/build-script.md new file mode 100644 index 000000000..b1eacae88 --- /dev/null +++ b/doc/manual/src/expressions/build-script.md @@ -0,0 +1,70 @@ +# Build Script + +Here is the builder referenced from Hello's Nix expression (stored in +`pkgs/applications/misc/hello/ex-1/builder.sh`): + +```bash +source $stdenv/setup ① + +PATH=$perl/bin:$PATH ② + +tar xvfz $src ③ +cd hello-* +./configure --prefix=$out ④ +make ⑤ +make install +``` + +The builder can actually be made a lot shorter by using the *generic +builder* functions provided by `stdenv`, but here we write out the build +steps to elucidate what a builder does. It performs the following steps: + +1. When Nix runs a builder, it initially completely clears the + environment (except for the attributes declared in the derivation). + This is done to prevent undeclared inputs from being used in the + build process. If for example the `PATH` contained `/usr/bin`, then + you might accidentally use `/usr/bin/gcc`. + + So the first step is to set up the environment. This is done by + calling the `setup` script of the standard environment. The + environment variable `stdenv` points to the location of the + standard environment being used. (It wasn't specified explicitly + as an attribute in Hello's Nix expression, but `mkDerivation` adds + it automatically.) + +2. Since Hello needs Perl, we have to make sure that Perl is in the + `PATH`. The `perl` environment variable points to the location of + the Perl package (since it was passed in as an attribute to the + derivation), so `$perl/bin` is the directory containing the Perl + interpreter. + +3. Now we have to unpack the sources. The `src` attribute was bound to + the result of fetching the Hello source tarball from the network, so + the `src` environment variable points to the location in the Nix + store to which the tarball was downloaded. After unpacking, we `cd` + to the resulting source directory. + + The whole build is performed in a temporary directory created in + `/tmp`, 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. + +4. GNU Hello is a typical Autoconf-based package, so we first have to + run its `configure` script. In Nix every package is stored in a + separate location in the Nix store, for instance + `/nix/store/9a54ba97fb71b65fda531012d0443ce2-hello-2.1.1`. Nix + computes this path by cryptographically hashing all attributes of + the derivation. The path is passed to the builder through the `out` + environment variable. So here we give `configure` the parameter + `--prefix=$out` to cause Hello to be installed in the expected + location. + +5. Finally we build Hello (`make`) and install it into the location + specified by `out` (`make install`). + +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 `-e` option, which causes the script to +be aborted if any command fails without an error check. diff --git a/doc/manual/src/expressions/builtin-constants.md b/doc/manual/src/expressions/builtin-constants.md new file mode 100644 index 000000000..1404289e5 --- /dev/null +++ b/doc/manual/src/expressions/builtin-constants.md @@ -0,0 +1,20 @@ +# Built-in Constants + +Here are the constants built into the Nix expression evaluator: + + - `builtins`\ + The set `builtins` contains all the built-in functions and values. + You can use `builtins` to test for the availability of features in + the Nix installation, e.g., + + ```nix + if builtins ? getEnv then builtins.getEnv "PATH" else "" + ``` + + This allows a Nix expression to fall back gracefully on older Nix + installations that don’t have the desired built-in function. + + - `builtins.currentSystem`\ + The built-in value `currentSystem` evaluates to the Nix platform + identifier for the Nix installation on which the expression is being + evaluated, such as `"i686-linux"` or `"x86_64-darwin"`. diff --git a/doc/manual/src/expressions/builtins-prefix.md b/doc/manual/src/expressions/builtins-prefix.md new file mode 100644 index 000000000..87127de2a --- /dev/null +++ b/doc/manual/src/expressions/builtins-prefix.md @@ -0,0 +1,16 @@ +# Built-in Functions + +This section lists the functions built into the Nix expression +evaluator. (The built-in function `derivation` is discussed above.) +Some built-ins, such as `derivation`, are always in scope of every Nix +expression; you can just access them right away. But to prevent +polluting the namespace too much, most built-ins are not in +scope. Instead, you can access them through the `builtins` built-in +value, which is a set that contains all built-in functions and values. +For instance, `derivation` is also available as `builtins.derivation`. + +<dl> + <dt><code>derivation <var>attrs</var></code>; + <code>builtins.derivation <var>attrs</var></code></dt> + <dd><p><var>derivation</var> in described in + <a href="derivations.md">its own section</a>.</p></dd> diff --git a/doc/manual/src/expressions/builtins-suffix.md b/doc/manual/src/expressions/builtins-suffix.md new file mode 100644 index 000000000..a74db2857 --- /dev/null +++ b/doc/manual/src/expressions/builtins-suffix.md @@ -0,0 +1 @@ +</dl> diff --git a/doc/manual/src/expressions/derivations.md b/doc/manual/src/expressions/derivations.md new file mode 100644 index 000000000..d26a33b7f --- /dev/null +++ b/doc/manual/src/expressions/derivations.md @@ -0,0 +1,161 @@ +# Derivations + +The most important built-in function is `derivation`, which is used to +describe a single derivation (a build action). It takes as input a set, +the attributes of which specify the inputs of the build. + + - There must be an attribute named `system` whose value must be a + string specifying a Nix system type, such as `"i686-linux"` or + `"x86_64-darwin"`. (To figure out your system type, run `nix -vv + --version`.) The build can only be performed on a machine and + operating system matching the system type. (Nix can automatically + [forward builds for other + platforms](../advanced-topics/distributed-builds.md) by forwarding + them to other machines.) + + - There must be an attribute named `name` whose value must be a + string. This is used as a symbolic name for the package by + `nix-env`, and it is appended to the output paths of the derivation. + + - There must be an attribute named `builder` that identifies the + program that is executed to perform the build. It can be either a + derivation or a source (a local file reference, e.g., + `./builder.sh`). + + - Every attribute is passed as an environment variable to the builder. + Attribute values are translated to environment variables as follows: + + - Strings and numbers are just passed verbatim. + + - A *path* (e.g., `../foo/sources.tar`) causes the referenced file + to be copied to the store; its location in the store is put in + the environment variable. The idea is that all sources should + reside in the Nix store, since all inputs to a derivation should + reside in the Nix store. + + - A *derivation* causes that derivation to be built prior to the + present derivation; its default output path is put in the + environment variable. + + - Lists of the previous types are also allowed. They are simply + concatenated, separated by spaces. + + - `true` is passed as the string `1`, `false` and `null` are + passed as an empty string. + + - The optional attribute `args` specifies command-line arguments to be + passed to the builder. It should be a list. + + - The optional attribute `outputs` specifies a list of symbolic + outputs of the derivation. By default, a derivation produces a + single output path, denoted as `out`. However, derivations can + produce multiple output paths. This is useful because it allows + outputs to be downloaded or garbage-collected separately. For + instance, imagine a library package that provides a dynamic library, + header files, and documentation. A program that links against the + library doesn’t need the header files and documentation at runtime, + and it doesn’t need the documentation at build time. Thus, the + library package could specify: + + ```nix + outputs = [ "lib" "headers" "doc" ]; + ``` + + This will cause Nix to pass environment variables `lib`, `headers` + and `doc` to the builder containing the intended store paths of each + output. The builder would typically do something like + + ```bash + ./configure \ + --libdir=$lib/lib \ + --includedir=$headers/include \ + --docdir=$doc/share/doc + ``` + + for an Autoconf-style package. You can refer to each output of a + derivation by selecting it as an attribute, e.g. + + ```nix + buildInputs = [ pkg.lib pkg.headers ]; + ``` + + The first element of `outputs` determines the *default output*. + Thus, you could also write + + ```nix + buildInputs = [ pkg pkg.headers ]; + ``` + + since `pkg` is equivalent to `pkg.lib`. + +The function `mkDerivation` in the Nixpkgs standard environment is a +wrapper around `derivation` that adds a default value for `system` and +always uses Bash as the builder, to which the supplied builder is passed +as a command-line argument. See the Nixpkgs manual for details. + +The builder is executed as follows: + + - A temporary directory is created under the directory specified by + `TMPDIR` (default `/tmp`) where the build will take place. The + current directory is changed to this directory. + + - The environment is cleared and set to the derivation attributes, as + specified above. + + - In addition, the following variables are set: + + - `NIX_BUILD_TOP` contains the path of the temporary directory for + this build. + + - Also, `TMPDIR`, `TEMPDIR`, `TMP`, `TEMP` are set to point to the + temporary directory. This is to prevent the builder from + accidentally writing temporary files anywhere else. Doing so + might cause interference by other processes. + + - `PATH` is set to `/path-not-set` to prevent shells from + initialising it to their built-in default value. + + - `HOME` is set to `/homeless-shelter` to prevent programs from + using `/etc/passwd` or the like to find the user's home + directory, which could cause impurity. Usually, when `HOME` is + set, it is used as the location of the home directory, even if + it points to a non-existent path. + + - `NIX_STORE` is set to the path of the top-level Nix store + directory (typically, `/nix/store`). + + - For each output declared in `outputs`, the corresponding + environment variable is set to point to the intended path in the + Nix store for that output. Each output path is a concatenation + of the cryptographic hash of all build inputs, the `name` + attribute and the output name. (The output name is omitted if + it’s `out`.) + + - If an output path already exists, it is removed. Also, locks are + acquired to prevent multiple Nix instances from performing the same + build at the same time. + + - A log of the combined standard output and error is written to + `/nix/var/log/nix`. + + - The builder is executed with the arguments specified by the + attribute `args`. If it exits with exit code 0, it is considered to + have succeeded. + + - The temporary directory is removed (unless the `-K` option was + specified). + + - If the build was successful, Nix scans each output path for + references to input paths by looking for the hash parts of the input + paths. Since these are potential runtime dependencies, Nix registers + them as dependencies of the output paths. + + - After the build, Nix sets the last-modified timestamp on all files + in the build result to 1 (00:00:01 1/1/1970 UTC), sets the group to + the default group, and sets the mode of the file to 0444 or 0555 + (i.e., read-only, with execute permission enabled if the file was + originally executable). Note that possible `setuid` and `setgid` + bits are cleared. Setuid and setgid programs are not currently + supported by Nix. This is because the Nix archives used in + deployment have no concept of ownership information, and because it + makes the build result dependent on the user performing the build. diff --git a/doc/manual/src/expressions/expression-language.md b/doc/manual/src/expressions/expression-language.md new file mode 100644 index 000000000..267fcb983 --- /dev/null +++ b/doc/manual/src/expressions/expression-language.md @@ -0,0 +1,12 @@ +# Nix Expression Language + +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 “normal” values that can be passed +around and manipulated in interesting ways. The language is not a +full-featured, general purpose language. Its main job is to describe +packages, compositions of packages, and the variability within packages. + +This section presents the various features of the language. diff --git a/doc/manual/src/expressions/expression-syntax.md b/doc/manual/src/expressions/expression-syntax.md new file mode 100644 index 000000000..2a1306e32 --- /dev/null +++ b/doc/manual/src/expressions/expression-syntax.md @@ -0,0 +1,93 @@ +# Expression Syntax + +Here is a Nix expression for GNU Hello: + +```nix +{ 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"; + sha256 = "1md7jsfd8pa45z73bz1kszpp01yw6x5ljkjk2hx7wl800any6465"; + }; + inherit perl; ⑥ +} +``` + +This file is 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): + +1. 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 package that + is used by almost all Nix Packages packages; 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. `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 package. + +2. So we have to build a package. 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 package from a set of + *attributes*. A set is just a list of key/value pairs where each + key is a string and each value is an arbitrary Nix + expression. They take the general form `{ name1 = expr1; ... + nameN = exprN; }`. + +3. The attribute `name` specifies the symbolic name and version of + the package. 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 packages. This attribute is required by `mkDerivation`. + +4. 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 the [next section](build-script.md), + discussed below. + +5. The builder has to know what the sources of the package are. Here, + the attribute `src` is bound to the result of a call to the + `fetchurl` function. Given a URL and a SHA-256 hash of the expected + contents of the file at that URL, this function 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). + +6. 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 + + ```nix + perl = perl; + ``` + + will do the trick: 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. diff --git a/doc/manual/src/expressions/generic-builder.md b/doc/manual/src/expressions/generic-builder.md new file mode 100644 index 000000000..cf26b5f82 --- /dev/null +++ b/doc/manual/src/expressions/generic-builder.md @@ -0,0 +1,66 @@ +# Generic Builder Syntax + +Recall that the [build script for GNU Hello](build-script.md) looked +something like this: + +```bash +PATH=$perl/bin:$PATH +tar xvfz $src +cd hello-* +./configure --prefix=$out +make +make install +``` + +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. Here is what a builder using +the generic build facilities looks like: + +```bash +buildInputs="$perl" ① + +source $stdenv/setup ② + +genericBuild ③ +``` + +Here is what each line means: + +1. The `buildInputs` variable tells `setup` to use the indicated + packages as “inputs”. This means that if a package provides a `bin` + subdirectory, it's added to `PATH`; if it has a `include` + subdirectory, it's added to GCC's header search path; and so on. + (This is implemented in a modular way: `setup` tries to source the + file `pkg/nix-support/setup-hook` of all dependencies. These “setup + hooks” can then set up whatever environment variables they want; for + instance, the setup hook for Perl sets the `PERL5LIB` environment + variable to contain the `lib/site_perl` directories of all inputs.) + +2. The function `genericBuild` is defined in the file `$stdenv/setup`. + +3. The final step calls the shell function `genericBuild`, which + performs the steps that were done explicitly in the previous build + script. The generic builder is smart enough to figure out whether + to unpack the sources using `gzip`, `bzip2`, etc. It can be + customised in many ways; see the Nixpkgs manual for details. + +Discerning readers will note that the `buildInputs` could just as well +have been set in the Nix expression, like this: + +```nix + buildInputs = [ perl ]; +``` + +The `perl` attribute can then be removed, and the builder becomes even +shorter: + +```bash +source $stdenv/setup +genericBuild +``` + +In fact, `mkDerivation` provides a default builder that looks exactly +like that, so it is actually possible to omit the builder for Hello +entirely. diff --git a/doc/manual/src/expressions/language-constructs.md b/doc/manual/src/expressions/language-constructs.md new file mode 100644 index 000000000..cb0169239 --- /dev/null +++ b/doc/manual/src/expressions/language-constructs.md @@ -0,0 +1,350 @@ +# Language Constructs + +## Recursive sets + +Recursive sets are just normal sets, but the attributes can refer to +each other. For example, + +```nix +rec { + x = y; + y = 123; +}.x +``` + +evaluates to `123`. Note that without `rec` the binding `x = y;` would +refer to the variable `y` in the surrounding scope, if one exists, and +would be invalid if no such variable exists. That is, in a normal +(non-recursive) set, attributes are not added to the lexical scope; in a +recursive set, they are. + +Recursive sets of course introduce the danger of infinite recursion. For +example, the expression + +```nix +rec { + x = y; + y = x; +}.x +``` + +will crash with an `infinite recursion encountered` error message. + +## Let-expressions + +A let-expression allows you to define local variables for an expression. +For instance, + +```nix +let + x = "foo"; + y = "bar"; +in x + y +``` + +evaluates to `"foobar"`. + +## Inheriting attributes + +When defining a set or in a let-expression it is often convenient to +copy variables from the surrounding lexical scope (e.g., when you want +to propagate attributes). This can be shortened using the `inherit` +keyword. For instance, + +```nix +let x = 123; in +{ inherit x; + y = 456; +} +``` + +is equivalent to + +```nix +let x = 123; in +{ x = x; + y = 456; +} +``` + +and both evaluate to `{ x = 123; y = 456; }`. (Note that this works +because `x` is added to the lexical scope by the `let` construct.) It is +also possible to inherit attributes from another set. For instance, in +this fragment from `all-packages.nix`, + +```nix +graphviz = (import ../tools/graphics/graphviz) { + inherit fetchurl stdenv libpng libjpeg expat x11 yacc; + inherit (xlibs) libXaw; +}; + +xlibs = { + libX11 = ...; + libXaw = ...; + ... +} + +libpng = ...; +libjpg = ...; +... +``` + +the set used in the function call to the function defined in +`../tools/graphics/graphviz` inherits a number of variables from the +surrounding scope (`fetchurl` ... `yacc`), but also inherits `libXaw` +(the X Athena Widgets) from the `xlibs` (X11 client-side libraries) set. + +Summarizing the fragment + +```nix +... +inherit x y z; +inherit (src-set) a b c; +... +``` + +is equivalent to + +```nix +... +x = x; y = y; z = z; +a = src-set.a; b = src-set.b; c = src-set.c; +... +``` + +when used while defining local variables in a let-expression or while +defining a set. + +## Functions + +Functions have the following form: + +```nix +pattern: body +``` + +The pattern specifies what the argument of the function must look like, +and binds variables in the body to (parts of) the argument. There are +three kinds of patterns: + + - If a pattern is a single identifier, then the function matches any + argument. Example: + + ```nix + let negate = x: !x; + concat = x: y: x + y; + in if negate true then concat "foo" "bar" else "" + ``` + + Note that `concat` is a function that takes one argument and returns + a function that takes another argument. This allows partial + parameterisation (i.e., only filling some of the arguments of a + function); e.g., + + ```nix + map (concat "foo") [ "bar" "bla" "abc" ] + ``` + + evaluates to `[ "foobar" "foobla" "fooabc" ]`. + + - A *set pattern* of the form `{ name1, name2, …, nameN }` matches a + set containing the listed attributes, and binds the values of those + attributes to variables in the function body. For example, the + function + + ```nix + { x, y, z }: z + y + x + ``` + + can only be called with a set containing exactly the attributes `x`, + `y` and `z`. No other attributes are allowed. If you want to allow + additional arguments, you can use an ellipsis (`...`): + + ```nix + { x, y, z, ... }: z + y + x + ``` + + This works on any set that contains at least the three named + attributes. + + It is possible to provide *default values* for attributes, in + which case they are allowed to be missing. A default value is + specified by writing `name ? e`, where *e* is an arbitrary + expression. For example, + + ```nix + { x, y ? "foo", z ? "bar" }: z + y + x + ``` + + specifies a function that only requires an attribute named `x`, but + optionally accepts `y` and `z`. + + - An `@`-pattern provides a means of referring to the whole value + being matched: + + ```nix + args@{ x, y, z, ... }: z + y + x + args.a + ``` + + but can also be written as: + + ```nix + { x, y, z, ... } @ args: z + y + x + args.a + ``` + + Here `args` is bound to the entire argument, which is further + matched against the pattern `{ x, y, z, + ... }`. `@`-pattern makes mainly sense with an ellipsis(`...`) as + you can access attribute names as `a`, using `args.a`, which was + given as an additional attribute to the function. + + > **Warning** + > + > The `args@` expression is bound to the argument passed to the + > function which means that attributes with defaults that aren't + > explicitly specified in the function call won't cause an + > evaluation error, but won't exist in `args`. + > + > For instance + > + > ```nix + > let + > function = args@{ a ? 23, ... }: args; + > in + > function {} + > ```` + > + > will evaluate to an empty attribute set. + +Note that functions do not have names. If you want to give them a name, +you can bind them to an attribute, e.g., + +```nix +let concat = { x, y }: x + y; +in concat { x = "foo"; y = "bar"; } +``` + +## Conditionals + +Conditionals look like this: + +```nix +if e1 then e2 else e3 +``` + +where *e1* is an expression that should evaluate to a Boolean value +(`true` or `false`). + +## Assertions + +Assertions are generally used to check that certain requirements on or +between features and dependencies hold. They look like this: + +```nix +assert e1; e2 +``` + +where *e1* is an expression that should evaluate to a Boolean value. If +it evaluates to `true`, *e2* is returned; otherwise expression +evaluation is aborted and a backtrace is printed. + +Here is a Nix expression for the Subversion package that shows how +assertions can be used:. + +```nix +{ localServer ? false +, httpServer ? false +, sslSupport ? false +, pythonBindings ? false +, javaSwigBindings ? false +, javahlBindings ? false +, stdenv, fetchurl +, openssl ? null, httpd ? null, db4 ? null, expat, swig ? null, j2sdk ? null +}: + +assert localServer -> db4 != null; ① +assert httpServer -> httpd != null && httpd.expat == expat; ② +assert sslSupport -> openssl != null && (httpServer -> httpd.openssl == openssl); ③ +assert pythonBindings -> swig != null && swig.pythonSupport; +assert javaSwigBindings -> swig != null && swig.javaSupport; +assert javahlBindings -> j2sdk != null; + +stdenv.mkDerivation { + name = "subversion-1.1.1"; + ... + openssl = if sslSupport then openssl else null; ④ + ... +} +``` + +The points of interest are: + +1. This assertion states that if Subversion is to have support for + local repositories, then Berkeley DB is needed. So if the Subversion + function is called with the `localServer` argument set to `true` but + the `db4` argument set to `null`, then the evaluation fails. + +2. This is a more subtle condition: if Subversion is built with Apache + (`httpServer`) support, then the Expat library (an XML library) used + by Subversion should be same as the one used by Apache. This is + because in this configuration Subversion code ends up being linked + with Apache code, and if the Expat libraries do not match, a build- + or runtime link error or incompatibility might occur. + +3. This assertion says that in order for Subversion to have SSL support + (so that it can access `https` URLs), an OpenSSL library must be + passed. Additionally, it says that *if* Apache support is enabled, + then Apache's OpenSSL should match Subversion's. (Note that if + Apache support is not enabled, we don't care about Apache's + OpenSSL.) + +4. The conditional here is not really related to assertions, but is + worth pointing out: it ensures that if SSL support is disabled, then + the Subversion derivation is not dependent on OpenSSL, even if a + non-`null` value was passed. This prevents an unnecessary rebuild of + Subversion if OpenSSL changes. + +## With-expressions + +A *with-expression*, + +```nix +with e1; e2 +``` + +introduces the set *e1* into the lexical scope of the expression *e2*. +For instance, + +```nix +let as = { x = "foo"; y = "bar"; }; +in with as; x + y +``` + +evaluates to `"foobar"` since the `with` adds the `x` and `y` attributes +of `as` to the lexical scope in the expression `x + y`. The most common +use of `with` is in conjunction with the `import` function. E.g., + +```nix +with (import ./definitions.nix); ... +``` + +makes all attributes defined in the file `definitions.nix` available as +if they were defined locally in a `let`-expression. + +The bindings introduced by `with` do not shadow bindings introduced by +other means, e.g. + +```nix +let a = 3; in with { a = 1; }; let a = 4; in with { a = 2; }; ... +``` + +establishes the same scope as + +```nix +let a = 1; in let a = 2; in let a = 3; in let a = 4; in ... +``` + +## Comments + +Comments can be single-line, started with a `#` character, or +inline/multi-line, enclosed within `/* ... */`. diff --git a/doc/manual/src/expressions/language-operators.md b/doc/manual/src/expressions/language-operators.md new file mode 100644 index 000000000..b7fd6f4c6 --- /dev/null +++ b/doc/manual/src/expressions/language-operators.md @@ -0,0 +1,28 @@ +# Operators + +The table below lists the operators in the Nix expression language, in +order of precedence (from strongest to weakest binding). + +| Name | Syntax | Associativity | Description | Precedence | +| ------------------------ | ----------------------------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | +| Select | *e* `.` *attrpath* \[ `or` *def* \] | none | Select attribute denoted by the attribute path *attrpath* from set *e*. (An attribute path is a dot-separated list of attribute names.) If the attribute doesn’t exist, return *def* if provided, otherwise abort evaluation. | 1 | +| Application | *e1* *e2* | left | Call function *e1* with argument *e2*. | 2 | +| Arithmetic Negation | `-` *e* | none | Arithmetic negation. | 3 | +| Has Attribute | *e* `?` *attrpath* | none | Test whether set *e* contains the attribute denoted by *attrpath*; return `true` or `false`. | 4 | +| List Concatenation | *e1* `++` *e2* | right | List concatenation. | 5 | +| Multiplication | *e1* `*` *e2*, | left | Arithmetic multiplication. | 6 | +| Division | *e1* `/` *e2* | left | Arithmetic division. | 6 | +| Addition | *e1* `+` *e2* | left | Arithmetic addition. | 7 | +| Subtraction | *e1* `-` *e2* | left | Arithmetic subtraction. | 7 | +| String Concatenation | *string1* `+` *string2* | left | String concatenation. | 7 | +| Not | `!` *e* | none | Boolean negation. | 8 | +| Update | *e1* `//` *e2* | right | Return a set consisting of the attributes in *e1* and *e2* (with the latter taking precedence over the former in case of equally named attributes). | 9 | +| Less Than | *e1* `<` *e2*, | none | Arithmetic comparison. | 10 | +| Less Than or Equal To | *e1* `<=` *e2* | none | Arithmetic comparison. | 10 | +| Greater Than | *e1* `>` *e2* | none | Arithmetic comparison. | 10 | +| Greater Than or Equal To | *e1* `>=` *e2* | none | Arithmetic comparison. | 10 | +| Equality | *e1* `==` *e2* | none | Equality. | 11 | +| Inequality | *e1* `!=` *e2* | none | Inequality. | 11 | +| Logical AND | *e1* `&&` *e2* | left | Logical AND. | 12 | +| Logical OR | *e1* `\|\|` *e2* | left | Logical OR. | 13 | +| Logical Implication | *e1* `->` *e2* | none | Logical implication (equivalent to `!e1 \|\| e2`). | 14 | diff --git a/doc/manual/src/expressions/language-values.md b/doc/manual/src/expressions/language-values.md new file mode 100644 index 000000000..28fa23b58 --- /dev/null +++ b/doc/manual/src/expressions/language-values.md @@ -0,0 +1,251 @@ +# Values + +## Simple Values + +Nix has the following basic data types: + + - *Strings* can be written in three ways. + + The most common way is to enclose the string between double quotes, + e.g., `"foo bar"`. Strings can span multiple lines. The special + characters `"` and `\` and the character sequence `${` must be + escaped by prefixing them with a backslash (`\`). Newlines, carriage + returns and tabs can be written as `\n`, `\r` and `\t`, + respectively. + + You can include the result of an expression into a string by + enclosing it in `${...}`, a feature known as *antiquotation*. The + enclosed expression must evaluate to something that can be coerced + into a string (meaning that it must be a string, a path, or a + derivation). For instance, rather than writing + + ```nix + "--with-freetype2-library=" + freetype + "/lib" + ``` + + (where `freetype` is a derivation), you can instead write the more + natural + + ```nix + "--with-freetype2-library=${freetype}/lib" + ``` + + The latter is automatically translated to the former. A more + complicated example (from the Nix expression for + [Qt](http://www.trolltech.com/products/qt)): + + ```nix + configureFlags = " + -system-zlib -system-libpng -system-libjpeg + ${if openglSupport then "-dlopen-opengl + -L${mesa}/lib -I${mesa}/include + -L${libXmu}/lib -I${libXmu}/include" else ""} + ${if threadSupport then "-thread" else "-no-thread"} + "; + ``` + + Note that Nix expressions and strings can be arbitrarily nested; in + this case the outer string contains various antiquotations that + themselves contain strings (e.g., `"-thread"`), some of which in + turn contain expressions (e.g., `${mesa}`). + + The second way to write string literals is as an *indented string*, + which is enclosed between pairs of *double single-quotes*, like so: + + ```nix + '' + This is the first line. + This is the second line. + This is the third line. + '' + ``` + + This kind of string literal intelligently strips indentation from + the start of each line. To be precise, it strips from each line a + number of spaces equal to the minimal indentation of the string as a + whole (disregarding the indentation of empty lines). For instance, + the first and second line are indented two space, while the third + line is indented four spaces. Thus, two spaces are stripped from + each line, so the resulting string is + + ```nix + "This is the first line.\nThis is the second line.\n This is the third line.\n" + ``` + + Note that the whitespace and newline following the opening `''` is + ignored if there is no non-whitespace text on the initial line. + + Antiquotation (`${expr}`) is supported in indented strings. + + Since `${` and `''` have special meaning in indented strings, you + need a way to quote them. `$` can be escaped by prefixing it with + `''` (that is, two single quotes), i.e., `''$`. `''` can be escaped + by prefixing it with `'`, i.e., `'''`. `$` removes any special + meaning from the following `$`. Linefeed, carriage-return and tab + characters can be written as `''\n`, `''\r`, `''\t`, and `''\` + escapes any other character. + + Indented strings are primarily useful in that they allow multi-line + string literals to follow the indentation of the enclosing Nix + expression, and that less escaping is typically necessary for + strings representing languages such as shell scripts and + configuration files because `''` is much less common than `"`. + Example: + + ```nix + stdenv.mkDerivation { + ... + postInstall = + '' + mkdir $out/bin $out/etc + cp foo $out/bin + echo "Hello World" > $out/etc/foo.conf + ${if enableBar then "cp bar $out/bin" else ""} + ''; + ... + } + ``` + + Finally, as a convenience, *URIs* as defined in appendix B of + [RFC 2396](http://www.ietf.org/rfc/rfc2396.txt) can be written *as + is*, without quotes. For instance, the string + `"http://example.org/foo.tar.bz2"` can also be written as + `http://example.org/foo.tar.bz2`. + + - Numbers, which can be *integers* (like `123`) or *floating point* + (like `123.43` or `.27e13`). + + Numbers are type-compatible: pure integer operations will always + return integers, whereas any operation involving at least one + floating point number will have a floating point number as a result. + + - *Paths*, e.g., `/bin/sh` or `./builder.sh`. A path must contain at + least one slash to be recognised as such. For instance, `builder.sh` + is not a path: it's parsed as an expression that selects the + attribute `sh` from the variable `builder`. If the file name 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 + `/foo/bar/bla.nix` refers to `../xyzzy/fnord.nix`, the absolute path + is `/foo/xyzzy/fnord.nix`. + + If the first component of a path is a `~`, it is interpreted as if + the rest of the path were relative to the user's home directory. + e.g. `~/foo` would be equivalent to `/home/edolstra/foo` for a user + whose home directory is `/home/edolstra`. + + Paths can also be specified between angle brackets, e.g. + `<nixpkgs>`. This means that the directories listed in the + environment variable `NIX_PATH` will be searched for the given file + or directory name. + + Antiquotation is supported in any paths except those in angle brackets. + `./${foo}-${bar}.nix` is a more convenient way of writing + `./. + "/" + foo + "-" + bar + ".nix"` or `./. + "/${foo}-${bar}.nix"`. At + least one slash must appear *before* any antiquotations for this to be + recognized as a path. `a.${foo}/b.${bar}` is a syntactically valid division + operation. `./a.${foo}/b.${bar}` is a path. + + - *Booleans* with values `true` and `false`. + + - The null value, denoted as `null`. + +## Lists + +Lists are formed by enclosing a whitespace-separated list of values +between square brackets. For example, + +```nix +[ 123 ./foo.nix "abc" (f { x = y; }) ] +``` + +defines a list of four elements, the last being the result of a call to +the function `f`. Note that function calls have to be enclosed in +parentheses. If they had been omitted, e.g., + +```nix +[ 123 ./foo.nix "abc" f { x = y; } ] +``` + +the result would be a list of five elements, the fourth one being a +function and the fifth being a set. + +Note that lists are only lazy in values, and they are strict in length. + +## Sets + +Sets are really the core of the language, since ultimately the Nix +language is all about creating derivations, which are really just sets +of attributes to be passed to build scripts. + +Sets are just a list of name/value pairs (called *attributes*) enclosed +in curly brackets, where each value is an arbitrary expression +terminated by a semicolon. For example: + +```nix +{ x = 123; + text = "Hello"; + y = f { bla = 456; }; +} +``` + +This defines a set with attributes named `x`, `text`, `y`. The order of +the attributes is irrelevant. An attribute name may only occur once. + +Attributes can be selected from a set using the `.` operator. For +instance, + +```nix +{ a = "Foo"; b = "Bar"; }.a +``` + +evaluates to `"Foo"`. It is possible to provide a default value in an +attribute selection using the `or` keyword. For example, + +```nix +{ a = "Foo"; b = "Bar"; }.c or "Xyzzy" +``` + +will evaluate to `"Xyzzy"` because there is no `c` attribute in the set. + +You can use arbitrary double-quoted strings as attribute names: + +```nix +{ "foo ${bar}" = 123; "nix-1.0" = 456; }."foo ${bar}" +``` + +This will evaluate to `123` (Assuming `bar` is antiquotable). In the +case where an attribute name is just a single antiquotation, the quotes +can be dropped: + +```nix +{ foo = 123; }.${bar} or 456 +``` + +This will evaluate to `123` if `bar` evaluates to `"foo"` when coerced +to a string and `456` otherwise (again assuming `bar` is antiquotable). + +In the special case where an attribute name inside of a set declaration +evaluates to `null` (which is normally an error, as `null` is not +antiquotable), that attribute is simply not added to the set: + +```nix +{ ${if foo then "bar" else null} = true; } +``` + +This will evaluate to `{}` if `foo` evaluates to `false`. + +A set that has a `__functor` attribute whose value is callable (i.e. is +itself a function or a set with a `__functor` attribute whose value is +callable) can be applied as if it were a function, with the set itself +passed in first , e.g., + +```nix +let add = { __functor = self: x: x + self.x; }; + inc = add // { x = 1; }; +in inc 1 +``` + +evaluates to `2`. This can be used to attach metadata to a function +without the caller needing to treat it specially, or to implement a form +of object-oriented programming, for example. diff --git a/doc/manual/src/expressions/simple-building-testing.md b/doc/manual/src/expressions/simple-building-testing.md new file mode 100644 index 000000000..6f730a936 --- /dev/null +++ b/doc/manual/src/expressions/simple-building-testing.md @@ -0,0 +1,61 @@ +# Building and Testing + +You can now try to build Hello. Of course, you could do `nix-env -i +hello`, but you may not want to install a possibly broken package just +yet. The best way to test the package is by using the command +`nix-build`, which builds a Nix expression and creates a symlink named +`result` in the current directory: + +```console +$ nix-build -A hello +building path `/nix/store/632d2b22514d...-hello-2.1.1' +hello-2.1.1/ +hello-2.1.1/intl/ +hello-2.1.1/intl/ChangeLog +... + +$ ls -l result +lrwxrwxrwx ... 2006-09-29 10:43 result -> /nix/store/632d2b22514d...-hello-2.1.1 + +$ ./result/bin/hello +Hello, world! +``` + +The `-A` option selects the `hello` attribute. This is faster than +using the symbolic package name specified by the `name` attribute +(which also happens to be `hello`) and is unambiguous (there can be +multiple packages with the symbolic name `hello`, but there can be +only one attribute in a set named `hello`). + +`nix-build` registers the `./result` symlink as a garbage collection +root, so unless and until you delete the `./result` symlink, the output +of the build will be safely kept on your system. You can use +`nix-build`’s `-o` switch to give the symlink another name. + +Nix has transactional semantics. Once a build finishes successfully, Nix +makes a note of this in its database: it registers that the path denoted +by `out` is now “valid”. 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 paths will not be registered as valid. If you try to build the +derivation again, Nix will remove the output paths if they exist (e.g., +because the builder died half-way through `make +install`) and try again. Note that there is no “negative caching”: 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). + +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: + +```console +$ nix-build -A hello +waiting for lock on `/nix/store/0h5b7hp8d4hqfrw8igvx97x1xawrjnac-hello-2.1.1x' +``` + +So it is always safe to run multiple instances of Nix in parallel (which +isn’t the case with, say, `make`). diff --git a/doc/manual/src/expressions/simple-expression.md b/doc/manual/src/expressions/simple-expression.md new file mode 100644 index 000000000..857f71b9b --- /dev/null +++ b/doc/manual/src/expressions/simple-expression.md @@ -0,0 +1,23 @@ +# A Simple Nix Expression + +This section shows how to add and test the [GNU Hello +package](http://www.gnu.org/software/hello/hello.html) to the Nix +Packages collection. Hello is a program that prints out the text “Hello, +world\!”. + +To add a package to the Nix Packages collection, you generally need to +do three things: + +1. Write a Nix expression for the package. This is a file that + describes all the inputs involved in building the package, such as + dependencies, sources, and so on. + +2. Write a *builder*. This is a shell script that builds the package + from the inputs. (In fact, it can be written in any language, but + typically it's a `bash` shell script.) + +3. Add the package to the file `pkgs/top-level/all-packages.nix`. The + Nix expression written in the first step is a *function*; it + requires other packages 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 package. diff --git a/doc/manual/src/expressions/writing-nix-expressions.md b/doc/manual/src/expressions/writing-nix-expressions.md new file mode 100644 index 000000000..5664108e7 --- /dev/null +++ b/doc/manual/src/expressions/writing-nix-expressions.md @@ -0,0 +1,12 @@ +This chapter shows you how to write Nix expressions, which instruct Nix +how to build packages. 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. + +> **Note** +> +> This chapter is mostly about the Nix expression language. For more +> extensive information on adding packages to the Nix Packages +> collection (such as functions in the standard environment and coding +> conventions), please consult [its +> manual](http://nixos.org/nixpkgs/manual/). |