1
0
Fork 0
mirror of https://github.com/NixOS/nix.dev.git synced 2024-10-18 14:32:43 -04:00
nix.dev/source/tutorials/nix-language.md

1194 lines
26 KiB
Markdown
Raw Normal View History

2022-08-02 06:46:49 -04:00
(reading-nix-language)=
# Nix language basics
2022-08-18 09:39:39 -04:00
The Nix language is used to declare packages and configurations for the [Nix package manager][nix-manual].
It is a domain-specific, purely functional, lazily evaluated, dynamically typed programming language.
2022-08-18 09:34:16 -04:00
Notable uses of the Nix language are:
- [Nix package collection][nixpkgs] (`nixpkgs`)
It is the largest, most up-to-date software distribution in the world, and written in Nix language.
- [NixOS][nixos-manual] Linux distribution
2022-08-18 09:34:16 -04:00
It is based on the Nix package manager, and can be configured fully declaratively.
Its underlying modular configuration system is written in Nix language, and uses packages from `nixpkgs`.
2022-08-18 09:34:16 -04:00
The operating system environment and services it provides are configured with Nix language.
[nix-manual]: https://nixos.org/manual/nix/stable/#preface
[nixpkgs-manual]: https://nixos.org/manual/nixpkgs/stable/#preface
[nixos-manual]: https://nixos.org/manual/nixos/stable/index.html#preface
[home-manager]: https://github.com/nix-community/home-manager
2022-08-18 09:34:16 -04:00
## Overview
Using the Nix language in practice entails multiple things:
- language: syntax and semantics
- standard libraries: `builtins` and `nixpkgs/lib`
2022-08-22 07:39:32 -04:00
- developer tools: testing, debugging, linting and formatting, ...
- generic build mechanisms: `stdenv`, trivial builders, ...
- composition and configuration mechanisms: `override`, `overrideAttrs`, overlays, `callPackage`, ...
- ecosystem-specific packaging mechanisms: `buildGoModule`, `buildPythonApplication`, ...
- NixOS module system: `config`, `option`, ...
**This guide only covers language syntax and semantics**, briefly discusses standard libraries, and at the end will direct you to resources on the other components.
### What will you learn?
2022-08-01 07:42:25 -04:00
This guide should enable you to read typical Nix language code and understand its structure.
2022-08-01 12:13:57 -04:00
It shows the most common and distingushing patterns in the Nix language:
2022-08-01 07:42:25 -04:00
2022-08-02 04:41:37 -04:00
- assigning names and accessing values
2022-08-01 07:42:25 -04:00
- declaring and calling functions
- built-in and library functions
- side effects to obtain build inputs and produce build results
2022-08-18 09:34:16 -04:00
2022-08-01 12:13:57 -04:00
It *does not* explain all Nix language features in detail.
See the [Nix manual][manual-language] for a full language reference.
2022-08-02 06:46:49 -04:00
[manual-language]: https://nixos.org/manual/nix/stable/expressions/expression-language.html
### What do you need?
2022-08-01 07:42:25 -04:00
- Familiarity with software development
- Familiarity with Unix shell, to read command line examples <!-- TODO: link to yet-to-be instructions on "how to read command line examples" -->
- Install the Nix package manager, to run the examples
2022-08-02 04:41:37 -04:00
<!-- TODO: approximate amount of time, as observed with test subjects -->
### How long does it take?
Carefully working through all definitions and examples, and reading all detailed explanations should take ca. 2 hours.
If you are proficient in procedural or object-oriented programming, learning syntax and semantics by examining all examples should take ca. 1 hour.
If you are familiar with functional programming, the Nix language will be unsurprizing.
Reading through the guide to get accustomed to the syntax should take ca. 30 minutes.
2022-08-18 09:34:16 -04:00
### How to run the examples?
2022-08-01 07:41:22 -04:00
- Every valid piece of Nix language code is a *Nix expression*.
- Nix expressions can contain other Nix expressions, that is, they can be nested.
- Evaluating a Nix expression produces a single value.
- Every *Nix file* (`.nix`) contains a single Nix expression.
:::{note}
To *evaluate* means to transform an expression according to the language rules until no further simplification is possible.
:::
All examples in this guide are valid Nix expressions.
Each one is followed by the expected evaluation result.
2022-08-01 07:41:22 -04:00
The following example is a Nix expression adding two numbers:
2022-08-02 03:14:30 -04:00
```nix
1 + 2
```
2022-08-01 07:41:22 -04:00
2022-08-01 12:21:18 -04:00
3
#### Interactive evaluation
Use `nix repl` to evaluate Nix expressions interactively (by typing them on the command line):
```console
nix repl
```
Welcome to Nix 2.5.1. Type :? for help.
```console
nix-repl> 1 + 2
```
3
#### Evaluating Nix files
2022-08-01 07:41:22 -04:00
Use `nix-instantiate --eval` to evaluate the expression in a Nix file.
```console
2022-08-02 03:14:30 -04:00
echo 1 + 2 > file.nix
2022-08-01 07:41:22 -04:00
2022-08-02 03:14:30 -04:00
nix-instantiate --eval file.nix
```
2022-08-01 07:41:22 -04:00
2022-08-15 05:18:42 -04:00
3
2022-08-01 07:41:22 -04:00
:::{note}
`nix-instantiate --eval` will evaluate `default.nix` if no file name is specified.
```console
2022-08-02 03:14:30 -04:00
echo 1 + 2 > default.nix
2022-08-01 07:41:22 -04:00
2022-08-02 03:14:30 -04:00
nix-instantiate --eval
```
2022-08-15 05:18:42 -04:00
3
2022-08-01 07:41:22 -04:00
:::
2022-08-18 09:34:16 -04:00
## Reading the Nix language without fear
You will quickly encounter Nix language expressions that may look very complicated.
As with any programming language, the required amount of Nix language code closely matches the complexity of the problem it is supposed to solve, and reflects how well the problem and its solution is understood.
Building software is a complex undertaking, and the Nix package manager both exposes and allows managing this complexity with the Nix language.
The purpose of the Nix language is to create *build tasks*: precise descriptions of how contents of existing files are used to derive new files.
2022-08-18 09:34:16 -04:00
:::{important}
A build task in the Nix package manager is also called *derivation*.
:::
The Nix language has only few basic constructs which can be combined arbitrarily:
- primitive data types
as basic building blocks
- compound data types and functions
to produce and transform complex data
- name assignment
to manipulate complex data as units
In addition it allows three side effects:
- reading files as Nix expressions
to enable code reuse
- reading files as *build inputs*
to capture what build tasks will operate on
- writing files as *build tasks*
to keep them for later execution, the *build*
There is nothing else to it.
What may look complicated comes not from the language, but from how it is used.
2022-08-18 09:34:16 -04:00
## Names and values
2022-08-01 12:34:53 -04:00
There are two ways to assign names to values in Nix: attribute sets and `let` expressions.
2022-08-01 12:34:53 -04:00
Assignments are denoted by a single equal sign (`=`).
### Attribute set `{ ... }`
2022-08-01 12:34:53 -04:00
2022-08-22 08:33:46 -04:00
An attribute set is an unordered collection of name-value-pairs, where names must be unique.
2022-08-01 12:34:53 -04:00
The following example shows all primitive data types, lists, and attribute sets.
:::{note}
If you are familiar with JSON, imagine the Nix language as *JSON with functions*.
Nix language data types *without functions* work just like their counterparts in JSON and look very similar.
:::
2022-08-02 06:46:49 -04:00
<table>
<tr>
<th>Nix language</th>
<th>JSON</th>
</tr>
<tr>
<td>
2022-08-02 03:14:30 -04:00
```nix
{
string = "hello";
integer = 1;
float = 3.141;
bool = true;
null = null;
list = [ 1 "two" false ];
attribute-set = {
a = "hello";
b = 2;
c = 2.718;
d = false;
}; # comments are supported
}
```
2022-08-02 06:46:49 -04:00
</td>
<td>
2022-08-02 03:14:30 -04:00
```json
{
"string": "hello",
"integer": 1,
"float": 3.141,
"bool": true,
"null": null,
"list": [1, "two", false],
2022-08-15 11:39:08 -04:00
"object": {
2022-08-02 03:14:30 -04:00
"a": "hello",
"b": 1,
"c": 2.718,
"d": false
}
}
```
2022-08-02 06:46:49 -04:00
</td>
</tr>
</table>
2022-08-01 12:34:53 -04:00
:::{note}
- Attribute names usually do not need quotes.[^1]
- List elements are separated by white space.[^2]
:::
2022-08-15 11:03:29 -04:00
[^1]: Details: Nix manual - attribute naming rules <!-- TODO: create and link manual section -->
2022-08-01 12:34:53 -04:00
[^2]: Details: [Nix manual - lists][manual-lists]
2022-08-01 12:34:53 -04:00
[manual-lists]: https://nixos.org/manual/nix/stable/expressions/language-values.html#lists
#### Recursive attribute set `rec { ... }`
2022-08-01 12:34:53 -04:00
You will sometimes see attribute sets declared with `rec` prepended.
2022-08-02 04:41:37 -04:00
This allows access to attributes from within the set.
2022-08-01 12:34:53 -04:00
Example:
2022-08-01 12:34:53 -04:00
```nix
rec {
one = 1;
two = one + 1;
three = two + 1;
}
```
2022-08-01 12:34:53 -04:00
{ one = 1; three = 3; two = 2; }
2022-08-22 08:33:46 -04:00
:::{note}
Attribute sets are unordered.
The evaluator prints them in alphabetic order.
:::
2022-08-01 12:34:53 -04:00
Counter-example:
2022-08-01 12:34:53 -04:00
```nix
{
one = 1;
two = one + 1;
three = two + 1;
}
```
2022-08-01 12:34:53 -04:00
error: undefined variable 'one'
2022-08-01 12:34:53 -04:00
at «string»:3:9:
2022-08-01 12:34:53 -04:00
2| one = 1;
3| two = one + 1;
| ^
4| three = two + 1;
2022-08-02 06:46:49 -04:00
{ref}`We recommend to avoid recursive sets <rec-expression>` and to use the `let` expression instead.
### `let ... in ...`
2022-08-02 06:46:49 -04:00
Also known as “`let` expression” or “`let` binding”
2022-08-01 12:34:53 -04:00
`let` expressions allow assigning names to values for repeated use.
2022-08-01 12:34:53 -04:00
Example:
2022-08-02 03:14:30 -04:00
```nix
let
a = 1;
in
a + a
```
2022-08-01 12:34:53 -04:00
2
2022-08-01 12:34:53 -04:00
As in attribute sets, names can be assigned in any order.
In contrast to attribute sets, the expressions on the right of the assignment can refer to other assigned names.
2022-08-01 12:34:53 -04:00
Example:
2022-08-02 03:14:30 -04:00
```nix
let
b = a + 1
a = 1;
in
a + b
```
2022-08-01 12:34:53 -04:00
3
2022-08-02 06:46:49 -04:00
Only expressions within the `let` expression itself can access the newly declared names.
2022-08-01 12:34:53 -04:00
We say: the bindings have local scope.
2022-08-02 04:41:37 -04:00
Counter-example:
2022-08-01 12:34:53 -04:00
```nix
{
a = let x = 1; in x;
b = x;
}
```
2022-08-01 12:34:53 -04:00
error: undefined variable 'x'
2022-08-01 12:34:53 -04:00
at «string»:3:7:
2022-08-01 12:34:53 -04:00
2| a = let x = 1; in x;
3| b = x;
| ^
4| }
2022-08-01 12:34:53 -04:00
<!-- TODO: exercise - use let to reuse a value in an attribute set -->
### Attribute access
2022-08-02 04:41:37 -04:00
Attributes in a set can be accessed with a dot (`.`) and the attribute name.
Example:
```nix
let
attrset = { x = 1; };
in
attrset.x
```
1
Accessing nested attributes works the same way.
Example:
```nix
let
attrset = { a = { b = { c = 1; }; }; };
2022-08-02 04:41:37 -04:00
in
attrset.a.b.c
```
1
The dot (`.`) notation also works when assigning attributes.
Example:
```nix
let
attrset = { a.b.c = 1; };
in
attrset
```
{ a = { b = { c = 1; }; }; }
2022-08-02 04:41:37 -04:00
### `with ...; ...`
2022-08-02 04:41:37 -04:00
2022-08-02 06:46:49 -04:00
The `with` expression allows access to attributes without repeatedly referencing their attribute set.
2022-08-02 04:41:37 -04:00
Example:
```nix
let
a = {
x = 1;
y = 2;
z = 3;
};
in
with a; [ x y z ]
```
[ 1 2 3 ]
The expression
with a; [ x y z ]
is equivalent to
[ a.x a.y a.z ]
Attributes made available through `with` are only in scope of the expression following the semicolon (`;`).
Counter-example:
```nix
let
a = {
x = 1;
y = 2;
z = 3;
};
in
{
b = with a; [ x y z ];
c = x;
}
```
error: undefined variable 'x'
at «string»:10:7:
9| b = with a; [ x y z ];
10| c = x;
| ^
11| }
### `inherit ...`
2022-08-02 04:41:37 -04:00
2022-08-15 05:18:59 -04:00
With `inherit` one can assign existing names to attributes of the same name.
2022-08-02 04:41:37 -04:00
It is for convenience to avoid repeating the same name multiple times.
Example:
```
let
x = 1;
y = 2;
in
{
inherit x y;
}
```
{ x = 1; y = 2; }
The fragment
inherit x y;
is equivalent to
x = x; y = y;
2022-08-22 12:56:22 -04:00
It is also possible to `inherit` names from a specific attribute set with parentheses (`inherit (...) ...`).
2022-08-02 04:41:37 -04:00
Example:
```nix
let
a = { x = 1; y = 2; };
in
{
inherit (a) x y;
}
```
{ x = 1; y = 2; }
The fragment
inherit (a) x y;
is equivalent to
x = a.x; y = a.y;
2022-08-01 12:45:02 -04:00
### File system paths
Nix language offers convenience syntax for file system paths.
Absolute paths always start with a slash (`/`):
/absolute/path
Paths are relative when they contain at least one slash (`/`) but to not start with one.
They are relative to the file containing the expression:
```nix
./relative
```
```nix
relative/path
```
One dot (`.`) denotes the same directory.
This is typically used to specify the current directory:
```nix
./.
```
Two dots (`..`) denote the parent directory.
2022-08-22 12:57:29 -04:00
#### Search path
Also known as “angle bracket syntax”.
<nixpkgs>
The value of a named path is a file system path that depends on the contents of the [`$NIX_PATH`][NIX_PATH] environment variable.
2022-08-22 23:56:26 -04:00
In practice, `<nixpkgs>` points to the file system path of some revision of the Nix package collection's source repository [`nixpkgs`][nixpkgs].
2022-08-22 12:57:29 -04:00
For example, `<nixpkgs/lib>` points to the subdirectory `lib` of that file system path.
While you will see many such examples, we recommend to {ref}`avoid search paths <search-path>` in practice, as they are not fully reproducible.
[NIX_PATH]: https://nixos.org/manual/nix/unstable/command-ref/env-common.html?highlight=nix_path#env-NIX_PATH
[nixpkgs]: https://github.org/NixOS/nixpkgs
[manual-primitives]: https://nixos.org/manual/nix/stable/expressions/language-values.html#primitives
### Indented strings
Also known as “multi-line strings”.
Nix language offers convenience syntax for character strings which span multiple lines that have common indentation.
Indented strings are denoted by *double single quotes* (`'' ''`).
Example:
```nix
''
multi
line
string
''
```
"multi\nline\nstring"
Equal amounts of prepended white space are trimmed from the result.
Example:
```nix
''
one
two
three
''
```
"one\n two\n three\n"
<!-- TODO: See [escaping rules](). -->
2022-08-22 23:56:54 -04:00
### Antiquotation `${ ... }`
Also known as “string interpolation”.
2022-08-22 23:56:54 -04:00
The value of a Nix expression can be inserted into a character string with the dollar-sign and braces (`${ }`).
Example:
```nix
let
name = "Nix";
in
"hello ${name}"
```
"hello Nix"
Only character strings or values that can be represented as a character string are allowed.
Counter-example:
```nix
let
x = 1;
in
"${x} + ${x} = ${x + x}"
```
error: cannot coerce an integer to a string
at «string»:4:2:
3| in
4| "${x} + ${x} = ${x + x}"
| ^
5|
Antiquotation can be arbitrarily nested.
(This can become hard to read, and we recommend to avoid it in practice.)
Example:
```nix
let
a = "no";
in
"${a + "${a + " ${a}"}"}"
```
"no no no"
:::{warning}
You may encounter strings that use the dollar sign (`$`) before an assigned name, but no braces (`{ }`):
These are *not* antiquotations, but usually denote variables in a shell script.
In such cases, the use of names from the surrounding Nix expression is a coincidence.
Example:
```nix
let
out = "Nix"
in
"echo ${out} > $out"
```
"echo Nix > $out"
:::
<!-- TODO: link to escaping rules -->
## Functions
2022-08-15 11:52:00 -04:00
Functions are everywhere in the Nix language and deserve particular attention.
2022-08-18 09:37:34 -04:00
### Single argument
Functions in Nix language can appear in different forms, but always take exactly one argument.
2022-08-01 12:34:53 -04:00
Argument and function body are separated by a colon (`:`).
2022-08-01 12:34:53 -04:00
Wherever you see a colon (`:`) in Nix language code:
- on its left is the function argument
- on its right is the function body.
2022-08-22 08:33:46 -04:00
Nix functions have no names.
We say they are anonymous, and call such a function a *lambda*.
Example:
```nix
x: x + 1
```
<LAMBDA>
The `<LAMBDA>` indicates the resulting value is an anonymous function.
We can assign functions a name as to any other value.
Example:
```nix
let
f = x: x + 1
in f
```
<LAMBDA>
2022-08-18 09:37:34 -04:00
### Calling functions
Also known as "function application".
2022-08-15 11:13:51 -04:00
Calling a function with an operand means writing the operand after the function.
2022-08-22 07:44:36 -04:00
Example:
2022-08-01 12:34:53 -04:00
```nix
(x: x + 1) 1
```
2022-08-01 12:34:53 -04:00
2
2022-08-22 08:33:46 -04:00
:::{note}
Since function and operand are separated by white space, sometimes parantheses (`( )`) are required to distinguish expressions.
:::
Example:
2022-08-02 03:14:30 -04:00
```nix
let
2022-08-22 08:33:46 -04:00
f = x: x.a;
2022-08-02 03:14:30 -04:00
in
2022-08-15 11:30:50 -04:00
f { a = 1; }
2022-08-02 03:14:30 -04:00
```
2022-08-15 11:30:50 -04:00
1
2022-08-22 08:33:46 -04:00
The above example calls `f` on a literal attribute set.
One can also pass operands by name.
Example:
```nix
let
f = x: x.a;
v = { a = 1; };
in
f v
```
1
2022-08-22 07:45:14 -04:00
### Chaining arguments
2022-08-22 08:33:46 -04:00
Arguments can be chained by nesting functions.
2022-08-22 08:33:46 -04:00
Such a nested function can be used like a function that takes multiple arguments, but offers additional flexibility.
2022-08-22 08:33:46 -04:00
Example:
```nix
x: y: x + y
```
<LAMBDA>
2022-08-01 12:34:53 -04:00
The above function takes one argument and returns a function `y: x + y` with `x` set to the value of the argument.
Example:
2022-08-02 03:14:30 -04:00
```nix
let
f = x: y: x + y;
in
f 1
```
2022-08-02 03:14:30 -04:00
<LAMBDA>
Applying that function `f 1` to another argument yields the inner body `x + y` (with `x` set to `1` and `y` set to the other argument), which can now be fully evaluated.
2022-08-02 03:14:30 -04:00
```nix
let
f = x: y: x + y;
in
f 1 2
```
3
2022-08-01 12:34:53 -04:00
<!-- TODO: exercise - assign the lambda a name and do something with it -->
### Attribute set argument
2022-08-02 06:46:49 -04:00
2022-08-22 13:00:40 -04:00
Also known as “keyword arguments” or “destructuring” .
2022-08-22 13:00:40 -04:00
Nix functions can be declared to require an attribute set with specific structure as argument.
2022-08-22 08:33:46 -04:00
This is denoted by listing the expected attribute names separated by commas (`,`) and enclosed in braces (`{ }`).
Example:
```nix
{a, b}: a + b
```
<LAMBDA>
The argument defines the exact attributes that have to be in that set.
Leaving out or passing additional attributes is an error.
Example:
2022-08-02 03:14:30 -04:00
```nix
let
f = {a, b}: a + b;
2022-08-02 03:14:30 -04:00
in
f { a = 1; b = 2; }
```
3
Counter-example:
```nix
let
f = {a, b}: a + b;
in
f { a = 1; b = 2; c = 3; }
```
error: 'f' at (string):2:7 called with unexpected argument 'c'
at «string»:4:1:
3| in
4| f { a = 1; b = 2; c = 3; }
| ^
5|
2022-08-22 13:00:40 -04:00
<!-- TODO: not the same as x: x.a + x.b (!!!!) -->
### Default attributes
Also known as “default arguments”.
2022-08-22 13:00:40 -04:00
Destructured arguments can have default values for attributes.
2022-08-22 08:33:46 -04:00
This is denoted by separating the attribute name and its default value with a question mark (`?`).
Attributes in the argument are not required if they have a default value.
Example:
2022-08-02 03:14:30 -04:00
```nix
let
f = {a, b ? 0}: a + b
in
f { a = 1; }
```
1
Example:
2022-08-02 03:14:30 -04:00
```nix
let
f = {a ? 0, b ? 0}: a + b
in
f { } # empty attribute set
```
0
### Additional attributes
2022-08-01 12:45:02 -04:00
Additional attributes are allowed with an ellipsis (`...`):
{a, b, ...}: a + b
Example:
2022-08-02 03:14:30 -04:00
```nix
let
f = {a, b, ...}: a + b
in
f { a = 1; b = 2; c = 3; }
```
3
### Named attribute argument
2022-08-22 08:33:46 -04:00
Also known as “@ pattern”, “@ syntax”, or “at syntax”.
An attribute set argument can be given a name to be accessible as a whole.
This is denoted by prepending or appending the name to the attribute set argument, separated by the at sign (`@`).
Example:
```nix
{a, b, ...}@args: a + b + args.c
```
2022-08-22 08:33:46 -04:00
<LAMBDA>
2022-07-28 05:49:03 -04:00
or
2022-08-22 08:33:46 -04:00
```nix
args@{a, b, ...}: a + b + args.c
```
<LAMBDA>
Example:
2022-08-02 03:14:30 -04:00
```nix
let
f = {a, b, ...}@args: a + b + args.c
in
f { a = 1; b = 2; c = 3; }
```
2022-07-28 05:49:03 -04:00
6
2022-08-01 12:34:53 -04:00
## Function libraries
2022-08-02 06:47:03 -04:00
There are two widely used libraries that *together* can be considered standard for the Nix language.
You need to know about both to understand and navigate Nix language code.
2022-08-15 06:50:43 -04:00
2022-08-22 23:57:54 -04:00
<!-- TODO: find a place for operators -->
2022-08-15 06:50:43 -04:00
We recommend to at least skim them to familiarise yourself with what is available.
### `builtins`
2022-08-15 06:50:43 -04:00
Nix comes with many functions that are built into the language.
:::{note}
2022-08-22 23:57:54 -04:00
The Nix manual lists all [Built-in Functions][nix-builtins], and shows how to use them.
2022-08-15 06:50:43 -04:00
:::
2022-08-22 23:57:54 -04:00
These functions are available under the `builtins` constant.
Example:
2022-08-15 06:50:43 -04:00
builtins.toString
Most of them are implemented in the Nix language interpreter itself, which means they usually execute faster than their equivalents implemented in the Nix language.
2022-08-22 23:57:54 -04:00
[nix-operators]: https://nixos.org/manual/nix/unstable/language/operators.html
2022-08-15 06:50:43 -04:00
[nix-builtins]: https://nixos.org/manual/nix/stable/expressions/builtins.html
### `pkgs.lib`
2022-08-15 06:50:43 -04:00
The Nix package collection [`nixpkgs`][nixpkgs] contains an attribute set called `lib`, which provides a large number of useful functions.
:::{note}
The `nixpkgs` manual lists all [Nixpkgs library functions][nixpkgs-functions].
:::
2022-08-22 23:59:24 -04:00
These functions are usually accessed through `pkgs.lib`.
Example:
2022-08-15 06:50:43 -04:00
pkgs.lib.strings.toUpper
[nixpkgs-functions]: https://nixos.org/manual/nixpkgs/stable/#sec-functions-library
2022-08-22 23:59:24 -04:00
## Building software with side effects
2022-08-02 06:47:03 -04:00
So far we have only covered what we call *pure expressions*:
declaring data and transforming it with functions.
2022-08-17 11:18:40 -04:00
Building software requires interaction with the outside world, called *side effects*.
2022-08-02 06:47:03 -04:00
2022-08-22 23:59:24 -04:00
There are three side effects in the Nix language that are relevant here:
1. Importing Nix expressions from other files
2. Reading files from the file system as build inputs
3. Writing files to the file system as build tasks
Side effects are performed while evaluating a given impure expression.
2022-08-22 13:02:12 -04:00
### Imports
2022-08-22 23:59:24 -04:00
The built-in function `import` takes a path to a Nix file, and reads it to evaluate the contained Nix expression.
Example:
```console
echo 1 + 2 > file.nix
```
```nix
import ./file.nix
```
3
Example:
```console
echo "x: x + 1" > file.nix
```
```nix
import ./file.nix 1
```
2
It is an error if the file system path does not exist.
### Build inputs
2022-08-02 06:47:03 -04:00
2022-08-22 23:59:24 -04:00
Build inputs are files that build tasks refer to in their precise description of how to derive new files.
Since Nix language evaluation is otherwise pure, the only way to specify build inputs is explicitly with:
- file system paths
- dedicated impure functions
When run, a build task will only have access to explicitly declared build inputs.
:::{important}
Purity is the key to reproducible builds.
It precludes build tasks from referring to files which are not explicitly specified as build inputs.
:::
2022-08-22 13:02:12 -04:00
#### Paths
2022-08-22 23:59:24 -04:00
Whenever a file system path is rendered to a character string with [antiquotation](#antiquotation), the contents of that file are copied to a special location in the file system, the *Nix store*.
The evaluated string then contains the Nix store path assigned to that file.
<!-- TODO: link to explanation of the Nix store -->
Example:
```console
echo 123 > data
```
```nix
"${./data}"
```
"/nix/store/h1qj5h5n05b5dl5q4nldrqq8mdg7dhqk-data"
#### Fetchers
Files to be used as build inputs do not have to come from the file system.
The Nix language provides built-in impure functions to fetch files from the network during evaluation:
- [builtins.fetchurl][fetchurl]
- [builtins.fetchTarball][fetchTarball]
- [builtins.fetchGit][fetchGit]
- [builtins.fetchClosure][fetchClosure]
These functions evaluate to a file system path in the Nix store, which is uniquely determined by the fetched file's contents.
Example:
```nix
builtins.fetchurl https://github.com/NixOS/nix/archive/7c3ab5751568a0bc63430b33a5169c5e4784a0ff.tar.gz
```
"/nix/store/7dhgs330clj36384akg86140fqkgh8zf-7c3ab5751568a0bc63430b33a5169c5e4784a0ff.tar.gz"
Some of them add extra convenience, such as automatically unpacking archives.
Example:
```nix
builtins.fetchGit https://github.com/NixOS/nix/archive/7c3ab5751568a0bc63430b33a5169c5e4784a0ff.tar.gz
```
"/nix/store/7dhgs330clj36384akg86140fqkgh8zf-7c3ab5751568a0bc63430b33a5169c5e4784a0ff.tar.gz"
[fetchurl]: https://nixos.org/manual/nix/stable/expressions/builtins.html#builtins-fetchurl
[fetchTarball]: https://nixos.org/manual/nix/stable/expressions/builtins.html#builtins-fetchTarball
[fetchGit]: https://nixos.org/manual/nix/stable/expressions/builtins.html#builtins-fetchGit
[fetchClosure]: https://nixos.org/manual/nix/stable/expressions/builtins.html#builtins-fetchClosure
### Build tasks
A build task in the Nix package manager is called *derivation*.
The Nix language primitive to declare such a derivation is the built-in function `derivation`.
:::{important}
You will most never encounter `derivation` in practice.
It is usually wrapped by the `nixpkgs` build mechanism `stdenv.mkDerivation`, which hides much of the complexity involved in build procedures.
:::
2022-08-15 05:19:58 -04:00
2022-08-16 07:16:27 -04:00
<!-- TODO: side effects - fetchers and derivations -->
2022-08-15 05:19:58 -04:00
See the [Nix Pills][nix-pills] series for a detailed explanation on how Nix the package manager builds software using library functions and packages from the Nix package collection.
[nix-pills]: https://nixos.org/guides/nix-pills/
2022-08-02 06:47:03 -04:00
2022-08-18 07:19:49 -04:00
## Worked examples
2022-08-02 05:23:10 -04:00
You should now be able to read Nix language code for simple packages and configurations, and come up with similiar explanations of the following examples.
Example:
```nix
2022-08-18 07:19:49 -04:00
{ pkgs ? import <nixpkgs> {} }:
2022-08-15 12:13:42 -04:00
let
2022-08-18 07:19:49 -04:00
message = "hello world";
2022-08-15 12:13:42 -04:00
in
2022-08-02 05:23:10 -04:00
pkgs.mkShell {
2022-08-18 07:19:49 -04:00
buildInputs = with pkgs; [ cowsay ];
shellHook = ''
cowsay ${message}
'';
2022-08-02 05:23:10 -04:00
}
```
2022-08-18 07:19:49 -04:00
This example declares a shell environment (which runs the `shellHook` on initialization).
2022-08-02 05:23:10 -04:00
Explanation:
2022-08-15 12:13:42 -04:00
- This expression is a function that takes an attribute set as an argument.
- If the argument has the attribute `pkgs`, it will be used in the function body.
2022-08-18 07:19:49 -04:00
Otherwise, by default, import the Nix expression in the file found on the search path `<nixpkgs>` (which is a function in this case), call the function with an empty attribute set, and use the resulting value.
- The name `message` is bound to the string value `"hello world"`.
2022-08-15 12:13:42 -04:00
- The attribute `mkShell` of the `pkgs` set is a function that is passed an attribute set as argument.
Its return value is also the result of the outer function.
2022-08-18 07:19:49 -04:00
- The attribute set passed to `mkShell` has the attributes `buildInputs` (set to a list with one element: the `cowsay` attribute from `pkgs`) and `shellHook` (set to an indented string).
- the indented string contains an antiquotation, which will expand to `"hello world"`, the value of `message`
2022-08-02 05:23:10 -04:00
Example:
```nix
{ config, pkgs, ... }: {
2022-08-18 07:19:49 -04:00
2022-08-05 04:24:14 -04:00
imports = [ ./hardware-configuration.nix ];
2022-08-18 07:19:49 -04:00
2022-08-02 05:23:10 -04:00
environment.systemPackages = with pkgs; [ git ];
2022-08-18 07:19:49 -04:00
2022-08-02 05:23:10 -04:00
# ...
2022-08-18 07:19:49 -04:00
2022-08-02 05:23:10 -04:00
}
```
2022-08-18 07:19:49 -04:00
This example is (part of) a NixOS configuration.
2022-08-02 05:23:10 -04:00
Explanation:
2022-08-15 12:14:34 -04:00
- This expression is a function that takes an attribute set as an argument.
It returns an attribute set.
2022-08-18 07:19:49 -04:00
- The argument must at least have the attributes `config` and `pkgs`, and may have more attributes.
- The returned attribute set contains the attributes `imports` and `environment`.
2022-08-15 12:14:34 -04:00
`imports` is a list with one element: a path to a file next to this Nix file, called `hardware-configuration.nix`.
:::{note}
`imports` is not the impure built-in `import`, but a regular attribute name!
:::
2022-08-18 07:19:49 -04:00
- `environment` is itself an attribute set with one attribute `systemPackages`, which will evaluate to a list with one element: the `git` attribute from the `pkgs` set.
2022-08-15 12:14:34 -04:00
- The `config` argument is not used.
2022-08-02 05:23:10 -04:00
Example:
```nix
{ lib, stdenv }:
2022-08-02 06:46:49 -04:00
2022-08-02 05:23:10 -04:00
stdenv.mkDerivation rec {
2022-08-02 06:46:49 -04:00
2022-08-02 05:23:10 -04:00
pname = "hello";
2022-08-02 06:46:49 -04:00
2022-08-02 05:23:10 -04:00
version = "2.12";
2022-08-02 06:46:49 -04:00
2022-08-02 05:23:10 -04:00
src = builtins.fetchTarball {
2022-08-18 07:19:49 -04:00
url = "mirror://gnu/${pname}/${pname}-${version}.tar.gz";
2022-08-02 05:23:10 -04:00
sha256 = "1ayhp9v4m4rdhjmnl2bq3cibrbqqkgjbl3s7yk2nhlh8vj3ay16g";
};
meta = with lib; {
license = licenses.gpl3Plus;
};
2022-08-18 07:19:49 -04:00
2022-08-02 05:23:10 -04:00
}
```
2022-08-18 07:19:49 -04:00
This example is a (simplified) package declaration from `nixpkgs`.
2022-08-02 05:23:10 -04:00
2022-08-18 07:19:49 -04:00
Explanation:
2022-08-02 05:23:10 -04:00
2022-08-18 07:19:49 -04:00
- This expression is a function that takes an attribute set which must have exactly the attributes `lib` and `stdenv`.
- It returns the result of evaluating the function `mkDerivaion`, which is an attribute of `stdenv`, applied to a recursive set.
- The recursive set passed to `mkDerivation` uses its own `pname` and `version` attributes in the argument to the built-in function `fetchTarball`.
- The `meta` attribute is itself an attribute set, where the `license` attribute has the value that was assigned to the nested attribute `lib.licenses.gpl3Plus`.
2022-08-02 05:23:10 -04:00