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