2021-01-01 17:45:43 +00:00
# Rust {#rust}
2017-03-20 19:41:37 +00:00
To install the rust compiler and cargo put
2021-03-13 23:30:36 +00:00
```nix
environment.systemPackages = [
rustc
cargo
];
2017-03-20 19:41:37 +00:00
```
2021-03-13 23:30:36 +00:00
into your `configuration.nix` or bring them into scope with `nix-shell -p rustc cargo` .
2017-03-20 19:41:37 +00:00
2020-08-11 11:21:25 +01:00
For other versions such as daily builds (beta and nightly),
use either `rustup` from nixpkgs (which will manage the rust installation in your home directory),
or use Mozilla's [Rust nightlies overlay ](#using-the-rust-nightlies-overlay ).
2017-03-20 19:41:37 +00:00
2021-06-05 20:22:45 +01:00
## Compiling Rust applications with Cargo {#compiling-rust-applications-with-cargo}
2017-03-20 19:41:37 +00:00
Rust applications are packaged by using the `buildRustPackage` helper from `rustPlatform` :
2021-03-13 23:30:36 +00:00
```nix
2021-09-19 14:29:06 +01:00
{ lib, fetchFromGitHub, rustPlatform }:
2021-01-21 00:07:16 +00:00
2017-11-17 07:26:51 +00:00
rustPlatform.buildRustPackage rec {
2020-01-12 17:19:57 +00:00
pname = "ripgrep";
2020-12-03 08:39:39 +00:00
version = "12.1.1";
2017-03-20 19:41:37 +00:00
src = fetchFromGitHub {
owner = "BurntSushi";
2020-01-12 17:19:57 +00:00
repo = pname;
rev = version;
2020-12-03 08:39:39 +00:00
sha256 = "1hqps7l5qrjh9f914r5i6kmcz6f1yb951nv4lby0cjnp5l253kps";
2017-03-20 19:41:37 +00:00
};
2020-12-03 08:39:39 +00:00
cargoSha256 = "03wf9r2csi6jpa7v5sw5lpxkrk4wfzwmzx7k3991q3bdjzcwnnwp";
2017-03-20 19:41:37 +00:00
2021-01-10 21:30:22 +00:00
meta = with lib; {
2017-11-17 07:26:51 +00:00
description = "A fast line-oriented regex search tool, similar to ag and ack";
2020-02-16 16:31:03 +00:00
homepage = "https://github.com/BurntSushi/ripgrep";
2017-11-17 07:26:51 +00:00
license = licenses.unlicense;
2017-03-20 19:41:37 +00:00
maintainers = [ maintainers.tailhook ];
};
}
```
2020-12-03 08:39:39 +00:00
`buildRustPackage` requires either the `cargoSha256` or the
`cargoHash` attribute which is computed over all crate sources of this
package. `cargoHash256` is used for traditional Nix SHA-256 hashes,
such as the one in the example above. `cargoHash` should instead be
used for [SRI ](https://www.w3.org/TR/SRI/ ) hashes. For example:
2021-03-13 23:30:36 +00:00
```nix
2020-12-03 08:39:39 +00:00
cargoHash = "sha256-l1vL2ZdtDRxSGvP0X/l3nMw8+6WF67KPutJEzUROjg8=";
```
Both types of hashes are permitted when contributing to nixpkgs. The
Cargo hash is obtained by inserting a fake checksum into the
expression and building the package once. The correct checksum can
then be taken from the failed build. A fake hash can be used for
`cargoSha256` as follows:
2021-03-13 23:30:36 +00:00
```nix
2021-01-10 21:30:22 +00:00
cargoSha256 = lib.fakeSha256;
2020-12-03 08:39:39 +00:00
```
For `cargoHash` you can use:
2021-03-13 23:30:36 +00:00
```nix
2021-01-10 21:30:22 +00:00
cargoHash = lib.fakeHash;
2020-12-03 08:39:39 +00:00
```
2017-03-20 19:41:37 +00:00
2020-02-16 07:33:02 +00:00
Per the instructions in the [Cargo Book ](https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html )
best practices guide, Rust applications should always commit the `Cargo.lock`
file in git to ensure a reproducible build. However, a few packages do not, and
2021-02-24 08:25:49 +00:00
Nix depends on this file, so if it is missing you can use `cargoPatches` to
apply it in the `patchPhase` . Consider sending a PR upstream with a note to the
2020-02-16 07:33:02 +00:00
maintainer describing why it's important to include in the application.
2018-08-14 03:20:30 +01:00
2020-03-19 00:43:07 +00:00
The fetcher will verify that the `Cargo.lock` file is in sync with the `src`
attribute, and fail the build if not. It will also will compress the vendor
directory into a tar.gz archive.
2019-08-24 13:29:47 +01:00
2021-02-15 06:06:31 +00:00
The tarball with vendored dependencies contains a directory with the
package's `name` , which is normally composed of `pname` and
`version` . This means that the vendored dependencies hash
(`cargoSha256`/`cargoHash`) is dependent on the package name and
version. The `cargoDepsName` attribute can be used to use another name
for the directory of vendored dependencies. For example, the hash can
be made invariant to the version by setting `cargoDepsName` to
`pname` :
```nix
rustPlatform.buildRustPackage rec {
pname = "broot";
version = "1.2.0";
src = fetchCrate {
inherit pname version;
sha256 = "1mqaynrqaas82f5957lx31x80v74zwmwmjxxlbywajb61vh00d38";
};
cargoHash = "sha256-JmBZcDVYJaK1cK05cxx5BrnGWp4t8ca6FLUbvIot67s=";
cargoDepsName = pname;
# ...
}
```
2021-06-05 20:22:45 +01:00
### Importing a `Cargo.lock` file {#importing-a-cargo.lock-file}
2021-05-08 06:44:31 +01:00
Using `cargoSha256` or `cargoHash` is tedious when using
`buildRustPackage` within a project, since it requires that the hash
is updated after every change to `Cargo.lock` . Therefore,
`buildRustPackage` also supports vendoring dependencies directly from
a `Cargo.lock` file using the `cargoLock` argument. For example:
```nix
2021-09-22 11:20:24 +01:00
rustPlatform.buildRustPackage {
2021-05-08 06:44:31 +01:00
pname = "myproject";
version = "1.0.0";
cargoLock = {
lockFile = ./Cargo.lock;
2021-09-21 12:48:25 +01:00
};
2021-05-08 06:44:31 +01:00
# ...
}
```
This will retrieve the dependencies using fixed-output derivations from
2021-09-21 12:48:25 +01:00
the specified lockfile.
2021-09-22 11:51:05 +01:00
One caveat is that `Cargo.lock` cannot be patched in the `patchPhase`
because it runs after the dependencies have already been fetched. If
you need to patch or generate the lockfile you can alternatively set
`cargoLock.lockFileContents` to a string of its contents:
2021-09-21 12:48:25 +01:00
```nix
2021-09-22 11:20:24 +01:00
rustPlatform.buildRustPackage {
2021-09-21 12:48:25 +01:00
pname = "myproject";
version = "1.0.0";
cargoLock = let
2021-09-21 13:58:40 +01:00
fixupLockFile = path: f (builtins.readFile path);
2021-09-21 12:48:25 +01:00
in {
lockFileContents = fixupLockFile ./Cargo.lock;
};
# ...
}
```
Note that setting `cargoLock.lockFile` or `cargoLock.lockFileContents`
doesn't add a `Cargo.lock` to your `src` , and a `Cargo.lock` is still
required to build a rust package. A simple fix is to use:
2021-08-01 22:01:13 +01:00
```nix
postPatch = ''
cp ${./Cargo.lock} Cargo.lock
'';
```
2021-05-08 06:44:31 +01:00
The output hash of each dependency that uses a git source must be
specified in the `outputHashes` attribute. For example:
```nix
rustPlatform.buildRustPackage rec {
pname = "myproject";
version = "1.0.0";
cargoLock = {
lockFile = ./Cargo.lock;
outputHashes = {
"finalfusion-0.14.0" = "17f4bsdzpcshwh74w5z119xjy2if6l2wgyjy56v621skr2r8y904";
};
2021-07-30 09:37:25 +01:00
};
2021-05-08 06:44:31 +01:00
# ...
}
```
If you do not specify an output hash for a git dependency, building
the package will fail and inform you of which crate needs to be
added. To find the correct hash, you can first use `lib.fakeSha256` or
`lib.fakeHash` as a stub hash. Building the package (and thus the
vendored dependencies) will then inform you of the correct hash.
2021-02-15 06:06:31 +00:00
2021-06-05 20:22:45 +01:00
### Cross compilation {#cross-compilation}
2020-10-14 04:37:29 +01:00
By default, Rust packages are compiled for the host platform, just like any
other package is. The `--target` passed to rust tools is computed from this.
By default, it takes the `stdenv.hostPlatform.config` and replaces components
where they are known to differ. But there are ways to customize the argument:
- To choose a different target by name, define
2020-11-28 19:32:43 +00:00
`stdenv.hostPlatform.rustc.config` as that name (a string), and that
2020-10-14 04:37:29 +01:00
name will be used instead.
For example:
2021-06-05 20:22:45 +01:00
2020-10-14 04:37:29 +01:00
```nix
import < nixpkgs > {
crossSystem = (import < nixpkgs / lib > ).systems.examples.armhf-embedded // {
2020-11-28 19:32:43 +00:00
rustc.config = "thumbv7em-none-eabi";
2020-10-14 04:37:29 +01:00
};
}
```
2021-06-05 20:22:45 +01:00
2020-10-14 04:37:29 +01:00
will result in:
2021-06-05 20:22:45 +01:00
2020-10-14 04:37:29 +01:00
```shell
--target thumbv7em-none-eabi
```
- To pass a completely custom target, define
2020-11-28 19:32:43 +00:00
`stdenv.hostPlatform.rustc.config` with its name, and
`stdenv.hostPlatform.rustc.platform` with the value. The value will be
2020-10-14 04:37:29 +01:00
serialized to JSON in a file called
2020-11-28 19:32:43 +00:00
`${stdenv.hostPlatform.rustc.config}.json` , and the path of that file
2020-10-14 04:37:29 +01:00
will be used instead.
For example:
2021-06-05 20:22:45 +01:00
2020-10-14 04:37:29 +01:00
```nix
import < nixpkgs > {
crossSystem = (import < nixpkgs / lib > ).systems.examples.armhf-embedded // {
2020-11-28 19:32:43 +00:00
rustc.config = "thumb-crazy";
rustc.platform = { foo = ""; bar = ""; };
2020-10-14 04:37:29 +01:00
};
}
2021-02-24 08:25:49 +00:00
```
2021-06-05 20:22:45 +01:00
2020-10-14 04:37:29 +01:00
will result in:
2021-06-05 20:22:45 +01:00
2020-10-14 04:37:29 +01:00
```shell
--target /nix/store/asdfasdfsadf-thumb-crazy.json # contains {"foo":"","bar":""}
```
2020-10-17 08:48:07 +01:00
Note that currently custom targets aren't compiled with `std` , so `cargo test`
will fail. This can be ignored by adding `doCheck = false;` to your derivation.
2021-06-05 20:22:45 +01:00
### Running package tests {#running-package-tests}
2020-05-24 17:37:34 +01:00
When using `buildRustPackage` , the `checkPhase` is enabled by default and runs
`cargo test` on the package to build. To make sure that we don't compile the
2020-07-31 06:06:53 +01:00
sources twice and to actually test the artifacts that will be used at runtime,
2020-05-31 19:47:32 +01:00
the tests will be ran in the `release` mode by default.
2020-05-24 17:37:34 +01:00
However, in some cases the test-suite of a package doesn't work properly in the
2020-05-31 19:47:32 +01:00
`release` mode. For these situations, the mode for `checkPhase` can be changed like
so:
2020-05-24 17:37:34 +01:00
```nix
rustPlatform.buildRustPackage {
/* ... */
checkType = "debug";
}
```
2020-05-31 19:47:32 +01:00
Please note that the code will be compiled twice here: once in `release` mode
for the `buildPhase` , and again in `debug` mode for the `checkPhase` .
2020-05-24 17:37:34 +01:00
2021-02-24 08:32:22 +00:00
Test flags, e.g., `--features xxx/yyy` , can be passed to `cargo test` via the
`cargoTestFlags` attribute.
Another attribute, called `checkFlags` , is used to pass arguments to the test
binary itself, as stated
(here)[https://doc.rust-lang.org/cargo/commands/cargo-test.html].
2021-06-05 20:22:45 +01:00
#### Tests relying on the structure of the `target/` directory {#tests-relying-on-the-structure-of-the-target-directory}
2020-05-31 19:47:32 +01:00
Some tests may rely on the structure of the `target/` directory. Those tests
are likely to fail because we use `cargo --target` during the build. This means that
2020-05-24 17:37:34 +01:00
the artifacts
2020-05-31 19:47:32 +01:00
[are stored in `target/<architecture>/release/` ](https://doc.rust-lang.org/cargo/guide/build-cache.html ),
rather than in `target/release/` .
2020-05-24 17:37:34 +01:00
2020-05-31 19:47:32 +01:00
This can only be worked around by patching the affected tests accordingly.
2020-05-24 17:37:34 +01:00
2021-06-05 20:22:45 +01:00
#### Disabling package-tests {#disabling-package-tests}
2020-05-24 17:37:34 +01:00
2020-05-31 19:47:32 +01:00
In some instances, it may be necessary to disable testing altogether (with `doCheck = false;` ):
2020-05-24 17:37:34 +01:00
2020-05-31 19:47:32 +01:00
* If no tests exist -- the `checkPhase` should be explicitly disabled to skip
unnecessary build steps to speed up the build.
* If tests are highly impure (e.g. due to network usage).
2020-05-24 17:37:34 +01:00
2020-05-31 19:47:32 +01:00
There will obviously be some corner-cases not listed above where it's sensible to disable tests.
The above are just guidelines, and exceptions may be granted on a case-by-case basis.
2020-05-24 17:37:34 +01:00
2020-05-31 19:47:32 +01:00
However, please check if it's possible to disable a problematic subset of the
test suite and leave a comment explaining your reasoning.
2020-05-24 17:37:34 +01:00
2021-06-05 20:22:45 +01:00
#### Setting `test-threads` {#setting-test-threads}
2020-09-09 12:39:23 +01:00
`buildRustPackage` will use parallel test threads by default,
sometimes it may be necessary to disable this so the tests run consecutively.
```nix
rustPlatform.buildRustPackage {
/* ... */
2021-02-15 09:26:40 +00:00
dontUseCargoParallelTests = true;
2020-09-09 12:39:23 +01:00
}
```
2021-06-05 20:22:45 +01:00
### Building a package in `debug` mode {#building-a-package-in-debug-mode}
2020-05-24 17:37:34 +01:00
2020-05-31 19:47:32 +01:00
By default, `buildRustPackage` will use `release` mode for builds. If a package
should be built in `debug` mode, it can be configured like so:
2020-05-24 17:37:34 +01:00
```nix
rustPlatform.buildRustPackage {
/* ... */
buildType = "debug";
}
```
2020-05-31 19:47:32 +01:00
In this scenario, the `checkPhase` will be ran in `debug` mode as well.
2020-05-24 17:37:34 +01:00
2021-06-05 20:22:45 +01:00
### Custom `build`/`install`-procedures {#custom-buildinstall-procedures}
2020-05-24 17:37:34 +01:00
Some packages may use custom scripts for building/installing, e.g. with a `Makefile` .
2020-05-31 19:47:32 +01:00
In these cases, it's recommended to override the `buildPhase` /`installPhase`/`checkPhase`.
2020-05-24 17:37:34 +01:00
2020-05-31 19:47:32 +01:00
Otherwise, some steps may fail because of the modified directory structure of `target/` .
2020-05-24 17:37:34 +01:00
2021-06-05 20:22:45 +01:00
### Building a crate with an absent or out-of-date Cargo.lock file {#building-a-crate-with-an-absent-or-out-of-date-cargo.lock-file}
2020-06-05 08:10:53 +01:00
`buildRustPackage` needs a `Cargo.lock` file to get all dependencies in the
source code in a reproducible way. If it is missing or out-of-date one can use
the `cargoPatches` attribute to update or add it.
2021-03-13 23:30:36 +00:00
```nix
2020-06-05 08:10:53 +01:00
rustPlatform.buildRustPackage rec {
(...)
cargoPatches = [
# a patch file to add/update Cargo.lock in the source code
./add-Cargo.lock.patch
];
}
```
2021-06-05 20:22:45 +01:00
## Compiling non-Rust packages that include Rust code {#compiling-non-rust-packages-that-include-rust-code}
2021-02-09 12:46:32 +00:00
Several non-Rust packages incorporate Rust code for performance- or
security-sensitive parts. `rustPlatform` exposes several functions and
hooks that can be used to integrate Cargo in non-Rust packages.
2021-06-05 20:22:45 +01:00
### Vendoring of dependencies {#vendoring-of-dependencies}
2021-02-09 12:46:32 +00:00
Since network access is not allowed in sandboxed builds, Rust crate
dependencies need to be retrieved using a fetcher. `rustPlatform`
provides the `fetchCargoTarball` fetcher, which vendors all
2021-02-12 07:35:50 +00:00
dependencies of a crate. For example, given a source path `src`
containing `Cargo.toml` and `Cargo.lock` , `fetchCargoTarball`
can be used as follows:
```nix
cargoDeps = rustPlatform.fetchCargoTarball {
inherit src;
hash = "sha256-BoHIN/519Top1NUBjpB/oEMqi86Omt3zTQcXFWqrek0=";
};
```
The `src` attribute is required, as well as a hash specified through
one of the `sha256` or `hash` attributes. The following optional
attributes can also be used:
* `name` : the name that is used for the dependencies tarball. If
`name` is not specified, then the name `cargo-deps` will be used.
* `sourceRoot` : when the `Cargo.lock` /`Cargo.toml` are in a
subdirectory, `sourceRoot` specifies the relative path to these
files.
* `patches` : patches to apply before vendoring. This is useful when
the `Cargo.lock` /`Cargo.toml` files need to be patched before
vendoring.
2021-05-08 06:40:34 +01:00
If a `Cargo.lock` file is available, you can alternatively use the
`importCargoLock` function. In contrast to `fetchCargoTarball` , this
function does not require a hash (unless git dependencies are used)
and fetches every dependency as a separate fixed-output derivation.
`importCargoLock` can be used as follows:
```
cargoDeps = rustPlatform.importCargoLock {
lockFile = ./Cargo.lock;
};
```
If the `Cargo.lock` file includes git dependencies, then their output
hashes need to be specified since they are not available through the
lock file. For example:
```
2021-06-01 12:14:28 +01:00
cargoDeps = rustPlatform.importCargoLock {
2021-05-08 06:40:34 +01:00
lockFile = ./Cargo.lock;
outputHashes = {
"rand-0.8.3" = "0ya2hia3cn31qa8894s3av2s8j5bjwb6yq92k0jsnlx7jid0jwqa";
};
};
```
If you do not specify an output hash for a git dependency, building
`cargoDeps` will fail and inform you of which crate needs to be
added. To find the correct hash, you can first use `lib.fakeSha256` or
`lib.fakeHash` as a stub hash. Building `cargoDeps` will then inform
you of the correct hash.
2021-06-05 20:22:45 +01:00
### Hooks {#hooks}
2021-02-12 07:35:50 +00:00
`rustPlatform` provides the following hooks to automate Cargo builds:
* `cargoSetupHook` : configure Cargo to use depenencies vendored
through `fetchCargoTarball` . This hook uses the `cargoDeps`
environment variable to find the vendored dependencies. If a project
already vendors its dependencies, the variable `cargoVendorDir` can
be used instead. When the `Cargo.toml` /`Cargo.lock` files are not in
`sourceRoot` , then the optional `cargoRoot` is used to specify the
Cargo root directory relative to `sourceRoot` .
* `cargoBuildHook` : use Cargo to build a crate. If the crate to be
built is a crate in e.g. a Cargo workspace, the relative path to the
crate to build can be set through the optional `buildAndTestSubdir`
environment variable. Additional Cargo build flags can be passed
through `cargoBuildFlags` .
* `maturinBuildHook` : use [Maturin ](https://github.com/PyO3/maturin )
to build a Python wheel. Similar to `cargoBuildHook` , the optional
variable `buildAndTestSubdir` can be used to build a crate in a
Cargo workspace. Additional maturin flags can be passed through
`maturinBuildFlags` .
2021-02-26 10:51:31 +00:00
* `cargoCheckHook` : run tests using Cargo. The build type for checks
can be set using `cargoCheckType` . Additional flags can be passed to
the tests using `checkFlags` and `checkFlagsArray` . By default,
tests are run in parallel. This can be disabled by setting
2021-02-15 09:26:40 +00:00
`dontUseCargoParallelTests` .
2021-02-15 05:54:18 +00:00
* `cargoInstallHook` : install binaries and static/shared libraries
that were built using `cargoBuildHook` .
2021-02-12 07:35:50 +00:00
2021-06-05 20:22:45 +01:00
### Examples {#examples}
2021-02-12 07:35:50 +00:00
2021-06-05 20:22:45 +01:00
#### Python package using `setuptools-rust` {#python-package-using-setuptools-rust}
2021-02-12 07:35:50 +00:00
For Python packages using `setuptools-rust` , you can use
`fetchCargoTarball` and `cargoSetupHook` to retrieve and set up Cargo
dependencies. The build itself is then performed by
`buildPythonPackage` .
The following example outlines how the `tokenizers` Python package is
built. Since the Python package is in the `source/bindings/python`
directory of the *tokenizers* project's source archive, we use
`sourceRoot` to point the tooling to this directory:
2021-02-09 12:46:32 +00:00
```nix
{ fetchFromGitHub
, buildPythonPackage
, rustPlatform
, setuptools-rust
}:
buildPythonPackage rec {
pname = "tokenizers";
version = "0.10.0";
src = fetchFromGitHub {
owner = "huggingface";
repo = pname;
rev = "python-v${version}";
hash = "sha256-rQ2hRV52naEf6PvRsWVCTN7B1oXAQGmnpJw4iIdhamw=";
};
cargoDeps = rustPlatform.fetchCargoTarball {
inherit src sourceRoot;
name = "${pname}-${version}";
hash = "sha256-BoHIN/519Top1NUBjpB/oEMqi86Omt3zTQcXFWqrek0=";
};
sourceRoot = "source/bindings/python";
nativeBuildInputs = [ setuptools-rust ] ++ (with rustPlatform; [
cargoSetupHook
rust.cargo
rust.rustc
]);
# ...
}
```
2021-02-12 07:35:50 +00:00
In some projects, the Rust crate is not in the main Python source
directory. In such cases, the `cargoRoot` attribute can be used to
specify the crate's directory relative to `sourceRoot` . In the
2021-02-09 12:46:32 +00:00
following example, the crate is in `src/rust` , as specified in the
`cargoRoot` attribute. Note that we also need to specify the correct
path for `fetchCargoTarball` .
```nix
{ buildPythonPackage
, fetchPypi
, rustPlatform
, setuptools-rust
, openssl
}:
buildPythonPackage rec {
pname = "cryptography";
version = "3.4.2"; # Also update the hash in vectors.nix
src = fetchPypi {
inherit pname version;
sha256 = "1i1mx5y9hkyfi9jrrkcw804hmkcglxi6rmf7vin7jfnbr2bf4q64";
};
cargoDeps = rustPlatform.fetchCargoTarball {
inherit src;
sourceRoot = "${pname}-${version}/${cargoRoot}";
name = "${pname}-${version}";
hash = "sha256-PS562W4L1NimqDV2H0jl5vYhL08H9est/pbIxSdYVfo=";
};
cargoRoot = "src/rust";
# ...
}
```
2021-06-05 20:22:45 +01:00
#### Python package using `maturin` {#python-package-using-maturin}
2021-02-12 07:35:50 +00:00
Python packages that use [Maturin ](https://github.com/PyO3/maturin )
can be built with `fetchCargoTarball` , `cargoSetupHook` , and
`maturinBuildHook` . For example, the following (partial) derivation
builds the `retworkx` Python package. `fetchCargoTarball` and
`cargoSetupHook` are used to fetch and set up the crate dependencies.
`maturinBuildHook` is used to perform the build.
```nix
{ lib
, buildPythonPackage
, rustPlatform
, fetchFromGitHub
}:
buildPythonPackage rec {
pname = "retworkx";
version = "0.6.0";
src = fetchFromGitHub {
owner = "Qiskit";
repo = "retworkx";
rev = version;
sha256 = "11n30ldg3y3y6qxg3hbj837pnbwjkqw3nxq6frds647mmmprrd20";
};
cargoDeps = rustPlatform.fetchCargoTarball {
inherit src;
name = "${pname}-${version}";
hash = "sha256-heOBK8qi2nuc/Ib+I/vLzZ1fUUD/G/KTw9d7M4Hz5O0=";
};
format = "pyproject";
nativeBuildInputs = with rustPlatform; [ cargoSetupHook maturinBuildHook ];
# ...
}
```
2021-06-05 20:22:45 +01:00
## Compiling Rust crates using Nix instead of Cargo {#compiling-rust-crates-using-nix-instead-of-cargo}
2017-12-12 10:55:15 +00:00
2021-06-05 20:22:45 +01:00
### Simple operation {#simple-operation}
2018-02-20 07:55:04 +00:00
2017-12-12 10:55:15 +00:00
When run, `cargo build` produces a file called `Cargo.lock` ,
containing pinned versions of all dependencies. Nixpkgs contains a
tool called `carnix` (`nix-env -iA nixos.carnix`), which can be used
to turn a `Cargo.lock` into a Nix expression.
That Nix expression calls `rustc` directly (hence bypassing Cargo),
and can be used to compile a crate and all its dependencies. Here is
an example for a minimal `hello` crate:
2021-06-05 20:22:45 +01:00
```ShellSession
$ cargo new hello
$ cd hello
$ cargo build
2017-12-12 10:55:15 +00:00
Compiling hello v0.1.0 (file:///tmp/hello)
2021-06-05 20:22:45 +01:00
Finished dev [unoptimized + debuginfo] target(s) in 0.20 secs
$ carnix -o hello.nix --src ./. Cargo.lock --standalone
$ nix-build hello.nix -A hello_0_1_0
```
2017-12-12 10:55:15 +00:00
Now, the file produced by the call to `carnix` , called `hello.nix` , looks like:
2021-03-13 23:30:36 +00:00
```nix
2018-01-28 19:29:09 +00:00
# Generated by carnix 0.6.5: carnix -o hello.nix --src ./. Cargo.lock --standalone
2021-01-21 00:07:16 +00:00
{ stdenv, buildRustCrate, fetchgit }:
2018-08-20 19:43:41 +01:00
let kernel = stdenv.buildPlatform.parsed.kernel.name;
2017-12-12 10:55:15 +00:00
# ... (content skipped)
in
rec {
2018-01-28 19:29:09 +00:00
hello = f: hello_0_1_0 { features = hello_0_1_0_features { hello_0_1_0 = f; }; };
hello_0_1_0_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate {
crateName = "hello";
version = "0.1.0";
authors = [ "pe@pijul.org < pe @ pijul . org > " ];
src = ./.;
inherit dependencies buildDependencies features;
};
hello_0_1_0 = { features?(hello_0_1_0_features {}) }: hello_0_1_0_ {};
hello_0_1_0_features = f: updateFeatures f (rec {
hello_0_1_0.default = (f.hello_0_1_0.default or true);
}) [ ];
2017-12-12 10:55:15 +00:00
}
```
In particular, note that the argument given as `--src` is copied
verbatim to the source. If we look at a more complicated
dependencies, for instance by adding a single line `libc="*"` to our
`Cargo.toml` , we first need to run `cargo build` to update the
`Cargo.lock` . Then, `carnix` needs to be run again, and produces the
following nix file:
2021-03-13 23:30:36 +00:00
```nix
2018-01-28 19:29:09 +00:00
# Generated by carnix 0.6.5: carnix -o hello.nix --src ./. Cargo.lock --standalone
2021-01-21 00:07:16 +00:00
{ stdenv, buildRustCrate, fetchgit }:
2018-08-20 19:43:41 +01:00
let kernel = stdenv.buildPlatform.parsed.kernel.name;
2017-12-12 10:55:15 +00:00
# ... (content skipped)
in
rec {
2018-01-28 19:29:09 +00:00
hello = f: hello_0_1_0 { features = hello_0_1_0_features { hello_0_1_0 = f; }; };
hello_0_1_0_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate {
crateName = "hello";
version = "0.1.0";
authors = [ "pe@pijul.org < pe @ pijul . org > " ];
src = ./.;
inherit dependencies buildDependencies features;
};
libc_0_2_36_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate {
crateName = "libc";
version = "0.2.36";
authors = [ "The Rust Project Developers" ];
sha256 = "01633h4yfqm0s302fm0dlba469bx8y6cs4nqc8bqrmjqxfxn515l";
inherit dependencies buildDependencies features;
2017-12-12 10:55:15 +00:00
};
2018-01-28 19:29:09 +00:00
hello_0_1_0 = { features?(hello_0_1_0_features {}) }: hello_0_1_0_ {
dependencies = mapFeatures features ([ libc_0_2_36 ]);
2017-12-12 10:55:15 +00:00
};
2018-01-28 19:29:09 +00:00
hello_0_1_0_features = f: updateFeatures f (rec {
hello_0_1_0.default = (f.hello_0_1_0.default or true);
libc_0_2_36.default = true;
}) [ libc_0_2_36_features ];
libc_0_2_36 = { features?(libc_0_2_36_features {}) }: libc_0_2_36_ {
features = mkFeatures (features.libc_0_2_36 or {});
};
libc_0_2_36_features = f: updateFeatures f (rec {
libc_0_2_36.default = (f.libc_0_2_36.default or true);
libc_0_2_36.use_std =
(f.libc_0_2_36.use_std or false) ||
(f.libc_0_2_36.default or false) ||
(libc_0_2_36.default or false);
}) [];
2017-12-12 10:55:15 +00:00
}
```
Here, the `libc` crate has no `src` attribute, so `buildRustCrate`
will fetch it from [crates.io ](https://crates.io ). A `sha256`
attribute is still needed for Nix purity.
2021-06-05 20:22:45 +01:00
### Handling external dependencies {#handling-external-dependencies}
2018-02-20 07:55:04 +00:00
2017-12-12 10:55:15 +00:00
Some crates require external libraries. For crates from
[crates.io ](https://crates.io ), such libraries can be specified in
`defaultCrateOverrides` package in nixpkgs itself.
Starting from that file, one can add more overrides, to add features
or build inputs by overriding the hello crate in a seperate file.
2021-03-13 23:30:36 +00:00
```nix
2017-12-12 10:55:15 +00:00
with import < nixpkgs > {};
2018-01-28 19:29:09 +00:00
((import ./hello.nix).hello {}).override {
2017-12-12 10:55:15 +00:00
crateOverrides = defaultCrateOverrides // {
hello = attrs: { buildInputs = [ openssl ]; };
};
}
```
Here, `crateOverrides` is expected to be a attribute set, where the
key is the crate name without version number and the value a function.
The function gets all attributes passed to `buildRustCrate` as first
argument and returns a set that contains all attribute that should be
overwritten.
For more complicated cases, such as when parts of the crate's
2019-11-09 09:07:59 +00:00
derivation depend on the crate's version, the `attrs` argument of
2017-12-12 10:55:15 +00:00
the override above can be read, as in the following example, which
patches the derivation:
2021-03-13 23:30:36 +00:00
```nix
2017-12-12 10:55:15 +00:00
with import < nixpkgs > {};
2018-01-28 19:29:09 +00:00
((import ./hello.nix).hello {}).override {
2017-12-12 10:55:15 +00:00
crateOverrides = defaultCrateOverrides // {
hello = attrs: lib.optionalAttrs (lib.versionAtLeast attrs.version "1.0") {
postPatch = ''
substituteInPlace lib/zoneinfo.rs \
--replace "/usr/share/zoneinfo" "${tzdata}/share/zoneinfo"
'';
};
};
}
```
Another situation is when we want to override a nested
dependency. This actually works in the exact same way, since the
`crateOverrides` parameter is forwarded to the crate's
dependencies. For instance, to override the build inputs for crate
`libc` in the example above, where `libc` is a dependency of the main
crate, we could do:
2021-03-13 23:30:36 +00:00
```nix
2017-12-12 10:55:15 +00:00
with import < nixpkgs > {};
2018-01-28 19:29:09 +00:00
((import hello.nix).hello {}).override {
2017-12-12 10:55:15 +00:00
crateOverrides = defaultCrateOverrides // {
libc = attrs: { buildInputs = []; };
};
}
```
2021-06-05 20:22:45 +01:00
### Options and phases configuration {#options-and-phases-configuration}
2018-02-20 07:55:04 +00:00
Actually, the overrides introduced in the previous section are more
general. A number of other parameters can be overridden:
2017-12-12 10:55:15 +00:00
- The version of rustc used to compile the crate:
2021-03-13 23:30:36 +00:00
```nix
2018-01-28 19:29:09 +00:00
(hello {}).override { rust = pkgs.rust; };
2017-12-12 10:55:15 +00:00
```
- Whether to build in release mode or debug mode (release mode by
default):
2021-03-13 23:30:36 +00:00
```nix
2018-01-28 19:29:09 +00:00
(hello {}).override { release = false; };
2017-12-12 10:55:15 +00:00
```
- Whether to print the commands sent to rustc when building
(equivalent to `--verbose` in cargo:
2021-03-13 23:30:36 +00:00
```nix
2018-01-28 19:29:09 +00:00
(hello {}).override { verbose = false; };
2017-12-12 10:55:15 +00:00
```
2018-02-20 07:55:04 +00:00
- Extra arguments to be passed to `rustc` :
2021-03-13 23:30:36 +00:00
```nix
2018-02-20 07:55:04 +00:00
(hello {}).override { extraRustcOpts = "-Z debuginfo=2"; };
```
- Phases, just like in any other derivation, can be specified using
the following attributes: `preUnpack` , `postUnpack` , `prePatch` ,
`patches` , `postPatch` , `preConfigure` (in the case of a Rust crate,
this is run before calling the "build" script), `postConfigure`
(after the "build" script),`preBuild`, `postBuild` , `preInstall` and
`postInstall` . As an example, here is how to create a new module
before running the build script:
2021-03-13 23:30:36 +00:00
```nix
2018-02-20 07:55:04 +00:00
(hello {}).override {
preConfigure = ''
echo "pub const PATH=\"${hi.out}\";" >> src/path.rs"
'';
};
```
2021-06-05 20:22:45 +01:00
### Features {#features}
2018-02-20 07:55:04 +00:00
2018-01-28 19:29:09 +00:00
One can also supply features switches. For example, if we want to
compile `diesel_cli` only with the `postgres` feature, and no default
features, we would write:
2021-03-13 23:30:36 +00:00
```nix
2018-01-28 19:29:09 +00:00
(callPackage ./diesel.nix {}).diesel {
default = false;
postgres = true;
}
```
2018-02-20 07:55:04 +00:00
Where `diesel.nix` is the file generated by Carnix, as explained above.
2017-12-12 10:55:15 +00:00
2021-06-05 20:22:45 +01:00
## Setting Up `nix-shell` {#setting-up-nix-shell}
2018-03-28 02:07:19 +01:00
Oftentimes you want to develop code from within `nix-shell` . Unfortunately
`buildRustCrate` does not support common `nix-shell` operations directly
(see [this issue ](https://github.com/NixOS/nixpkgs/issues/37945 ))
so we will use `stdenv.mkDerivation` instead.
Using the example `hello` project above, we want to do the following:
2021-06-05 20:22:45 +01:00
2018-03-28 02:07:19 +01:00
- Have access to `cargo` and `rustc`
- Have the `openssl` library available to a crate through it's _normal_
compilation mechanism (`pkg-config`).
A typical `shell.nix` might look like:
2021-03-13 23:30:36 +00:00
```nix
2018-03-28 02:07:19 +01:00
with import < nixpkgs > {};
stdenv.mkDerivation {
name = "rust-env";
2018-12-13 07:05:30 +00:00
nativeBuildInputs = [
2018-03-28 02:07:19 +01:00
rustc cargo
2018-12-13 07:05:30 +00:00
# Example Build-time Additional Dependencies
2021-01-19 03:19:48 +00:00
pkg-config
2018-12-13 07:05:30 +00:00
];
buildInputs = [
# Example Run-time Additional Dependencies
openssl
2018-03-28 02:07:19 +01:00
];
# Set Environment Variables
RUST_BACKTRACE = 1;
}
```
You should now be able to run the following:
2021-06-05 20:22:45 +01:00
```ShellSession
2018-03-28 02:07:19 +01:00
$ nix-shell --pure
$ cargo build
$ cargo test
```
2021-06-05 20:22:45 +01:00
### Controlling Rust Version Inside `nix-shell` {#controlling-rust-version-inside-nix-shell}
2018-03-28 02:07:19 +01:00
To control your rust version (i.e. use nightly) from within `shell.nix` (or
other nix expressions) you can use the following `shell.nix`
2021-03-13 23:30:36 +00:00
```nix
2018-03-28 02:07:19 +01:00
# Latest Nightly
with import < nixpkgs > {};
let src = fetchFromGitHub {
owner = "mozilla";
repo = "nixpkgs-mozilla";
2019-06-08 15:15:32 +01:00
# commit from: 2019-05-15
rev = "9f35c4b09fd44a77227e79ff0c1b4b6a69dff533";
sha256 = "18h0nvh55b5an4gmlgfbvwbyqj91bklf1zymis6lbdh75571qaz0";
2018-03-28 02:07:19 +01:00
};
in
with import "${src.out}/rust-overlay.nix" pkgs pkgs;
stdenv.mkDerivation {
name = "rust-env";
buildInputs = [
2021-03-14 10:49:35 +00:00
# Note: to use stable, just replace `nightly` with `stable`
2018-03-28 02:07:19 +01:00
latest.rustChannels.nightly.rust
# Add some extra dependencies from `pkgs`
2021-01-19 03:19:48 +00:00
pkg-config openssl
2018-03-28 02:07:19 +01:00
];
# Set Environment Variables
RUST_BACKTRACE = 1;
}
```
Now run:
2021-06-05 20:22:45 +01:00
2021-03-13 23:30:36 +00:00
```ShellSession
2018-03-28 02:07:19 +01:00
$ rustc --version
rustc 1.26.0-nightly (188e693b3 2018-03-26)
```
To see that you are using nightly.
2021-06-05 20:22:45 +01:00
## Using the Rust nightlies overlay {#using-the-rust-nightlies-overlay}
2017-03-20 19:41:37 +00:00
Mozilla provides an overlay for nixpkgs to bring a nightly version of Rust into scope.
This overlay can _also_ be used to install recent unstable or stable versions
of Rust, if desired.
2021-06-05 20:22:45 +01:00
### Rust overlay installation {#rust-overlay-installation}
2020-08-11 11:21:25 +01:00
You can use this overlay by either changing your local nixpkgs configuration,
or by adding the overlay declaratively in a nix expression, e.g. in `configuration.nix` .
2021-06-05 20:22:45 +01:00
For more information see [the manual on installing overlays ](#sec-overlays-install ).
2020-08-11 11:21:25 +01:00
2021-06-05 20:22:45 +01:00
#### Imperative rust overlay installation {#imperative-rust-overlay-installation}
2020-08-11 11:21:25 +01:00
Clone [nixpkgs-mozilla ](https://github.com/mozilla/nixpkgs-mozilla ),
2017-03-20 19:41:37 +00:00
and create a symbolic link to the file
[rust-overlay.nix ](https://github.com/mozilla/nixpkgs-mozilla/blob/master/rust-overlay.nix )
in the `~/.config/nixpkgs/overlays` directory.
2021-06-05 20:22:45 +01:00
```ShellSession
$ git clone https://github.com/mozilla/nixpkgs-mozilla.git
$ mkdir -p ~/.config/nixpkgs/overlays
$ ln -s $(pwd)/nixpkgs-mozilla/rust-overlay.nix ~/.config/nixpkgs/overlays/rust-overlay.nix
```
2017-03-20 19:41:37 +00:00
2021-06-05 20:22:45 +01:00
### Declarative rust overlay installation {#declarative-rust-overlay-installation}
2020-08-11 11:21:25 +01:00
Add the following to your `configuration.nix` , `home-configuration.nix` , `shell.nix` , or similar:
2021-03-13 23:30:36 +00:00
```nix
2021-01-17 06:29:15 +00:00
{ pkgs ? import < nixpkgs > {
2020-08-11 11:21:25 +01:00
overlays = [
(import (builtins.fetchTarball https://github.com/mozilla/nixpkgs-mozilla/archive/master.tar.gz))
# Further overlays go here
];
};
2021-01-17 06:29:15 +00:00
};
2020-08-11 11:21:25 +01:00
```
Note that this will fetch the latest overlay version when rebuilding your system.
2021-06-05 20:22:45 +01:00
### Rust overlay usage {#rust-overlay-usage}
2020-08-11 11:21:25 +01:00
The overlay contains attribute sets corresponding to different versions of the rust toolchain, such as:
* `latest.rustChannels.stable`
* `latest.rustChannels.nightly`
* a function `rustChannelOf` , called as `(rustChannelOf { date = "2018-04-11"; channel = "nightly"; })` , or...
* `(nixpkgs.rustChannelOf { rustToolchain = ./rust-toolchain; })` if you have a local `rust-toolchain` file (see https://github.com/mozilla/nixpkgs-mozilla#using-in-nix-expressions for an example)
Each of these contain packages such as `rust` , which contains your usual rust development tools with the respective toolchain chosen.
For example, you might want to add `latest.rustChannels.stable.rust` to the list of packages in your configuration.
Imperatively, the latest stable version can be installed with the following command:
2017-03-20 19:41:37 +00:00
2021-06-05 20:22:45 +01:00
```ShellSession
$ nix-env -Ai nixpkgs.latest.rustChannels.stable.rust
```
2017-03-20 19:41:37 +00:00
Or using the attribute with nix-shell:
2021-06-05 20:22:45 +01:00
```ShellSession
$ nix-shell -p nixpkgs.latest.rustChannels.stable.rust
```
2017-03-20 19:41:37 +00:00
2019-08-26 13:38:18 +01:00
Substitute the `nixpkgs` prefix with `nixos` on NixOS.
2017-03-20 19:41:37 +00:00
To install the beta or nightly channel, "stable" should be substituted by
"nightly" or "beta", or
use the function provided by this overlay to pull a version based on a
build date.
The overlay automatically updates itself as it uses the same source as
[rustup ](https://www.rustup.rs/ ).