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