aboutsummaryrefslogtreecommitdiff
path: root/doc/manual/src/expressions/expression-syntax.md
blob: 2a1306e326207d2bd7bc7708f950ea6efb3073f8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
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.