1# Rust {#rust}
2
3To install the rust compiler and cargo put
4
5```nix
6environment.systemPackages = [
7 rustc
8 cargo
9];
10```
11
12into your `configuration.nix` or bring them into scope with `nix-shell -p rustc cargo`.
13
14For other versions such as daily builds (beta and nightly),
15use either `rustup` from nixpkgs (which will manage the rust installation in your home directory),
16or use a community maintained [Rust overlay](#using-community-rust-overlays).
17
18## `buildRustPackage`: Compiling Rust applications with Cargo {#compiling-rust-applications-with-cargo}
19
20Rust applications are packaged by using the `buildRustPackage` helper from `rustPlatform`:
21
22```nix
23{ lib, fetchFromGitHub, rustPlatform }:
24
25rustPlatform.buildRustPackage rec {
26 pname = "ripgrep";
27 version = "12.1.1";
28
29 src = fetchFromGitHub {
30 owner = "BurntSushi";
31 repo = pname;
32 rev = version;
33 sha256 = "1hqps7l5qrjh9f914r5i6kmcz6f1yb951nv4lby0cjnp5l253kps";
34 };
35
36 cargoSha256 = "03wf9r2csi6jpa7v5sw5lpxkrk4wfzwmzx7k3991q3bdjzcwnnwp";
37
38 meta = with lib; {
39 description = "A fast line-oriented regex search tool, similar to ag and ack";
40 homepage = "https://github.com/BurntSushi/ripgrep";
41 license = licenses.unlicense;
42 maintainers = [ maintainers.tailhook ];
43 };
44}
45```
46
47`buildRustPackage` requires either the `cargoSha256` or the
48`cargoHash` attribute which is computed over all crate sources of this
49package. `cargoHash256` is used for traditional Nix SHA-256 hashes,
50such as the one in the example above. `cargoHash` should instead be
51used for [SRI](https://www.w3.org/TR/SRI/) hashes. For example:
52
53```nix
54 cargoHash = "sha256-l1vL2ZdtDRxSGvP0X/l3nMw8+6WF67KPutJEzUROjg8=";
55```
56
57Both types of hashes are permitted when contributing to nixpkgs. The
58Cargo hash is obtained by inserting a fake checksum into the
59expression and building the package once. The correct checksum can
60then be taken from the failed build. A fake hash can be used for
61`cargoSha256` as follows:
62
63```nix
64 cargoSha256 = lib.fakeSha256;
65```
66
67For `cargoHash` you can use:
68
69```nix
70 cargoHash = lib.fakeHash;
71```
72
73Per the instructions in the [Cargo Book](https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html)
74best practices guide, Rust applications should always commit the `Cargo.lock`
75file in git to ensure a reproducible build. However, a few packages do not, and
76Nix depends on this file, so if it is missing you can use `cargoPatches` to
77apply it in the `patchPhase`. Consider sending a PR upstream with a note to the
78maintainer describing why it's important to include in the application.
79
80The fetcher will verify that the `Cargo.lock` file is in sync with the `src`
81attribute, and fail the build if not. It will also will compress the vendor
82directory into a tar.gz archive.
83
84The tarball with vendored dependencies contains a directory with the
85package's `name`, which is normally composed of `pname` and
86`version`. This means that the vendored dependencies hash
87(`cargoSha256`/`cargoHash`) is dependent on the package name and
88version. The `cargoDepsName` attribute can be used to use another name
89for the directory of vendored dependencies. For example, the hash can
90be made invariant to the version by setting `cargoDepsName` to
91`pname`:
92
93```nix
94rustPlatform.buildRustPackage rec {
95 pname = "broot";
96 version = "1.2.0";
97
98 src = fetchCrate {
99 inherit pname version;
100 sha256 = "1mqaynrqaas82f5957lx31x80v74zwmwmjxxlbywajb61vh00d38";
101 };
102
103 cargoHash = "sha256-JmBZcDVYJaK1cK05cxx5BrnGWp4t8ca6FLUbvIot67s=";
104 cargoDepsName = pname;
105
106 # ...
107}
108```
109
110### Importing a `Cargo.lock` file {#importing-a-cargo.lock-file}
111
112Using `cargoSha256` or `cargoHash` is tedious when using
113`buildRustPackage` within a project, since it requires that the hash
114is updated after every change to `Cargo.lock`. Therefore,
115`buildRustPackage` also supports vendoring dependencies directly from
116a `Cargo.lock` file using the `cargoLock` argument. For example:
117
118```nix
119rustPlatform.buildRustPackage {
120 pname = "myproject";
121 version = "1.0.0";
122
123 cargoLock = {
124 lockFile = ./Cargo.lock;
125 };
126
127 # ...
128}
129```
130
131This will retrieve the dependencies using fixed-output derivations from
132the specified lockfile.
133
134One caveat is that `Cargo.lock` cannot be patched in the `patchPhase`
135because it runs after the dependencies have already been fetched. If
136you need to patch or generate the lockfile you can alternatively set
137`cargoLock.lockFileContents` to a string of its contents:
138
139```nix
140rustPlatform.buildRustPackage {
141 pname = "myproject";
142 version = "1.0.0";
143
144 cargoLock = let
145 fixupLockFile = path: f (builtins.readFile path);
146 in {
147 lockFileContents = fixupLockFile ./Cargo.lock;
148 };
149
150 # ...
151}
152```
153
154Note that setting `cargoLock.lockFile` or `cargoLock.lockFileContents`
155doesn't add a `Cargo.lock` to your `src`, and a `Cargo.lock` is still
156required to build a rust package. A simple fix is to use:
157
158```nix
159postPatch = ''
160 cp ${./Cargo.lock} Cargo.lock
161'';
162```
163
164The output hash of each dependency that uses a git source must be
165specified in the `outputHashes` attribute. For example:
166
167```nix
168rustPlatform.buildRustPackage rec {
169 pname = "myproject";
170 version = "1.0.0";
171
172 cargoLock = {
173 lockFile = ./Cargo.lock;
174 outputHashes = {
175 "finalfusion-0.14.0" = "17f4bsdzpcshwh74w5z119xjy2if6l2wgyjy56v621skr2r8y904";
176 };
177 };
178
179 # ...
180}
181```
182
183If you do not specify an output hash for a git dependency, building
184the package will fail and inform you of which crate needs to be
185added. To find the correct hash, you can first use `lib.fakeSha256` or
186`lib.fakeHash` as a stub hash. Building the package (and thus the
187vendored dependencies) will then inform you of the correct hash.
188
189### Cargo features {#cargo-features}
190
191You can disable default features using `buildNoDefaultFeatures`, and
192extra features can be added with `buildFeatures`.
193
194If you want to use different features for check phase, you can use
195`checkNoDefaultFeatures` and `checkFeatures`. They are only passed to
196`cargo test` and not `cargo build`. If left unset, they default to
197`buildNoDefaultFeatures` and `buildFeatures`.
198
199For example:
200
201```nix
202rustPlatform.buildRustPackage rec {
203 pname = "myproject";
204 version = "1.0.0";
205
206 buildNoDefaultFeatures = true;
207 buildFeatures = [ "color" "net" ];
208
209 # disable network features in tests
210 checkFeatures = [ "color" ];
211
212 # ...
213}
214```
215
216### Cross compilation {#cross-compilation}
217
218By default, Rust packages are compiled for the host platform, just like any
219other package is. The `--target` passed to rust tools is computed from this.
220By default, it takes the `stdenv.hostPlatform.config` and replaces components
221where they are known to differ. But there are ways to customize the argument:
222
223 - To choose a different target by name, define
224 `stdenv.hostPlatform.rustc.config` as that name (a string), and that
225 name will be used instead.
226
227 For example:
228
229 ```nix
230 import <nixpkgs> {
231 crossSystem = (import <nixpkgs/lib>).systems.examples.armhf-embedded // {
232 rustc.config = "thumbv7em-none-eabi";
233 };
234 }
235 ```
236
237 will result in:
238
239 ```shell
240 --target thumbv7em-none-eabi
241 ```
242
243 - To pass a completely custom target, define
244 `stdenv.hostPlatform.rustc.config` with its name, and
245 `stdenv.hostPlatform.rustc.platform` with the value. The value will be
246 serialized to JSON in a file called
247 `${stdenv.hostPlatform.rustc.config}.json`, and the path of that file
248 will be used instead.
249
250 For example:
251
252 ```nix
253 import <nixpkgs> {
254 crossSystem = (import <nixpkgs/lib>).systems.examples.armhf-embedded // {
255 rustc.config = "thumb-crazy";
256 rustc.platform = { foo = ""; bar = ""; };
257 };
258 }
259 ```
260
261 will result in:
262
263 ```shell
264 --target /nix/store/asdfasdfsadf-thumb-crazy.json # contains {"foo":"","bar":""}
265 ```
266
267Note that currently custom targets aren't compiled with `std`, so `cargo test`
268will fail. This can be ignored by adding `doCheck = false;` to your derivation.
269
270### Running package tests {#running-package-tests}
271
272When using `buildRustPackage`, the `checkPhase` is enabled by default and runs
273`cargo test` on the package to build. To make sure that we don't compile the
274sources twice and to actually test the artifacts that will be used at runtime,
275the tests will be ran in the `release` mode by default.
276
277However, in some cases the test-suite of a package doesn't work properly in the
278`release` mode. For these situations, the mode for `checkPhase` can be changed like
279so:
280
281```nix
282rustPlatform.buildRustPackage {
283 /* ... */
284 checkType = "debug";
285}
286```
287
288Please note that the code will be compiled twice here: once in `release` mode
289for the `buildPhase`, and again in `debug` mode for the `checkPhase`.
290
291Test flags, e.g., `--package foo`, can be passed to `cargo test` via the
292`cargoTestFlags` attribute.
293
294Another attribute, called `checkFlags`, is used to pass arguments to the test
295binary itself, as stated
296[here](https://doc.rust-lang.org/cargo/commands/cargo-test.html).
297
298#### Tests relying on the structure of the `target/` directory {#tests-relying-on-the-structure-of-the-target-directory}
299
300Some tests may rely on the structure of the `target/` directory. Those tests
301are likely to fail because we use `cargo --target` during the build. This means that
302the artifacts
303[are stored in `target/<architecture>/release/`](https://doc.rust-lang.org/cargo/guide/build-cache.html),
304rather than in `target/release/`.
305
306This can only be worked around by patching the affected tests accordingly.
307
308#### Disabling package-tests {#disabling-package-tests}
309
310In some instances, it may be necessary to disable testing altogether (with `doCheck = false;`):
311
312* If no tests exist -- the `checkPhase` should be explicitly disabled to skip
313 unnecessary build steps to speed up the build.
314* If tests are highly impure (e.g. due to network usage).
315
316There will obviously be some corner-cases not listed above where it's sensible to disable tests.
317The above are just guidelines, and exceptions may be granted on a case-by-case basis.
318
319However, please check if it's possible to disable a problematic subset of the
320test suite and leave a comment explaining your reasoning.
321
322This can be achived with `--skip` in `checkFlags`:
323
324```nix
325rustPlatform.buildRustPackage {
326 /* ... */
327 checkFlags = [
328 # reason for disabling test
329 "--skip=example::tests:example_test"
330 ];
331}
332```
333
334#### Setting `test-threads` {#setting-test-threads}
335
336`buildRustPackage` will use parallel test threads by default,
337sometimes it may be necessary to disable this so the tests run consecutively.
338
339```nix
340rustPlatform.buildRustPackage {
341 /* ... */
342 dontUseCargoParallelTests = true;
343}
344```
345
346### Building a package in `debug` mode {#building-a-package-in-debug-mode}
347
348By default, `buildRustPackage` will use `release` mode for builds. If a package
349should be built in `debug` mode, it can be configured like so:
350
351```nix
352rustPlatform.buildRustPackage {
353 /* ... */
354 buildType = "debug";
355}
356```
357
358In this scenario, the `checkPhase` will be ran in `debug` mode as well.
359
360### Custom `build`/`install`-procedures {#custom-buildinstall-procedures}
361
362Some packages may use custom scripts for building/installing, e.g. with a `Makefile`.
363In these cases, it's recommended to override the `buildPhase`/`installPhase`/`checkPhase`.
364
365Otherwise, some steps may fail because of the modified directory structure of `target/`.
366
367### 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}
368
369`buildRustPackage` needs a `Cargo.lock` file to get all dependencies in the
370source code in a reproducible way. If it is missing or out-of-date one can use
371the `cargoPatches` attribute to update or add it.
372
373```nix
374rustPlatform.buildRustPackage rec {
375 (...)
376 cargoPatches = [
377 # a patch file to add/update Cargo.lock in the source code
378 ./add-Cargo.lock.patch
379 ];
380}
381```
382
383## Compiling non-Rust packages that include Rust code {#compiling-non-rust-packages-that-include-rust-code}
384
385Several non-Rust packages incorporate Rust code for performance- or
386security-sensitive parts. `rustPlatform` exposes several functions and
387hooks that can be used to integrate Cargo in non-Rust packages.
388
389### Vendoring of dependencies {#vendoring-of-dependencies}
390
391Since network access is not allowed in sandboxed builds, Rust crate
392dependencies need to be retrieved using a fetcher. `rustPlatform`
393provides the `fetchCargoTarball` fetcher, which vendors all
394dependencies of a crate. For example, given a source path `src`
395containing `Cargo.toml` and `Cargo.lock`, `fetchCargoTarball`
396can be used as follows:
397
398```nix
399cargoDeps = rustPlatform.fetchCargoTarball {
400 inherit src;
401 hash = "sha256-BoHIN/519Top1NUBjpB/oEMqi86Omt3zTQcXFWqrek0=";
402};
403```
404
405The `src` attribute is required, as well as a hash specified through
406one of the `sha256` or `hash` attributes. The following optional
407attributes can also be used:
408
409* `name`: the name that is used for the dependencies tarball. If
410 `name` is not specified, then the name `cargo-deps` will be used.
411* `sourceRoot`: when the `Cargo.lock`/`Cargo.toml` are in a
412 subdirectory, `sourceRoot` specifies the relative path to these
413 files.
414* `patches`: patches to apply before vendoring. This is useful when
415 the `Cargo.lock`/`Cargo.toml` files need to be patched before
416 vendoring.
417
418If a `Cargo.lock` file is available, you can alternatively use the
419`importCargoLock` function. In contrast to `fetchCargoTarball`, this
420function does not require a hash (unless git dependencies are used)
421and fetches every dependency as a separate fixed-output derivation.
422`importCargoLock` can be used as follows:
423
424```
425cargoDeps = rustPlatform.importCargoLock {
426 lockFile = ./Cargo.lock;
427};
428```
429
430If the `Cargo.lock` file includes git dependencies, then their output
431hashes need to be specified since they are not available through the
432lock file. For example:
433
434```
435cargoDeps = rustPlatform.importCargoLock {
436 lockFile = ./Cargo.lock;
437 outputHashes = {
438 "rand-0.8.3" = "0ya2hia3cn31qa8894s3av2s8j5bjwb6yq92k0jsnlx7jid0jwqa";
439 };
440};
441```
442
443If you do not specify an output hash for a git dependency, building
444`cargoDeps` will fail and inform you of which crate needs to be
445added. To find the correct hash, you can first use `lib.fakeSha256` or
446`lib.fakeHash` as a stub hash. Building `cargoDeps` will then inform
447you of the correct hash.
448
449### Hooks {#hooks}
450
451`rustPlatform` provides the following hooks to automate Cargo builds:
452
453* `cargoSetupHook`: configure Cargo to use dependencies vendored
454 through `fetchCargoTarball`. This hook uses the `cargoDeps`
455 environment variable to find the vendored dependencies. If a project
456 already vendors its dependencies, the variable `cargoVendorDir` can
457 be used instead. When the `Cargo.toml`/`Cargo.lock` files are not in
458 `sourceRoot`, then the optional `cargoRoot` is used to specify the
459 Cargo root directory relative to `sourceRoot`.
460* `cargoBuildHook`: use Cargo to build a crate. If the crate to be
461 built is a crate in e.g. a Cargo workspace, the relative path to the
462 crate to build can be set through the optional `buildAndTestSubdir`
463 environment variable. Features can be specified with
464 `cargoBuildNoDefaultFeatures` and `cargoBuildFeatures`. Additional
465 Cargo build flags can be passed through `cargoBuildFlags`.
466* `maturinBuildHook`: use [Maturin](https://github.com/PyO3/maturin)
467 to build a Python wheel. Similar to `cargoBuildHook`, the optional
468 variable `buildAndTestSubdir` can be used to build a crate in a
469 Cargo workspace. Additional Maturin flags can be passed through
470 `maturinBuildFlags`.
471* `cargoCheckHook`: run tests using Cargo. The build type for checks
472 can be set using `cargoCheckType`. Features can be specified with
473 `cargoCheckNoDefaultFeatures` and `cargoCheckFeatures`. Additional
474 flags can be passed to the tests using `checkFlags` and
475 `checkFlagsArray`. By default, tests are run in parallel. This can
476 be disabled by setting `dontUseCargoParallelTests`.
477* `cargoInstallHook`: install binaries and static/shared libraries
478 that were built using `cargoBuildHook`.
479* `bindgenHook`: for crates which use `bindgen` as a build dependency, lets
480 `bindgen` find `libclang` and `libclang` find the libraries in `buildInputs`.
481
482### Examples {#examples}
483
484#### Python package using `setuptools-rust` {#python-package-using-setuptools-rust}
485
486For Python packages using `setuptools-rust`, you can use
487`fetchCargoTarball` and `cargoSetupHook` to retrieve and set up Cargo
488dependencies. The build itself is then performed by
489`buildPythonPackage`.
490
491The following example outlines how the `tokenizers` Python package is
492built. Since the Python package is in the `source/bindings/python`
493directory of the `tokenizers` project's source archive, we use
494`sourceRoot` to point the tooling to this directory:
495
496```nix
497{ fetchFromGitHub
498, buildPythonPackage
499, rustPlatform
500, setuptools-rust
501}:
502
503buildPythonPackage rec {
504 pname = "tokenizers";
505 version = "0.10.0";
506
507 src = fetchFromGitHub {
508 owner = "huggingface";
509 repo = pname;
510 rev = "python-v${version}";
511 hash = "sha256-rQ2hRV52naEf6PvRsWVCTN7B1oXAQGmnpJw4iIdhamw=";
512 };
513
514 cargoDeps = rustPlatform.fetchCargoTarball {
515 inherit src sourceRoot;
516 name = "${pname}-${version}";
517 hash = "sha256-BoHIN/519Top1NUBjpB/oEMqi86Omt3zTQcXFWqrek0=";
518 };
519
520 sourceRoot = "source/bindings/python";
521
522 nativeBuildInputs = [ setuptools-rust ] ++ (with rustPlatform; [
523 cargoSetupHook
524 rust.cargo
525 rust.rustc
526 ]);
527
528 # ...
529}
530```
531
532In some projects, the Rust crate is not in the main Python source
533directory. In such cases, the `cargoRoot` attribute can be used to
534specify the crate's directory relative to `sourceRoot`. In the
535following example, the crate is in `src/rust`, as specified in the
536`cargoRoot` attribute. Note that we also need to specify the correct
537path for `fetchCargoTarball`.
538
539```nix
540
541{ buildPythonPackage
542, fetchPypi
543, rustPlatform
544, setuptools-rust
545, openssl
546}:
547
548buildPythonPackage rec {
549 pname = "cryptography";
550 version = "3.4.2"; # Also update the hash in vectors.nix
551
552 src = fetchPypi {
553 inherit pname version;
554 sha256 = "1i1mx5y9hkyfi9jrrkcw804hmkcglxi6rmf7vin7jfnbr2bf4q64";
555 };
556
557 cargoDeps = rustPlatform.fetchCargoTarball {
558 inherit src;
559 sourceRoot = "${pname}-${version}/${cargoRoot}";
560 name = "${pname}-${version}";
561 hash = "sha256-PS562W4L1NimqDV2H0jl5vYhL08H9est/pbIxSdYVfo=";
562 };
563
564 cargoRoot = "src/rust";
565
566 # ...
567}
568```
569
570#### Python package using `maturin` {#python-package-using-maturin}
571
572Python packages that use [Maturin](https://github.com/PyO3/maturin)
573can be built with `fetchCargoTarball`, `cargoSetupHook`, and
574`maturinBuildHook`. For example, the following (partial) derivation
575builds the `retworkx` Python package. `fetchCargoTarball` and
576`cargoSetupHook` are used to fetch and set up the crate dependencies.
577`maturinBuildHook` is used to perform the build.
578
579```nix
580{ lib
581, buildPythonPackage
582, rustPlatform
583, fetchFromGitHub
584}:
585
586buildPythonPackage rec {
587 pname = "retworkx";
588 version = "0.6.0";
589
590 src = fetchFromGitHub {
591 owner = "Qiskit";
592 repo = "retworkx";
593 rev = version;
594 sha256 = "11n30ldg3y3y6qxg3hbj837pnbwjkqw3nxq6frds647mmmprrd20";
595 };
596
597 cargoDeps = rustPlatform.fetchCargoTarball {
598 inherit src;
599 name = "${pname}-${version}";
600 hash = "sha256-heOBK8qi2nuc/Ib+I/vLzZ1fUUD/G/KTw9d7M4Hz5O0=";
601 };
602
603 format = "pyproject";
604
605 nativeBuildInputs = with rustPlatform; [ cargoSetupHook maturinBuildHook ];
606
607 # ...
608}
609```
610
611## `buildRustCrate`: Compiling Rust crates using Nix instead of Cargo {#compiling-rust-crates-using-nix-instead-of-cargo}
612
613### Simple operation {#simple-operation}
614
615When run, `cargo build` produces a file called `Cargo.lock`,
616containing pinned versions of all dependencies. Nixpkgs contains a
617tool called `carnix` (`nix-env -iA nixos.carnix`), which can be used
618to turn a `Cargo.lock` into a Nix expression.
619
620That Nix expression calls `rustc` directly (hence bypassing Cargo),
621and can be used to compile a crate and all its dependencies. Here is
622an example for a minimal `hello` crate:
623
624```ShellSession
625$ cargo new hello
626$ cd hello
627$ cargo build
628 Compiling hello v0.1.0 (file:///tmp/hello)
629 Finished dev [unoptimized + debuginfo] target(s) in 0.20 secs
630$ carnix -o hello.nix --src ./. Cargo.lock --standalone
631$ nix-build hello.nix -A hello_0_1_0
632```
633
634Now, the file produced by the call to `carnix`, called `hello.nix`, looks like:
635
636```nix
637# Generated by carnix 0.6.5: carnix -o hello.nix --src ./. Cargo.lock --standalone
638{ stdenv, buildRustCrate, fetchgit }:
639let kernel = stdenv.buildPlatform.parsed.kernel.name;
640 # ... (content skipped)
641in
642rec {
643 hello = f: hello_0_1_0 { features = hello_0_1_0_features { hello_0_1_0 = f; }; };
644 hello_0_1_0_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate {
645 crateName = "hello";
646 version = "0.1.0";
647 authors = [ "pe@pijul.org <pe@pijul.org>" ];
648 src = ./.;
649 inherit dependencies buildDependencies features;
650 };
651 hello_0_1_0 = { features?(hello_0_1_0_features {}) }: hello_0_1_0_ {};
652 hello_0_1_0_features = f: updateFeatures f (rec {
653 hello_0_1_0.default = (f.hello_0_1_0.default or true);
654 }) [ ];
655}
656```
657
658In particular, note that the argument given as `--src` is copied
659verbatim to the source. If we look at a more complicated
660dependencies, for instance by adding a single line `libc="*"` to our
661`Cargo.toml`, we first need to run `cargo build` to update the
662`Cargo.lock`. Then, `carnix` needs to be run again, and produces the
663following nix file:
664
665```nix
666# Generated by carnix 0.6.5: carnix -o hello.nix --src ./. Cargo.lock --standalone
667{ stdenv, buildRustCrate, fetchgit }:
668let kernel = stdenv.buildPlatform.parsed.kernel.name;
669 # ... (content skipped)
670in
671rec {
672 hello = f: hello_0_1_0 { features = hello_0_1_0_features { hello_0_1_0 = f; }; };
673 hello_0_1_0_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate {
674 crateName = "hello";
675 version = "0.1.0";
676 authors = [ "pe@pijul.org <pe@pijul.org>" ];
677 src = ./.;
678 inherit dependencies buildDependencies features;
679 };
680 libc_0_2_36_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate {
681 crateName = "libc";
682 version = "0.2.36";
683 authors = [ "The Rust Project Developers" ];
684 sha256 = "01633h4yfqm0s302fm0dlba469bx8y6cs4nqc8bqrmjqxfxn515l";
685 inherit dependencies buildDependencies features;
686 };
687 hello_0_1_0 = { features?(hello_0_1_0_features {}) }: hello_0_1_0_ {
688 dependencies = mapFeatures features ([ libc_0_2_36 ]);
689 };
690 hello_0_1_0_features = f: updateFeatures f (rec {
691 hello_0_1_0.default = (f.hello_0_1_0.default or true);
692 libc_0_2_36.default = true;
693 }) [ libc_0_2_36_features ];
694 libc_0_2_36 = { features?(libc_0_2_36_features {}) }: libc_0_2_36_ {
695 features = mkFeatures (features.libc_0_2_36 or {});
696 };
697 libc_0_2_36_features = f: updateFeatures f (rec {
698 libc_0_2_36.default = (f.libc_0_2_36.default or true);
699 libc_0_2_36.use_std =
700 (f.libc_0_2_36.use_std or false) ||
701 (f.libc_0_2_36.default or false) ||
702 (libc_0_2_36.default or false);
703 }) [];
704}
705```
706
707Here, the `libc` crate has no `src` attribute, so `buildRustCrate`
708will fetch it from [crates.io](https://crates.io). A `sha256`
709attribute is still needed for Nix purity.
710
711### Handling external dependencies {#handling-external-dependencies}
712
713Some crates require external libraries. For crates from
714[crates.io](https://crates.io), such libraries can be specified in
715`defaultCrateOverrides` package in nixpkgs itself.
716
717Starting from that file, one can add more overrides, to add features
718or build inputs by overriding the hello crate in a separate file.
719
720```nix
721with import <nixpkgs> {};
722((import ./hello.nix).hello {}).override {
723 crateOverrides = defaultCrateOverrides // {
724 hello = attrs: { buildInputs = [ openssl ]; };
725 };
726}
727```
728
729Here, `crateOverrides` is expected to be a attribute set, where the
730key is the crate name without version number and the value a function.
731The function gets all attributes passed to `buildRustCrate` as first
732argument and returns a set that contains all attribute that should be
733overwritten.
734
735For more complicated cases, such as when parts of the crate's
736derivation depend on the crate's version, the `attrs` argument of
737the override above can be read, as in the following example, which
738patches the derivation:
739
740```nix
741with import <nixpkgs> {};
742((import ./hello.nix).hello {}).override {
743 crateOverrides = defaultCrateOverrides // {
744 hello = attrs: lib.optionalAttrs (lib.versionAtLeast attrs.version "1.0") {
745 postPatch = ''
746 substituteInPlace lib/zoneinfo.rs \
747 --replace "/usr/share/zoneinfo" "${tzdata}/share/zoneinfo"
748 '';
749 };
750 };
751}
752```
753
754Another situation is when we want to override a nested
755dependency. This actually works in the exact same way, since the
756`crateOverrides` parameter is forwarded to the crate's
757dependencies. For instance, to override the build inputs for crate
758`libc` in the example above, where `libc` is a dependency of the main
759crate, we could do:
760
761```nix
762with import <nixpkgs> {};
763((import hello.nix).hello {}).override {
764 crateOverrides = defaultCrateOverrides // {
765 libc = attrs: { buildInputs = []; };
766 };
767}
768```
769
770### Options and phases configuration {#options-and-phases-configuration}
771
772Actually, the overrides introduced in the previous section are more
773general. A number of other parameters can be overridden:
774
775- The version of `rustc` used to compile the crate:
776
777 ```nix
778 (hello {}).override { rust = pkgs.rust; };
779 ```
780
781- Whether to build in release mode or debug mode (release mode by
782 default):
783
784 ```nix
785 (hello {}).override { release = false; };
786 ```
787
788- Whether to print the commands sent to `rustc` when building
789 (equivalent to `--verbose` in cargo:
790
791 ```nix
792 (hello {}).override { verbose = false; };
793 ```
794
795- Extra arguments to be passed to `rustc`:
796
797 ```nix
798 (hello {}).override { extraRustcOpts = "-Z debuginfo=2"; };
799 ```
800
801- Phases, just like in any other derivation, can be specified using
802 the following attributes: `preUnpack`, `postUnpack`, `prePatch`,
803 `patches`, `postPatch`, `preConfigure` (in the case of a Rust crate,
804 this is run before calling the "build" script), `postConfigure`
805 (after the "build" script),`preBuild`, `postBuild`, `preInstall` and
806 `postInstall`. As an example, here is how to create a new module
807 before running the build script:
808
809 ```nix
810 (hello {}).override {
811 preConfigure = ''
812 echo "pub const PATH=\"${hi.out}\";" >> src/path.rs"
813 '';
814 };
815 ```
816
817### Features {#features}
818
819One can also supply features switches. For example, if we want to
820compile `diesel_cli` only with the `postgres` feature, and no default
821features, we would write:
822
823```nix
824(callPackage ./diesel.nix {}).diesel {
825 default = false;
826 postgres = true;
827}
828```
829
830Where `diesel.nix` is the file generated by Carnix, as explained above.
831
832## Setting Up `nix-shell` {#setting-up-nix-shell}
833
834Oftentimes you want to develop code from within `nix-shell`. Unfortunately
835`buildRustCrate` does not support common `nix-shell` operations directly
836(see [this issue](https://github.com/NixOS/nixpkgs/issues/37945))
837so we will use `stdenv.mkDerivation` instead.
838
839Using the example `hello` project above, we want to do the following:
840
841- Have access to `cargo` and `rustc`
842- Have the `openssl` library available to a crate through it's _normal_
843 compilation mechanism (`pkg-config`).
844
845A typical `shell.nix` might look like:
846
847```nix
848with import <nixpkgs> {};
849
850stdenv.mkDerivation {
851 name = "rust-env";
852 nativeBuildInputs = [
853 rustc cargo
854
855 # Example Build-time Additional Dependencies
856 pkg-config
857 ];
858 buildInputs = [
859 # Example Run-time Additional Dependencies
860 openssl
861 ];
862
863 # Set Environment Variables
864 RUST_BACKTRACE = 1;
865}
866```
867
868You should now be able to run the following:
869
870```ShellSession
871$ nix-shell --pure
872$ cargo build
873$ cargo test
874```
875
876### Controlling Rust Version Inside `nix-shell` {#controlling-rust-version-inside-nix-shell}
877
878To control your rust version (i.e. use nightly) from within `shell.nix` (or
879other nix expressions) you can use the following `shell.nix`
880
881```nix
882# Latest Nightly
883with import <nixpkgs> {};
884let src = fetchFromGitHub {
885 owner = "mozilla";
886 repo = "nixpkgs-mozilla";
887 # commit from: 2019-05-15
888 rev = "9f35c4b09fd44a77227e79ff0c1b4b6a69dff533";
889 sha256 = "18h0nvh55b5an4gmlgfbvwbyqj91bklf1zymis6lbdh75571qaz0";
890 };
891in
892with import "${src.out}/rust-overlay.nix" pkgs pkgs;
893stdenv.mkDerivation {
894 name = "rust-env";
895 buildInputs = [
896 # Note: to use stable, just replace `nightly` with `stable`
897 latest.rustChannels.nightly.rust
898
899 # Add some extra dependencies from `pkgs`
900 pkg-config openssl
901 ];
902
903 # Set Environment Variables
904 RUST_BACKTRACE = 1;
905}
906```
907
908Now run:
909
910```ShellSession
911$ rustc --version
912rustc 1.26.0-nightly (188e693b3 2018-03-26)
913```
914
915To see that you are using nightly.
916
917## Using community Rust overlays {#using-community-rust-overlays}
918
919There are two community maintained approaches to Rust toolchain management:
920- [oxalica's Rust overlay](https://github.com/oxalica/rust-overlay)
921- [fenix](https://github.com/nix-community/fenix)
922
923Oxalica's overlay allows you to select a particular Rust version and components.
924See [their documentation](https://github.com/oxalica/rust-overlay#rust-overlay) for more
925detailed usage.
926
927Fenix is an alternative to `rustup` and can also be used as an overlay.
928
929Both oxalica's overlay and fenix better integrate with nix and cache optimizations.
930Because of this and ergonomics, either of those community projects
931should be preferred to the Mozilla's Rust overlay (`nixpkgs-mozilla`).
932
933### How to select a specific `rustc` and toolchain version {#how-to-select-a-specific-rustc-and-toolchain-version}
934
935You can consume the oxalica overlay and use it to grab a specific Rust toolchain version.
936Here is an example `shell.nix` showing how to grab the current stable toolchain:
937```nix
938{ pkgs ? import <nixpkgs> {
939 overlays = [
940 (import (fetchTarball "https://github.com/oxalica/rust-overlay/archive/master.tar.gz"))
941 ];
942 }
943}:
944pkgs.mkShell {
945 nativeBuildInputs = with pkgs; [
946 pkg-config
947 rust-bin.stable.latest.minimal
948 ];
949}
950```
951
952You can try this out by:
9531. Saving that to `shell.nix`
9542. Executing `nix-shell --pure --command 'rustc --version'`
955
956As of writing, this prints out `rustc 1.56.0 (09c42c458 2021-10-18)`.
957
958### How to use an overlay toolchain in a derivation {#how-to-use-an-overlay-toolchain-in-a-derivation}
959
960You can also use an overlay's Rust toolchain with `buildRustPackage`.
961The below snippet demonstrates invoking `buildRustPackage` with an oxalica overlay selected Rust toolchain:
962```nix
963with import <nixpkgs> {
964 overlays = [
965 (import (fetchTarball "https://github.com/oxalica/rust-overlay/archive/master.tar.gz"))
966 ];
967};
968
969rustPlatform.buildRustPackage rec {
970 pname = "ripgrep";
971 version = "12.1.1";
972 nativeBuildInputs = [
973 rust-bin.stable.latest.minimal
974 ];
975
976 src = fetchFromGitHub {
977 owner = "BurntSushi";
978 repo = "ripgrep";
979 rev = version;
980 sha256 = "1hqps7l5qrjh9f914r5i6kmcz6f1yb951nv4lby0cjnp5l253kps";
981 };
982
983 cargoSha256 = "03wf9r2csi6jpa7v5sw5lpxkrk4wfzwmzx7k3991q3bdjzcwnnwp";
984
985 meta = with lib; {
986 description = "A fast line-oriented regex search tool, similar to ag and ack";
987 homepage = "https://github.com/BurntSushi/ripgrep";
988 license = licenses.unlicense;
989 maintainers = [ maintainers.tailhook ];
990 };
991}
992```
993
994Follow the below steps to try that snippet.
9951. create a new directory
9961. save the above snippet as `default.nix` in that directory
9971. cd into that directory and run `nix-build`
998
999### Rust overlay installation {#rust-overlay-installation}
1000
1001You can use this overlay by either changing your local nixpkgs configuration,
1002or by adding the overlay declaratively in a nix expression, e.g. in `configuration.nix`.
1003For more information see [the manual on installing overlays](#sec-overlays-install).
1004
1005### Declarative Rust overlay installation {#declarative-rust-overlay-installation}
1006
1007This snippet shows how to use oxalica's Rust overlay.
1008Add the following to your `configuration.nix`, `home-configuration.nix`, `shell.nix`, or similar:
1009
1010```nix
1011{ pkgs ? import <nixpkgs> {
1012 overlays = [
1013 (import (builtins.fetchTarball "https://github.com/oxalica/rust-overlay/archive/master.tar.gz"))
1014 # Further overlays go here
1015 ];
1016 };
1017};
1018```
1019
1020Note that this will fetch the latest overlay version when rebuilding your system.