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