forked from lix-project/lix
Fix some dangling references
This commit is contained in:
parent
4a79b3598f
commit
da3d776cb9
|
@ -1,33 +1,32 @@
|
||||||
# Tuning Cores and Jobs
|
# Tuning Cores and Jobs
|
||||||
|
|
||||||
Nix has two relevant settings with regards to how your CPU cores will be
|
Nix has two relevant settings with regards to how your CPU cores will
|
||||||
utilized: [???](#conf-cores) and [???](#conf-max-jobs). This chapter
|
be utilized: `cores` and `max-jobs`. This chapter will talk about what
|
||||||
will talk about what they are, how they interact, and their
|
they are, how they interact, and their configuration trade-offs.
|
||||||
configuration trade-offs.
|
|
||||||
|
|
||||||
- [???](#conf-max-jobs)
|
- `max-jobs`
|
||||||
Dictates how many separate derivations will be built at the same
|
Dictates how many separate derivations will be built at the same
|
||||||
time. If you set this to zero, the local machine will do no builds.
|
time. If you set this to zero, the local machine will do no
|
||||||
Nix will still substitute from binary caches, and build remotely if
|
builds. Nix will still substitute from binary caches, and build
|
||||||
remote builders are configured.
|
remotely if remote builders are configured.
|
||||||
|
|
||||||
- [???](#conf-cores)
|
- `cores`
|
||||||
Suggests how many cores each derivation should use. Similar to `make
|
Suggests how many cores each derivation should use. Similar to
|
||||||
-j`.
|
`make -j`.
|
||||||
|
|
||||||
The [???](#conf-cores) setting determines the value of
|
The `cores` setting determines the value of
|
||||||
`NIX_BUILD_CORES`. `NIX_BUILD_CORES` is equal to [???](#conf-cores),
|
`NIX_BUILD_CORES`. `NIX_BUILD_CORES` is equal to `cores`, unless
|
||||||
unless [???](#conf-cores) equals `0`, in which case `NIX_BUILD_CORES`
|
`cores` equals `0`, in which case `NIX_BUILD_CORES` will be the total
|
||||||
will be the total number of cores in the system.
|
number of cores in the system.
|
||||||
|
|
||||||
The maximum number of consumed cores is a simple multiplication,
|
The maximum number of consumed cores is a simple multiplication,
|
||||||
[???](#conf-max-jobs) \* `NIX_BUILD_CORES`.
|
`max-jobs` \* `NIX_BUILD_CORES`.
|
||||||
|
|
||||||
The balance on how to set these two independent variables depends upon
|
The balance on how to set these two independent variables depends upon
|
||||||
each builder's workload and hardware. Here are a few example scenarios
|
each builder's workload and hardware. Here are a few example scenarios
|
||||||
on a machine with 24 cores:
|
on a machine with 24 cores:
|
||||||
|
|
||||||
| [???](#conf-max-jobs) | [???](#conf-cores) | `NIX_BUILD_CORES` | Maximum Processes | Result |
|
| `max-jobs` | `cores` | `NIX_BUILD_CORES` | Maximum Processes | Result |
|
||||||
| --------------------- | ------------------ | ----------------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| --------------------- | ------------------ | ----------------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| 1 | 24 | 24 | 24 | One derivation will be built at a time, each one can use 24 cores. Undersold if a job can’t use 24 cores. |
|
| 1 | 24 | 24 | 24 | One derivation will be built at a time, each one can use 24 cores. Undersold if a job can’t use 24 cores. |
|
||||||
| 4 | 6 | 6 | 24 | Four derivations will be built at once, each given access to six cores. |
|
| 4 | 6 | 6 | 24 | Four derivations will be built at once, each given access to six cores. |
|
||||||
|
@ -35,8 +34,6 @@ on a machine with 24 cores:
|
||||||
| 24 | 1 | 1 | 24 | 24 derivations can build at the same time, each using a single core. Never oversold, but derivations which require many cores will be very slow to compile. |
|
| 24 | 1 | 1 | 24 | 24 derivations can build at the same time, each using a single core. Never oversold, but derivations which require many cores will be very slow to compile. |
|
||||||
| 24 | 0 | 24 | 576 | 24 derivations can build at the same time, each using all the available cores of the machine. Very likely to be oversold, and very likely to suffer context switches. |
|
| 24 | 0 | 24 | 576 | 24 derivations can build at the same time, each using all the available cores of the machine. Very likely to be oversold, and very likely to suffer context switches. |
|
||||||
|
|
||||||
Balancing 24 Build Cores
|
|
||||||
|
|
||||||
It is up to the derivations' build script to respect host's requested
|
It is up to the derivations' build script to respect host's requested
|
||||||
cores-per-build by following the value of the `NIX_BUILD_CORES`
|
cores-per-build by following the value of the `NIX_BUILD_CORES`
|
||||||
environment variable.
|
environment variable.
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
# Verifying Build Reproducibility
|
# Verifying Build Reproducibility
|
||||||
|
|
||||||
Specify a program with Nix's [???](#conf-diff-hook) to compare build
|
You can use Nix's `diff-hook` setting to compare build results. Note
|
||||||
results when two builds produce different results. Note: this hook is
|
that this hook is only executed if the results differ; it is not used
|
||||||
only executed if the results are not the same, this hook is not used for
|
for determining if the results are the same.
|
||||||
determining if the results are the same.
|
|
||||||
|
|
||||||
For purposes of demonstration, we'll use the following Nix file,
|
For purposes of demonstration, we'll use the following Nix file,
|
||||||
`deterministic.nix` for testing:
|
`deterministic.nix` for testing:
|
||||||
|
@ -93,7 +92,7 @@ has copied the build results to that directory where you can examine it.
|
||||||
> path will be deleted on the next garbage collection.
|
> path will be deleted on the next garbage collection.
|
||||||
>
|
>
|
||||||
> The path is guaranteed to be alive for the duration of
|
> The path is guaranteed to be alive for the duration of
|
||||||
> [???](#conf-diff-hook)'s execution, but may be deleted any time after.
|
> the `diff-hook`'s execution, but may be deleted any time after.
|
||||||
>
|
>
|
||||||
> If the comparison is performed as part of automated tooling, please
|
> If the comparison is performed as part of automated tooling, please
|
||||||
> use the diff-hook or author your tooling to handle the case where the
|
> use the diff-hook or author your tooling to handle the case where the
|
||||||
|
@ -112,9 +111,8 @@ Run the build without `--check`, and then try with `--check` again.
|
||||||
Automatically verify every build at build time by executing the build
|
Automatically verify every build at build time by executing the build
|
||||||
multiple times.
|
multiple times.
|
||||||
|
|
||||||
Setting [???](#conf-repeat) and [???](#conf-enforce-determinism) in your
|
Setting `repeat` and `enforce-determinism` in your `nix.conf` permits
|
||||||
`nix.conf` permits the automated verification of every build Nix
|
the automated verification of every build Nix performs.
|
||||||
performs.
|
|
||||||
|
|
||||||
The following configuration will run each build three times, and will
|
The following configuration will run each build three times, and will
|
||||||
require the build to be deterministic:
|
require the build to be deterministic:
|
||||||
|
@ -122,9 +120,9 @@ require the build to be deterministic:
|
||||||
enforce-determinism = true
|
enforce-determinism = true
|
||||||
repeat = 2
|
repeat = 2
|
||||||
|
|
||||||
Setting [???](#conf-enforce-determinism) to false as in the following
|
Setting `enforce-determinism` to false as in the following
|
||||||
configuration will run the build multiple times, execute the build hook,
|
configuration will run the build multiple times, execute the build
|
||||||
but will allow the build to succeed even if it does not build
|
hook, but will allow the build to succeed even if it does not build
|
||||||
reproducibly:
|
reproducibly:
|
||||||
|
|
||||||
enforce-determinism = false
|
enforce-determinism = false
|
||||||
|
|
|
@ -17,9 +17,8 @@ the build loop.
|
||||||
|
|
||||||
# Prerequisites
|
# Prerequisites
|
||||||
|
|
||||||
This tutorial assumes you have configured an S3-compatible binary cache
|
This tutorial assumes you have [configured an S3-compatible binary
|
||||||
according to the instructions at
|
cache](../package-management/s3-substituter.md), and that the `root`
|
||||||
[???](#ssec-s3-substituter-authenticated-writes), and that the `root`
|
|
||||||
user's default AWS profile can upload to the bucket.
|
user's default AWS profile can upload to the bucket.
|
||||||
|
|
||||||
# Set up a Signing Key
|
# Set up a Signing Key
|
||||||
|
@ -33,7 +32,7 @@ distribute the public key for verifying the authenticity of the paths.
|
||||||
example-nix-cache-1:1/cKDz3QCCOmwcztD2eV6Coggp6rqc9DGjWv7C0G+rM=
|
example-nix-cache-1:1/cKDz3QCCOmwcztD2eV6Coggp6rqc9DGjWv7C0G+rM=
|
||||||
|
|
||||||
Then, add the public key and the cache URL to your `nix.conf`'s
|
Then, add the public key and the cache URL to your `nix.conf`'s
|
||||||
[???](#conf-trusted-public-keys) and [???](#conf-substituters) like:
|
`trusted-public-keys` and `substituters` options:
|
||||||
|
|
||||||
substituters = https://cache.nixos.org/ s3://example-nix-cache
|
substituters = https://cache.nixos.org/ s3://example-nix-cache
|
||||||
trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= example-nix-cache-1:1/cKDz3QCCOmwcztD2eV6Coggp6rqc9DGjWv7C0G+rM=
|
trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= example-nix-cache-1:1/cKDz3QCCOmwcztD2eV6Coggp6rqc9DGjWv7C0G+rM=
|
||||||
|
|
|
@ -77,8 +77,7 @@ The following settings are currently available:
|
||||||
--optimise` to get rid of duplicate files.
|
--optimise` to get rid of duplicate files.
|
||||||
|
|
||||||
- `builders`
|
- `builders`
|
||||||
A list of machines on which to perform builds. See
|
A list of machines on which to perform builds.
|
||||||
[???](#chap-distributed-builds) for details.
|
|
||||||
|
|
||||||
- `builders-use-substitutes`
|
- `builders-use-substitutes`
|
||||||
If set to `true`, Nix will instruct remote build machines to use
|
If set to `true`, Nix will instruct remote build machines to use
|
||||||
|
@ -141,8 +140,6 @@ The following settings are currently available:
|
||||||
command line switch and defaults to `1`. The value `0` means that
|
command line switch and defaults to `1`. The value `0` means that
|
||||||
the builder should use all available CPU cores in the system.
|
the builder should use all available CPU cores in the system.
|
||||||
|
|
||||||
See also [???](#chap-tuning-cores-and-jobs).
|
|
||||||
|
|
||||||
- `diff-hook`
|
- `diff-hook`
|
||||||
Absolute path to an executable capable of diffing build results. The
|
Absolute path to an executable capable of diffing build results. The
|
||||||
hook executes if [varlistentry\_title](#conf-run-diff-hook) is true,
|
hook executes if [varlistentry\_title](#conf-run-diff-hook) is true,
|
||||||
|
@ -299,8 +296,6 @@ The following settings are currently available:
|
||||||
regardless). It can be overridden using the `--max-jobs` (`-j`)
|
regardless). It can be overridden using the `--max-jobs` (`-j`)
|
||||||
command line switch.
|
command line switch.
|
||||||
|
|
||||||
See also [???](#chap-tuning-cores-and-jobs).
|
|
||||||
|
|
||||||
- `max-silent-time`
|
- `max-silent-time`
|
||||||
This option defines the maximum number of seconds that a builder can
|
This option defines the maximum number of seconds that a builder can
|
||||||
go without producing any data on standard output or standard error.
|
go without producing any data on standard output or standard error.
|
||||||
|
@ -434,8 +429,6 @@ The following settings are currently available:
|
||||||
/nix/store/r7fng3kk3vlpdlh2idnrbn37vh4imlj2-bash-4.4-p23-man
|
/nix/store/r7fng3kk3vlpdlh2idnrbn37vh4imlj2-bash-4.4-p23-man
|
||||||
/nix/store/xfghy8ixrhz3kyy6p724iv3cxji088dx-bash-4.4-p23`.
|
/nix/store/xfghy8ixrhz3kyy6p724iv3cxji088dx-bash-4.4-p23`.
|
||||||
|
|
||||||
See [???](#chap-post-build-hook) for an example implementation.
|
|
||||||
|
|
||||||
- `repeat`
|
- `repeat`
|
||||||
How many times to repeat builds to check whether they are
|
How many times to repeat builds to check whether they are
|
||||||
deterministic. The default value is 0. If the value is non-zero,
|
deterministic. The default value is 0. If the value is non-zero,
|
||||||
|
@ -459,8 +452,7 @@ The following settings are currently available:
|
||||||
`allowed-uri`. The default is `false`.
|
`allowed-uri`. The default is `false`.
|
||||||
|
|
||||||
- `run-diff-hook`
|
- `run-diff-hook`
|
||||||
If true, enable the execution of
|
If true, enable the execution of the `diff-hook` program.
|
||||||
[varlistentry\_title](#conf-diff-hook).
|
|
||||||
|
|
||||||
When using the Nix daemon, `run-diff-hook` must be set in the
|
When using the Nix daemon, `run-diff-hook` must be set in the
|
||||||
`nix.conf` configuration file, and cannot be passed at the command
|
`nix.conf` configuration file, and cannot be passed at the command
|
||||||
|
@ -595,15 +587,11 @@ The following settings are currently available:
|
||||||
Nix will print a log message at the "vomit" level for every function
|
Nix will print a log message at the "vomit" level for every function
|
||||||
entrance and function exit.
|
entrance and function exit.
|
||||||
|
|
||||||
<div class="informalexample">
|
|
||||||
|
|
||||||
function-trace entered undefined position at 1565795816999559622
|
function-trace entered undefined position at 1565795816999559622
|
||||||
function-trace exited undefined position at 1565795816999581277
|
function-trace exited undefined position at 1565795816999581277
|
||||||
function-trace entered /nix/store/.../example.nix:226:41 at 1565795253249935150
|
function-trace entered /nix/store/.../example.nix:226:41 at 1565795253249935150
|
||||||
function-trace exited /nix/store/.../example.nix:226:41 at 1565795253249941684
|
function-trace exited /nix/store/.../example.nix:226:41 at 1565795253249941684
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
The `undefined position` means the function call is a builtin.
|
The `undefined position` means the function call is a builtin.
|
||||||
|
|
||||||
Use the `contrib/stack-collapse.py` script distributed with the Nix
|
Use the `contrib/stack-collapse.py` script distributed with the Nix
|
||||||
|
|
|
@ -46,7 +46,7 @@ expression to a low-level store derivation) and [`nix-store
|
||||||
|
|
||||||
All options not listed here are passed to `nix-store
|
All options not listed here are passed to `nix-store
|
||||||
--realise`, except for `--arg` and `--attr` / `-A` which are passed to
|
--realise`, except for `--arg` and `--attr` / `-A` which are passed to
|
||||||
`nix-instantiate`. See also [???](#sec-common-options).
|
`nix-instantiate`.
|
||||||
|
|
||||||
- `--no-out-link`
|
- `--no-out-link`
|
||||||
Do not create a symlink to the output path. Note that as a result
|
Do not create a symlink to the output path. Note that as a result
|
||||||
|
|
|
@ -13,7 +13,6 @@ Title: nix-channel
|
||||||
A Nix channel is a mechanism that allows you to automatically stay
|
A Nix channel is a mechanism that allows you to automatically stay
|
||||||
up-to-date with a set of pre-built Nix expressions. A Nix channel is
|
up-to-date with a set of pre-built Nix expressions. A Nix channel is
|
||||||
just a URL that points to a place containing a set of Nix expressions.
|
just a URL that points to a place containing a set of Nix expressions.
|
||||||
See also [???](#sec-channels).
|
|
||||||
|
|
||||||
To see the list of official NixOS channels, visit
|
To see the list of official NixOS channels, visit
|
||||||
<https://nixos.org/channels>.
|
<https://nixos.org/channels>.
|
||||||
|
|
|
@ -66,7 +66,7 @@ match. Here are some examples:
|
||||||
|
|
||||||
This section lists the options that are common to all operations. These
|
This section lists the options that are common to all operations. These
|
||||||
options are allowed for every subcommand, though they may not always
|
options are allowed for every subcommand, though they may not always
|
||||||
have an effect. See also [???](#sec-common-options).
|
have an effect.
|
||||||
|
|
||||||
- `--file` / `-f` *path*
|
- `--file` / `-f` *path*
|
||||||
Specifies the Nix expression (designated below as the *active Nix
|
Specifies the Nix expression (designated below as the *active Nix
|
||||||
|
|
|
@ -30,8 +30,6 @@ the resulting store derivations are printed on standard output.
|
||||||
If *files* is the character `-`, then a Nix expression will be read from
|
If *files* is the character `-`, then a Nix expression will be read from
|
||||||
standard input.
|
standard input.
|
||||||
|
|
||||||
See also [???](#sec-common-options) for a list of common options.
|
|
||||||
|
|
||||||
# Options
|
# Options
|
||||||
|
|
||||||
- `--add-root` *path*; `--indirect`
|
- `--add-root` *path*; `--indirect`
|
||||||
|
|
|
@ -50,7 +50,7 @@ will cause `nix-shell` to print `Hello shell`.
|
||||||
|
|
||||||
All options not listed here are passed to `nix-store
|
All options not listed here are passed to `nix-store
|
||||||
--realise`, except for `--arg` and `--attr` / `-A` which are passed to
|
--realise`, except for `--arg` and `--attr` / `-A` which are passed to
|
||||||
`nix-instantiate`. See also [???](#sec-common-options).
|
`nix-instantiate`.
|
||||||
|
|
||||||
- `--command` *cmd*
|
- `--command` *cmd*
|
||||||
In the environment of the derivation, run the shell command *cmd*.
|
In the environment of the derivation, run the shell command *cmd*.
|
||||||
|
|
|
@ -23,16 +23,15 @@ subcommand to be performed. These are documented below.
|
||||||
|
|
||||||
This section lists the options that are common to all operations. These
|
This section lists the options that are common to all operations. These
|
||||||
options are allowed for every subcommand, though they may not always
|
options are allowed for every subcommand, though they may not always
|
||||||
have an effect. See also [???](#sec-common-options) for a list of common
|
have an effect.
|
||||||
options.
|
|
||||||
|
|
||||||
- `--add-root` *path*
|
- `--add-root` *path*
|
||||||
Causes the result of a realisation (`--realise` and
|
Causes the result of a realisation (`--realise` and
|
||||||
`--force-realise`) to be registered as a root of the garbage
|
`--force-realise`) to be registered as a root of the garbage
|
||||||
collector(see [???](#ssec-gc-roots)). The root is stored in *path*,
|
collector. The root is stored in *path*, which must be inside a
|
||||||
which must be inside a directory that is scanned for roots by the
|
directory that is scanned for roots by the garbage collector
|
||||||
garbage collector (i.e., typically in a subdirectory of
|
(i.e., typically in a subdirectory of `/nix/var/nix/gcroots/`)
|
||||||
`/nix/var/nix/gcroots/`) *unless* the `--indirect` flag is used.
|
*unless* the `--indirect` flag is used.
|
||||||
|
|
||||||
If there are multiple results, then multiple symlinks will be
|
If there are multiple results, then multiple symlinks will be
|
||||||
created by sequentially numbering symlinks beyond the first one
|
created by sequentially numbering symlinks beyond the first one
|
||||||
|
@ -209,8 +208,7 @@ The following suboperations may be specified:
|
||||||
|
|
||||||
- `--print-roots`
|
- `--print-roots`
|
||||||
This operation prints on standard output the set of roots used by
|
This operation prints on standard output the set of roots used by
|
||||||
the garbage collector. What constitutes a root is described in
|
the garbage collector.
|
||||||
[???](#ssec-gc-roots).
|
|
||||||
|
|
||||||
- `--print-live`
|
- `--print-live`
|
||||||
This operation prints on standard output the set of “live” store
|
This operation prints on standard output the set of “live” store
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
# Arguments and Variables
|
# Arguments and Variables
|
||||||
|
|
||||||
The Nix expression in [???](#ex-hello-nix) is a function; it is missing
|
The [Nix expression for GNU Hello](expression-syntax.md) is a
|
||||||
some arguments that have to be filled in somewhere. In the Nix Packages
|
function; it is missing some arguments that have to be filled in
|
||||||
collection this is done in the file `pkgs/top-level/all-packages.nix`,
|
somewhere. In the Nix Packages collection this is done in the file
|
||||||
where all Nix expressions for packages are imported and called with the
|
`pkgs/top-level/all-packages.nix`, where all Nix expressions for
|
||||||
appropriate arguments. Here are some fragments of `all-packages.nix`,
|
packages are imported and called with the appropriate arguments. Here
|
||||||
with annotations of what they mean:
|
are some fragments of `all-packages.nix`, with annotations of what
|
||||||
|
they mean:
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
||||||
|
@ -35,9 +36,10 @@ with annotations of what they mean:
|
||||||
|
|
||||||
2. Here we *import* the Nix expression for GNU Hello. The import
|
2. Here we *import* the Nix expression for GNU Hello. The import
|
||||||
operation just loads and returns the specified Nix expression. In
|
operation just loads and returns the specified Nix expression. In
|
||||||
fact, we could just have put the contents of [???](#ex-hello-nix) in
|
fact, we could just have put the contents of the Nix expression
|
||||||
`all-packages.nix` at this point. That would be completely
|
for GNU Hello in `all-packages.nix` at this point. That would be
|
||||||
equivalent, but it would make the file rather bulky.
|
completely equivalent, but it would make `all-packages.nix` rather
|
||||||
|
bulky.
|
||||||
|
|
||||||
Note that we refer to `../applications/misc/hello/ex-1`, not
|
Note that we refer to `../applications/misc/hello/ex-1`, not
|
||||||
`../applications/misc/hello/ex-1/default.nix`. When you try to
|
`../applications/misc/hello/ex-1/default.nix`. When you try to
|
||||||
|
@ -54,7 +56,7 @@ with annotations of what they mean:
|
||||||
The result of this function call is an actual derivation that can be
|
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,
|
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`
|
what we get is its body, which is the call to `stdenv.mkDerivation`
|
||||||
in [???](#ex-hello-nix)).
|
in the [Nix expression for GNU Hello](expression-syntax.md)).
|
||||||
|
|
||||||
> **Note**
|
> **Note**
|
||||||
>
|
>
|
||||||
|
|
|
@ -25,10 +25,10 @@ steps to elucidate what a builder does. It performs the following steps:
|
||||||
|
|
||||||
So the first step is to set up the environment. This is done by
|
So the first step is to set up the environment. This is done by
|
||||||
calling the `setup` script of the standard environment. The
|
calling the `setup` script of the standard environment. The
|
||||||
environment variable `stdenv` points to the location of the standard
|
environment variable `stdenv` points to the location of the
|
||||||
environment being used. (It wasn't specified explicitly as an
|
standard environment being used. (It wasn't specified explicitly
|
||||||
attribute in [???](#ex-hello-nix), but `mkDerivation` adds it
|
as an attribute in Hello's Nix expression, but `mkDerivation` adds
|
||||||
automatically.)
|
it automatically.)
|
||||||
|
|
||||||
2. Since Hello needs Perl, we have to make sure that Perl is in the
|
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
|
`PATH`. The `perl` environment variable points to the location of
|
||||||
|
|
|
@ -1,72 +0,0 @@
|
||||||
# Builder Syntax
|
|
||||||
|
|
||||||
source $stdenv/setup
|
|
||||||
|
|
||||||
PATH=$perl/bin:$PATH
|
|
||||||
|
|
||||||
tar xvfz $src
|
|
||||||
cd hello-*
|
|
||||||
./configure --prefix=$out
|
|
||||||
make
|
|
||||||
make install
|
|
||||||
|
|
||||||
[example\_title](#ex-hello-builder) shows the builder referenced from
|
|
||||||
Hello's Nix expression (stored in
|
|
||||||
`pkgs/applications/misc/hello/ex-1/builder.sh`). 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:
|
|
||||||
|
|
||||||
- When Nix runs a builder, it initially completely clears the
|
|
||||||
environment (except for the attributes declared in the derivation).
|
|
||||||
For instance, the `PATH` variable is empty\[1\]. 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 [???](#ex-hello-nix), but `mkDerivation` adds it
|
|
||||||
automatically.)
|
|
||||||
|
|
||||||
- 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.
|
|
||||||
|
|
||||||
- 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.
|
|
||||||
|
|
||||||
- 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.
|
|
||||||
|
|
||||||
- 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.
|
|
||||||
|
|
||||||
1. Actually, it's initialised to `/path-not-set` to prevent Bash from
|
|
||||||
setting it to a default value.
|
|
|
@ -83,7 +83,7 @@ For instance, `derivation` is also available as `builtins.derivation`.
|
||||||
its elements or attributes are also evaluated recursively.
|
its elements or attributes are also evaluated recursively.
|
||||||
|
|
||||||
- `derivation` *attrs*; `builtins.derivation` *attrs*
|
- `derivation` *attrs*; `builtins.derivation` *attrs*
|
||||||
`derivation` is described in [???](#ssec-derivation).
|
`derivation` is described in [its own section](derivations.md).
|
||||||
|
|
||||||
- `dirOf` *s*; `builtins.dirOf` *s*
|
- `dirOf` *s*; `builtins.dirOf` *s*
|
||||||
Return the directory part of the string *s*, that is, everything
|
Return the directory part of the string *s*, that is, everything
|
||||||
|
@ -233,8 +233,8 @@ For instance, `derivation` is also available as `builtins.derivation`.
|
||||||
|
|
||||||
> **Note**
|
> **Note**
|
||||||
>
|
>
|
||||||
> Nix will refetch the branch in accordance to
|
> Nix will refetch the branch in accordance with
|
||||||
> [???](#conf-tarball-ttl).
|
> the option `tarball-ttl`.
|
||||||
|
|
||||||
> **Note**
|
> **Note**
|
||||||
>
|
>
|
||||||
|
@ -351,19 +351,18 @@ For instance, `derivation` is also available as `builtins.derivation`.
|
||||||
|
|
||||||
- `import` *path*; `builtins.import` *path*
|
- `import` *path*; `builtins.import` *path*
|
||||||
Load, parse and return the Nix expression in the file *path*. If
|
Load, parse and return the Nix expression in the file *path*. If
|
||||||
*path* is a directory, the file ` default.nix
|
*path* is a directory, the file ` default.nix ` in that directory
|
||||||
` in that directory is loaded. Evaluation aborts if the file
|
is loaded. Evaluation aborts if the file doesn’t exist or contains
|
||||||
doesn’t exist or contains an incorrect Nix expression. `import`
|
an incorrect Nix expression. `import` implements Nix’s module
|
||||||
implements Nix’s module system: you can put any Nix expression (such
|
system: you can put any Nix expression (such as a set or a
|
||||||
as a set or a function) in a separate file, and use it from Nix
|
function) in a separate file, and use it from Nix expressions in
|
||||||
expressions in other files.
|
other files.
|
||||||
|
|
||||||
> **Note**
|
> **Note**
|
||||||
>
|
>
|
||||||
> Unlike some languages, `import` is a regular function in Nix.
|
> Unlike some languages, `import` is a regular function in Nix.
|
||||||
> Paths using the angle bracket syntax (e.g., `
|
> Paths using the angle bracket syntax (e.g., `import` *\<foo\>*)
|
||||||
> > > > > import` *\<foo\>*) are normal path values (see
|
> are [normal path values](language-values.md).
|
||||||
> [???](#ssec-values)).
|
|
||||||
|
|
||||||
A Nix expression loaded by `import` must not contain any *free
|
A Nix expression loaded by `import` must not contain any *free
|
||||||
variables* (identifiers that are not defined in the Nix expression
|
variables* (identifiers that are not defined in the Nix expression
|
||||||
|
@ -643,11 +642,12 @@ For instance, `derivation` is also available as `builtins.derivation`.
|
||||||
(which is not the case for `abort`).
|
(which is not the case for `abort`).
|
||||||
|
|
||||||
- `builtins.toFile` *name* *s*
|
- `builtins.toFile` *name* *s*
|
||||||
Store the string *s* in a file in the Nix store and return its path.
|
Store the string *s* in a file in the Nix store and return its
|
||||||
The file has suffix *name*. This file can be used as an input to
|
path. The file has suffix *name*. This file can be used as an
|
||||||
derivations. One application is to write builders “inline”. For
|
input to derivations. One application is to write builders
|
||||||
instance, the following Nix expression combines [???](#ex-hello-nix)
|
“inline”. For instance, the following Nix expression combines the
|
||||||
and [???](#ex-hello-builder) into one file:
|
[Nix expression for GNU Hello](expression-syntax.md) and its
|
||||||
|
[build script](build-script.md) into one file:
|
||||||
|
|
||||||
{ stdenv, fetchurl, perl }:
|
{ stdenv, fetchurl, perl }:
|
||||||
|
|
||||||
|
@ -688,8 +688,9 @@ For instance, `derivation` is also available as `builtins.derivation`.
|
||||||
";
|
";
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that `${configFile}` is an antiquotation (see
|
Note that `${configFile}` is an
|
||||||
[???](#ssec-values)), so the result of the expression `configFile`
|
[antiquotation](language-values.md), so the result of the
|
||||||
|
expression `configFile`
|
||||||
(i.e., a path like `/nix/store/m7p7jfny445k...-foo.conf`) will be
|
(i.e., a path like `/nix/store/m7p7jfny445k...-foo.conf`) will be
|
||||||
spliced into the resulting string.
|
spliced into the resulting string.
|
||||||
|
|
||||||
|
@ -786,17 +787,17 @@ For instance, `derivation` is also available as `builtins.derivation`.
|
||||||
container contains a number of servlets (`*.war` files) each
|
container contains a number of servlets (`*.war` files) each
|
||||||
exported under a specific URI prefix. So the servlet configuration
|
exported under a specific URI prefix. So the servlet configuration
|
||||||
is a list of sets containing the `path` and `war` of the servlet
|
is a list of sets containing the `path` and `war` of the servlet
|
||||||
([???](#ex-toxml-co-servlets)). This kind of information is
|
(①). This kind of information is difficult to communicate with the
|
||||||
difficult to communicate with the normal method of passing
|
normal method of passing information through an environment
|
||||||
information through an environment variable, which just concatenates
|
variable, which just concatenates everything together into a
|
||||||
everything together into a string (which might just work in this
|
string (which might just work in this case, but wouldn’t work if
|
||||||
case, but wouldn’t work if fields are optional or contain lists
|
fields are optional or contain lists themselves). Instead the Nix
|
||||||
themselves). Instead the Nix expression is converted to an XML
|
expression is converted to an XML representation with `toXML`,
|
||||||
representation with `toXML`, which is unambiguous and can easily be
|
which is unambiguous and can easily be processed with the
|
||||||
processed with the appropriate tools. For instance, in the example
|
appropriate tools. For instance, in the example an XSLT stylesheet
|
||||||
an XSLT stylesheet (at point ②) is applied to it (at point ①) to
|
(at point ②) is applied to it (at point ①) to generate the XML
|
||||||
generate the XML configuration file for the Jetty server. The XML
|
configuration file for the Jetty server. The XML representation
|
||||||
representation produced at point ③ by `toXML` is as follows:
|
produced at point ③ by `toXML` is as follows:
|
||||||
|
|
||||||
<?xml version='1.0' encoding='utf-8'?>
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
<expr>
|
<expr>
|
||||||
|
@ -820,10 +821,10 @@ For instance, `derivation` is also available as `builtins.derivation`.
|
||||||
</list>
|
</list>
|
||||||
</expr>
|
</expr>
|
||||||
|
|
||||||
Note that [???](#ex-toxml) uses the `toFile` built-in to write the
|
Note that we used the `toFile` built-in to write the builder and
|
||||||
builder and the stylesheet “inline” in the Nix expression. The path
|
the stylesheet “inline” in the Nix expression. The path of the
|
||||||
of the stylesheet is spliced into the builder using the syntax
|
stylesheet is spliced into the builder using the syntax `xsltproc
|
||||||
`xsltproc ${stylesheet}`.
|
${stylesheet}`.
|
||||||
|
|
||||||
- `builtins.trace` *e1* *e2*
|
- `builtins.trace` *e1* *e2*
|
||||||
Evaluate *e1* and print its abstract syntax representation on
|
Evaluate *e1* and print its abstract syntax representation on
|
||||||
|
|
|
@ -9,8 +9,9 @@ the attributes of which specify the inputs of the build.
|
||||||
`"x86_64-darwin"`. (To figure out your system type, run `nix -vv
|
`"x86_64-darwin"`. (To figure out your system type, run `nix -vv
|
||||||
--version`.) The build can only be performed on a machine and
|
--version`.) The build can only be performed on a machine and
|
||||||
operating system matching the system type. (Nix can automatically
|
operating system matching the system type. (Nix can automatically
|
||||||
forward builds for other platforms by forwarding them to other
|
[forward builds for other
|
||||||
machines; see [???](#chap-distributed-builds).)
|
platforms](../advanced-topics/distributed-builds.md) by forwarding
|
||||||
|
them to other machines.)
|
||||||
|
|
||||||
- There must be an attribute named `name` whose value must be a
|
- There must be an attribute named `name` whose value must be a
|
||||||
string. This is used as a symbolic name for the package by
|
string. This is used as a symbolic name for the package by
|
||||||
|
|
|
@ -61,9 +61,10 @@ elements (referenced from the figure by number):
|
||||||
sometimes be omitted, in which case `mkDerivation` will fill in a
|
sometimes be omitted, in which case `mkDerivation` will fill in a
|
||||||
default builder (which does a `configure; make; make install`, in
|
default builder (which does a `configure; make; make install`, in
|
||||||
essence). Hello is sufficiently simple that the default builder
|
essence). Hello is sufficiently simple that the default builder
|
||||||
would suffice, but in this case, we will show an actual builder for
|
would suffice, but in this case, we will show an actual builder
|
||||||
educational purposes. The value `./builder.sh` refers to the shell
|
for educational purposes. The value `./builder.sh` refers to the
|
||||||
script shown in [???](#ex-hello-builder), discussed below.
|
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,
|
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
|
the attribute `src` is bound to the result of a call to the
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# Generic Builder Syntax
|
# Generic Builder Syntax
|
||||||
|
|
||||||
Recall from [???](#ex-hello-builder) that the builder looked something
|
Recall that the [build script for GNU Hello](build-script.md) looked
|
||||||
like this:
|
something like this:
|
||||||
|
|
||||||
PATH=$perl/bin:$PATH
|
PATH=$perl/bin:$PATH
|
||||||
tar xvfz $src
|
tar xvfz $src
|
||||||
|
@ -37,11 +37,10 @@ Here is what each line means:
|
||||||
2. The function `genericBuild` is defined in the file `$stdenv/setup`.
|
2. The function `genericBuild` is defined in the file `$stdenv/setup`.
|
||||||
|
|
||||||
3. The final step calls the shell function `genericBuild`, which
|
3. The final step calls the shell function `genericBuild`, which
|
||||||
performs the steps that were done explicitly in
|
performs the steps that were done explicitly in the previous build
|
||||||
[???](#ex-hello-builder). The generic builder is smart enough to
|
script. The generic builder is smart enough to figure out whether
|
||||||
figure out whether to unpack the sources using `gzip`, `bzip2`, etc.
|
to unpack the sources using `gzip`, `bzip2`, etc. It can be
|
||||||
It can be customised in many ways; see the Nixpkgs manual for
|
customised in many ways; see the Nixpkgs manual for details.
|
||||||
details.
|
|
||||||
|
|
||||||
Discerning readers will note that the `buildInputs` could just as well
|
Discerning readers will note that the `buildInputs` could just as well
|
||||||
have been set in the Nix expression, like this:
|
have been set in the Nix expression, like this:
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
# Operators
|
# Operators
|
||||||
|
|
||||||
[table\_title](#table-operators) lists the operators in the Nix
|
The table below lists the operators in the Nix expression language, in
|
||||||
expression language, in order of precedence (from strongest to weakest
|
order of precedence (from strongest to weakest binding).
|
||||||
binding).
|
|
||||||
|
|
||||||
| Name | Syntax | Associativity | Description | Precedence |
|
| Name | Syntax | Associativity | Description | Precedence |
|
||||||
| ------------------------ | ----------------------------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
|
| ------------------------ | ----------------------------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
|
||||||
|
@ -28,5 +27,3 @@ binding).
|
||||||
| Logical OR | *e1* `\|\|` *e2* | left | Logical OR. | 13 |
|
| Logical OR | *e1* `\|\|` *e2* | left | Logical OR. | 13 |
|
||||||
| Logical Implication | *e1* `->` *e2* | none | Logical implication (equivalent to `!e1 \|\|
|
| Logical Implication | *e1* `->` *e2* | none | Logical implication (equivalent to `!e1 \|\|
|
||||||
e2`). | 14 |
|
e2`). | 14 |
|
||||||
|
|
||||||
Operators
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
- derivation
|
- derivation
|
||||||
A description of a build action. The result of a derivation is a
|
A description of a build action. The result of a derivation is a
|
||||||
store object. Derivations are typically specified in Nix expressions
|
store object. Derivations are typically specified in Nix expressions
|
||||||
using the [`derivation` primitive](#ssec-derivation). These are
|
using the [`derivation` primitive](expressions/derivations.md). These are
|
||||||
translated into low-level *store derivations* (implicitly by
|
translated into low-level *store derivations* (implicitly by
|
||||||
`nix-env` and `nix-build`, or explicitly by `nix-instantiate`).
|
`nix-env` and `nix-build`, or explicitly by `nix-instantiate`).
|
||||||
|
|
||||||
|
@ -53,20 +53,19 @@
|
||||||
paths.
|
paths.
|
||||||
|
|
||||||
- reachable
|
- reachable
|
||||||
A store path `Q` is reachable from another store path `P` if `Q` is
|
A store path `Q` is reachable from another store path `P` if `Q`
|
||||||
in the [closure](#gloss-closure) of the
|
is in the *closure* of the *references* relation.
|
||||||
[references](#gloss-reference) relation.
|
|
||||||
|
|
||||||
- closure
|
- closure
|
||||||
The closure of a store path is the set of store paths that are
|
The closure of a store path is the set of store paths that are
|
||||||
directly or indirectly “reachable” from that store path; that is,
|
directly or indirectly “reachable” from that store path; that is,
|
||||||
it’s the closure of the path under the
|
it’s the closure of the path under the *references* relation. For
|
||||||
[references](#gloss-reference) relation. For a package, the closure
|
a package, the closure of its derivation is equivalent to the
|
||||||
of its derivation is equivalent to the build-time dependencies,
|
build-time dependencies, while the closure of its output path is
|
||||||
while the closure of its output path is equivalent to its runtime
|
equivalent to its runtime dependencies. For correct deployment it
|
||||||
dependencies. For correct deployment it is necessary to deploy whole
|
is necessary to deploy whole closures, since otherwise at runtime
|
||||||
closures, since otherwise at runtime files could be missing. The
|
files could be missing. The command `nix-store -qR` prints out
|
||||||
command `nix-store -qR` prints out closures of store paths.
|
closures of store paths.
|
||||||
|
|
||||||
As an example, if the store object at path `P` contains a reference
|
As an example, if the store object at path `P` contains a reference
|
||||||
to path `Q`, then `Q` is in the closure of `P`. Further, if `Q`
|
to path `Q`, then `Q` is in the closure of `P`. Further, if `Q`
|
||||||
|
@ -76,7 +75,7 @@
|
||||||
A store path produced by a derivation.
|
A store path produced by a derivation.
|
||||||
|
|
||||||
- deriver
|
- deriver
|
||||||
The deriver of an [output path](#gloss-output-path) is the store
|
The deriver of an *output path* is the store
|
||||||
derivation that built it.
|
derivation that built it.
|
||||||
|
|
||||||
- validity
|
- validity
|
||||||
|
@ -87,16 +86,15 @@
|
||||||
- user environment
|
- user environment
|
||||||
An automatically generated store object that consists of a set of
|
An automatically generated store object that consists of a set of
|
||||||
symlinks to “active” applications, i.e., other store paths. These
|
symlinks to “active” applications, i.e., other store paths. These
|
||||||
are generated automatically by [`nix-env`](#sec-nix-env). See
|
are generated automatically by
|
||||||
[???](#sec-profiles).
|
[`nix-env`](command-ref/nix-env.md). See *profiles*.
|
||||||
|
|
||||||
- profile
|
- profile
|
||||||
A symlink to the current [user environment](#gloss-user-env) of a
|
A symlink to the current *user environment* of a user, e.g.,
|
||||||
user, e.g., `/nix/var/nix/profiles/default`.
|
`/nix/var/nix/profiles/default`.
|
||||||
|
|
||||||
- NAR
|
- NAR
|
||||||
A *N*ix *AR*chive. This is a serialisation of a path in the Nix
|
A *N*ix *AR*chive. This is a serialisation of a path in the Nix
|
||||||
store. It can contain regular files, directories and symbolic links.
|
store. It can contain regular files, directories and symbolic
|
||||||
NARs are generated and unpacked using `nix-store --dump` and
|
links. NARs are generated and unpacked using `nix-store --dump`
|
||||||
`nix-store
|
and `nix-store --restore`.
|
||||||
--restore`.
|
|
||||||
|
|
|
@ -24,11 +24,11 @@ or completely new ones.)
|
||||||
|
|
||||||
You can manually download the latest version of Nixpkgs from
|
You can manually download the latest version of Nixpkgs from
|
||||||
<http://nixos.org/nixpkgs/download.html>. However, it’s much more
|
<http://nixos.org/nixpkgs/download.html>. However, it’s much more
|
||||||
convenient to use the Nixpkgs *channel*, since it makes it easy to stay
|
convenient to use the Nixpkgs [*channel*](channels.md), since it makes
|
||||||
up to date with new versions of Nixpkgs. (Channels are described in more
|
it easy to stay up to date with new versions of Nixpkgs. Nixpkgs is
|
||||||
detail in [???](#sec-channels).) Nixpkgs is automatically added to your
|
automatically added to your list of “subscribed” channels when you
|
||||||
list of “subscribed” channels when you install Nix. If this is not the
|
install Nix. If this is not the case for some reason, you can add it
|
||||||
case for some reason, you can add it as follows:
|
as follows:
|
||||||
|
|
||||||
$ nix-channel --add https://nixos.org/channels/nixpkgs-unstable
|
$ nix-channel --add https://nixos.org/channels/nixpkgs-unstable
|
||||||
$ nix-channel --update
|
$ nix-channel --update
|
||||||
|
|
|
@ -8,7 +8,7 @@ dependencies:
|
||||||
|
|
||||||
$ nix-copy-closure --to alice@itchy.example.org $(type -p firefox)
|
$ nix-copy-closure --to alice@itchy.example.org $(type -p firefox)
|
||||||
|
|
||||||
See [???](#sec-nix-copy-closure) for details.
|
See the [manpage for `nix-copy-closure`](../command-ref/nix-copy-closure.md) for details.
|
||||||
|
|
||||||
With `nix-store
|
With `nix-store
|
||||||
--export` and `nix-store --import` you can write the closure of a store
|
--export` and `nix-store --import` you can write the closure of a store
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
This chapter discusses how to do package management with Nix, i.e., how
|
This chapter discusses how to do package management with Nix, i.e.,
|
||||||
to obtain, install, upgrade, and erase packages. This is the “user’s”
|
how to obtain, install, upgrade, and erase packages. This is the
|
||||||
perspective of the Nix system — people who want to *create* packages
|
“user’s” perspective of the Nix system — people who want to *create*
|
||||||
should consult [???](#chap-writing-nix-expressions).
|
packages should consult the [chapter on writing Nix
|
||||||
|
expressions](../expressions/writing-nix-expressions.md).
|
||||||
|
|
|
@ -104,8 +104,7 @@ These commands switch to the `my-profile` and default profile,
|
||||||
respectively. If the profile doesn’t exist, it will be created
|
respectively. If the profile doesn’t exist, it will be created
|
||||||
automatically. You should be careful about storing a profile in another
|
automatically. You should be careful about storing a profile in another
|
||||||
location than the `profiles` directory, since otherwise it might not be
|
location than the `profiles` directory, since otherwise it might not be
|
||||||
used as a root of the garbage collector (see
|
used as a root of the [garbage collector](garbage-collection.md).
|
||||||
[???](#sec-garbage-collection)).
|
|
||||||
|
|
||||||
All `nix-env` operations work on the profile pointed to by
|
All `nix-env` operations work on the profile pointed to by
|
||||||
`~/.nix-profile`, but you can override this using the `--profile` option
|
`~/.nix-profile`, but you can override this using the `--profile` option
|
||||||
|
|
Loading…
Reference in a new issue