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