1---
2title: Rust
3author: Matthias Beyer
4date: 2017-03-05
5---
6
7# Rust
8
9To install the rust compiler and cargo put
10
11```
12rustc
13cargo
14```
15
16into the `environment.systemPackages` or bring them into
17scope with `nix-shell -p rustc cargo`.
18
19For daily builds (beta and nightly) use either rustup from
20nixpkgs or use the [Rust nightlies
21overlay](#using-the-rust-nightlies-overlay).
22
23## Compiling Rust applications with Cargo
24
25Rust applications are packaged by using the `buildRustPackage` helper from `rustPlatform`:
26
27```
28rustPlatform.buildRustPackage rec {
29 pname = "ripgrep";
30 version = "11.0.2";
31
32 src = fetchFromGitHub {
33 owner = "BurntSushi";
34 repo = pname;
35 rev = version;
36 sha256 = "1iga3320mgi7m853la55xip514a3chqsdi1a1rwv25lr9b1p7vd3";
37 };
38
39 cargoSha256 = "17ldqr3asrdcsh4l29m3b5r37r5d0b3npq1lrgjmxb6vlx6a36qh";
40
41 meta = with stdenv.lib; {
42 description = "A fast line-oriented regex search tool, similar to ag and ack";
43 homepage = "https://github.com/BurntSushi/ripgrep";
44 license = licenses.unlicense;
45 maintainers = [ maintainers.tailhook ];
46 };
47}
48```
49
50`buildRustPackage` requires a `cargoSha256` attribute which is computed over
51all crate sources of this package. Currently it is obtained by inserting a
52fake checksum into the expression and building the package once. The correct
53checksum can be then take from the failed build.
54
55Per the instructions in the [Cargo Book](https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html)
56best practices guide, Rust applications should always commit the `Cargo.lock`
57file in git to ensure a reproducible build. However, a few packages do not, and
58Nix depends on this file, so if it missing you can use `cargoPatches` to apply
59it in the `patchPhase`. Consider sending a PR upstream with a note to the
60maintainer describing why it's important to include in the application.
61
62The fetcher will verify that the `Cargo.lock` file is in sync with the `src`
63attribute, and fail the build if not. It will also will compress the vendor
64directory into a tar.gz archive.
65
66### Building a crate for a different target
67
68To build your crate with a different cargo `--target` simply specify the `target` attribute:
69
70```nix
71pkgs.rustPlatform.buildRustPackage {
72 (...)
73 target = "x86_64-fortanix-unknown-sgx";
74}
75```
76
77### Running package tests
78
79When using `buildRustPackage`, the `checkPhase` is enabled by default and runs
80`cargo test` on the package to build. To make sure that we don't compile the
81sources twice and to actually test the artifacts that will be used at runtime,
82the tests will be ran in the `release` mode by default.
83
84However, in some cases the test-suite of a package doesn't work properly in the
85`release` mode. For these situations, the mode for `checkPhase` can be changed like
86so:
87
88```nix
89rustPlatform.buildRustPackage {
90 /* ... */
91 checkType = "debug";
92}
93```
94
95Please note that the code will be compiled twice here: once in `release` mode
96for the `buildPhase`, and again in `debug` mode for the `checkPhase`.
97
98#### Tests relying on the structure of the `target/` directory
99
100Some tests may rely on the structure of the `target/` directory. Those tests
101are likely to fail because we use `cargo --target` during the build. This means that
102the artifacts
103[are stored in `target/<architecture>/release/`](https://doc.rust-lang.org/cargo/guide/build-cache.html),
104rather than in `target/release/`.
105
106This can only be worked around by patching the affected tests accordingly.
107
108#### Disabling package-tests
109
110In some instances, it may be necessary to disable testing altogether (with `doCheck = false;`):
111
112* If no tests exist -- the `checkPhase` should be explicitly disabled to skip
113 unnecessary build steps to speed up the build.
114* If tests are highly impure (e.g. due to network usage).
115
116There will obviously be some corner-cases not listed above where it's sensible to disable tests.
117The above are just guidelines, and exceptions may be granted on a case-by-case basis.
118
119However, please check if it's possible to disable a problematic subset of the
120test suite and leave a comment explaining your reasoning.
121
122### Building a package in `debug` mode
123
124By default, `buildRustPackage` will use `release` mode for builds. If a package
125should be built in `debug` mode, it can be configured like so:
126
127```nix
128rustPlatform.buildRustPackage {
129 /* ... */
130 buildType = "debug";
131}
132```
133
134In this scenario, the `checkPhase` will be ran in `debug` mode as well.
135
136### Custom `build`/`install`-procedures
137
138Some packages may use custom scripts for building/installing, e.g. with a `Makefile`.
139In these cases, it's recommended to override the `buildPhase`/`installPhase`/`checkPhase`.
140
141Otherwise, some steps may fail because of the modified directory structure of `target/`.
142
143### Building a crate with an absent or out-of-date Cargo.lock file
144
145`buildRustPackage` needs a `Cargo.lock` file to get all dependencies in the
146source code in a reproducible way. If it is missing or out-of-date one can use
147the `cargoPatches` attribute to update or add it.
148
149```
150{ lib, rustPlatform, fetchFromGitHub }:
151
152rustPlatform.buildRustPackage rec {
153 (...)
154 cargoPatches = [
155 # a patch file to add/update Cargo.lock in the source code
156 ./add-Cargo.lock.patch
157 ];
158}
159```
160
161## Compiling Rust crates using Nix instead of Cargo
162
163### Simple operation
164
165When run, `cargo build` produces a file called `Cargo.lock`,
166containing pinned versions of all dependencies. Nixpkgs contains a
167tool called `carnix` (`nix-env -iA nixos.carnix`), which can be used
168to turn a `Cargo.lock` into a Nix expression.
169
170That Nix expression calls `rustc` directly (hence bypassing Cargo),
171and can be used to compile a crate and all its dependencies. Here is
172an example for a minimal `hello` crate:
173
174
175 $ cargo new hello
176 $ cd hello
177 $ cargo build
178 Compiling hello v0.1.0 (file:///tmp/hello)
179 Finished dev [unoptimized + debuginfo] target(s) in 0.20 secs
180 $ carnix -o hello.nix --src ./. Cargo.lock --standalone
181 $ nix-build hello.nix -A hello_0_1_0
182
183Now, the file produced by the call to `carnix`, called `hello.nix`, looks like:
184
185```
186# Generated by carnix 0.6.5: carnix -o hello.nix --src ./. Cargo.lock --standalone
187{ lib, stdenv, buildRustCrate, fetchgit }:
188let kernel = stdenv.buildPlatform.parsed.kernel.name;
189 # ... (content skipped)
190in
191rec {
192 hello = f: hello_0_1_0 { features = hello_0_1_0_features { hello_0_1_0 = f; }; };
193 hello_0_1_0_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate {
194 crateName = "hello";
195 version = "0.1.0";
196 authors = [ "pe@pijul.org <pe@pijul.org>" ];
197 src = ./.;
198 inherit dependencies buildDependencies features;
199 };
200 hello_0_1_0 = { features?(hello_0_1_0_features {}) }: hello_0_1_0_ {};
201 hello_0_1_0_features = f: updateFeatures f (rec {
202 hello_0_1_0.default = (f.hello_0_1_0.default or true);
203 }) [ ];
204}
205```
206
207In particular, note that the argument given as `--src` is copied
208verbatim to the source. If we look at a more complicated
209dependencies, for instance by adding a single line `libc="*"` to our
210`Cargo.toml`, we first need to run `cargo build` to update the
211`Cargo.lock`. Then, `carnix` needs to be run again, and produces the
212following nix file:
213
214```
215# Generated by carnix 0.6.5: carnix -o hello.nix --src ./. Cargo.lock --standalone
216{ lib, stdenv, buildRustCrate, fetchgit }:
217let kernel = stdenv.buildPlatform.parsed.kernel.name;
218 # ... (content skipped)
219in
220rec {
221 hello = f: hello_0_1_0 { features = hello_0_1_0_features { hello_0_1_0 = f; }; };
222 hello_0_1_0_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate {
223 crateName = "hello";
224 version = "0.1.0";
225 authors = [ "pe@pijul.org <pe@pijul.org>" ];
226 src = ./.;
227 inherit dependencies buildDependencies features;
228 };
229 libc_0_2_36_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate {
230 crateName = "libc";
231 version = "0.2.36";
232 authors = [ "The Rust Project Developers" ];
233 sha256 = "01633h4yfqm0s302fm0dlba469bx8y6cs4nqc8bqrmjqxfxn515l";
234 inherit dependencies buildDependencies features;
235 };
236 hello_0_1_0 = { features?(hello_0_1_0_features {}) }: hello_0_1_0_ {
237 dependencies = mapFeatures features ([ libc_0_2_36 ]);
238 };
239 hello_0_1_0_features = f: updateFeatures f (rec {
240 hello_0_1_0.default = (f.hello_0_1_0.default or true);
241 libc_0_2_36.default = true;
242 }) [ libc_0_2_36_features ];
243 libc_0_2_36 = { features?(libc_0_2_36_features {}) }: libc_0_2_36_ {
244 features = mkFeatures (features.libc_0_2_36 or {});
245 };
246 libc_0_2_36_features = f: updateFeatures f (rec {
247 libc_0_2_36.default = (f.libc_0_2_36.default or true);
248 libc_0_2_36.use_std =
249 (f.libc_0_2_36.use_std or false) ||
250 (f.libc_0_2_36.default or false) ||
251 (libc_0_2_36.default or false);
252 }) [];
253}
254```
255
256Here, the `libc` crate has no `src` attribute, so `buildRustCrate`
257will fetch it from [crates.io](https://crates.io). A `sha256`
258attribute is still needed for Nix purity.
259
260### Handling external dependencies
261
262Some crates require external libraries. For crates from
263[crates.io](https://crates.io), such libraries can be specified in
264`defaultCrateOverrides` package in nixpkgs itself.
265
266Starting from that file, one can add more overrides, to add features
267or build inputs by overriding the hello crate in a seperate file.
268
269```
270with import <nixpkgs> {};
271((import ./hello.nix).hello {}).override {
272 crateOverrides = defaultCrateOverrides // {
273 hello = attrs: { buildInputs = [ openssl ]; };
274 };
275}
276```
277
278Here, `crateOverrides` is expected to be a attribute set, where the
279key is the crate name without version number and the value a function.
280The function gets all attributes passed to `buildRustCrate` as first
281argument and returns a set that contains all attribute that should be
282overwritten.
283
284For more complicated cases, such as when parts of the crate's
285derivation depend on the crate's version, the `attrs` argument of
286the override above can be read, as in the following example, which
287patches the derivation:
288
289```
290with import <nixpkgs> {};
291((import ./hello.nix).hello {}).override {
292 crateOverrides = defaultCrateOverrides // {
293 hello = attrs: lib.optionalAttrs (lib.versionAtLeast attrs.version "1.0") {
294 postPatch = ''
295 substituteInPlace lib/zoneinfo.rs \
296 --replace "/usr/share/zoneinfo" "${tzdata}/share/zoneinfo"
297 '';
298 };
299 };
300}
301```
302
303Another situation is when we want to override a nested
304dependency. This actually works in the exact same way, since the
305`crateOverrides` parameter is forwarded to the crate's
306dependencies. For instance, to override the build inputs for crate
307`libc` in the example above, where `libc` is a dependency of the main
308crate, we could do:
309
310```
311with import <nixpkgs> {};
312((import hello.nix).hello {}).override {
313 crateOverrides = defaultCrateOverrides // {
314 libc = attrs: { buildInputs = []; };
315 };
316}
317```
318
319### Options and phases configuration
320
321Actually, the overrides introduced in the previous section are more
322general. A number of other parameters can be overridden:
323
324- The version of rustc used to compile the crate:
325
326 ```
327 (hello {}).override { rust = pkgs.rust; };
328 ```
329
330- Whether to build in release mode or debug mode (release mode by
331 default):
332
333 ```
334 (hello {}).override { release = false; };
335 ```
336
337- Whether to print the commands sent to rustc when building
338 (equivalent to `--verbose` in cargo:
339
340 ```
341 (hello {}).override { verbose = false; };
342 ```
343
344- Extra arguments to be passed to `rustc`:
345
346 ```
347 (hello {}).override { extraRustcOpts = "-Z debuginfo=2"; };
348 ```
349
350- Phases, just like in any other derivation, can be specified using
351 the following attributes: `preUnpack`, `postUnpack`, `prePatch`,
352 `patches`, `postPatch`, `preConfigure` (in the case of a Rust crate,
353 this is run before calling the "build" script), `postConfigure`
354 (after the "build" script),`preBuild`, `postBuild`, `preInstall` and
355 `postInstall`. As an example, here is how to create a new module
356 before running the build script:
357
358 ```
359 (hello {}).override {
360 preConfigure = ''
361 echo "pub const PATH=\"${hi.out}\";" >> src/path.rs"
362 '';
363 };
364 ```
365
366### Features
367
368One can also supply features switches. For example, if we want to
369compile `diesel_cli` only with the `postgres` feature, and no default
370features, we would write:
371
372```
373(callPackage ./diesel.nix {}).diesel {
374 default = false;
375 postgres = true;
376}
377```
378
379Where `diesel.nix` is the file generated by Carnix, as explained above.
380
381
382## Setting Up `nix-shell`
383Oftentimes you want to develop code from within `nix-shell`. Unfortunately
384`buildRustCrate` does not support common `nix-shell` operations directly
385(see [this issue](https://github.com/NixOS/nixpkgs/issues/37945))
386so we will use `stdenv.mkDerivation` instead.
387
388Using the example `hello` project above, we want to do the following:
389- Have access to `cargo` and `rustc`
390- Have the `openssl` library available to a crate through it's _normal_
391 compilation mechanism (`pkg-config`).
392
393A typical `shell.nix` might look like:
394
395```
396with import <nixpkgs> {};
397
398stdenv.mkDerivation {
399 name = "rust-env";
400 nativeBuildInputs = [
401 rustc cargo
402
403 # Example Build-time Additional Dependencies
404 pkgconfig
405 ];
406 buildInputs = [
407 # Example Run-time Additional Dependencies
408 openssl
409 ];
410
411 # Set Environment Variables
412 RUST_BACKTRACE = 1;
413}
414```
415
416You should now be able to run the following:
417```
418$ nix-shell --pure
419$ cargo build
420$ cargo test
421```
422
423### Controlling Rust Version Inside `nix-shell`
424To control your rust version (i.e. use nightly) from within `shell.nix` (or
425other nix expressions) you can use the following `shell.nix`
426
427```
428# Latest Nightly
429with import <nixpkgs> {};
430let src = fetchFromGitHub {
431 owner = "mozilla";
432 repo = "nixpkgs-mozilla";
433 # commit from: 2019-05-15
434 rev = "9f35c4b09fd44a77227e79ff0c1b4b6a69dff533";
435 sha256 = "18h0nvh55b5an4gmlgfbvwbyqj91bklf1zymis6lbdh75571qaz0";
436 };
437in
438with import "${src.out}/rust-overlay.nix" pkgs pkgs;
439stdenv.mkDerivation {
440 name = "rust-env";
441 buildInputs = [
442 # Note: to use use stable, just replace `nightly` with `stable`
443 latest.rustChannels.nightly.rust
444
445 # Add some extra dependencies from `pkgs`
446 pkgconfig openssl
447 ];
448
449 # Set Environment Variables
450 RUST_BACKTRACE = 1;
451}
452```
453
454Now run:
455```
456$ rustc --version
457rustc 1.26.0-nightly (188e693b3 2018-03-26)
458```
459
460To see that you are using nightly.
461
462
463## Using the Rust nightlies overlay
464
465Mozilla provides an overlay for nixpkgs to bring a nightly version of Rust into scope.
466This overlay can _also_ be used to install recent unstable or stable versions
467of Rust, if desired.
468
469To use this overlay, clone
470[nixpkgs-mozilla](https://github.com/mozilla/nixpkgs-mozilla),
471and create a symbolic link to the file
472[rust-overlay.nix](https://github.com/mozilla/nixpkgs-mozilla/blob/master/rust-overlay.nix)
473in the `~/.config/nixpkgs/overlays` directory.
474
475 $ git clone https://github.com/mozilla/nixpkgs-mozilla.git
476 $ mkdir -p ~/.config/nixpkgs/overlays
477 $ ln -s $(pwd)/nixpkgs-mozilla/rust-overlay.nix ~/.config/nixpkgs/overlays/rust-overlay.nix
478
479The latest version can be installed with the following command:
480
481 $ nix-env -Ai nixos.latest.rustChannels.stable.rust
482
483Or using the attribute with nix-shell:
484
485 $ nix-shell -p nixos.latest.rustChannels.stable.rust
486
487To install the beta or nightly channel, "stable" should be substituted by
488"nightly" or "beta", or
489use the function provided by this overlay to pull a version based on a
490build date.
491
492The overlay automatically updates itself as it uses the same source as
493[rustup](https://www.rustup.rs/).