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.rustcTarget` 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.rustcTarget = "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.rustcTarget` with its name, and
278 `stdenv.hostPlatform.rust.platform` with the value. The value will be
279 serialized to JSON in a file called
280 `${stdenv.hostPlatform.rust.rustcTarget}.json`, and the path of that file
281 will be used instead.
282
283 For example:
284
285 ```nix
286 import <nixpkgs> {
287 crossSystem = (import <nixpkgs/lib>).systems.examples.armhf-embedded // {
288 rust.rustcTarget = "thumb-crazy";
289 rust.platform = {
290 foo = "";
291 bar = "";
292 };
293 };
294 }
295 ```
296
297 will result in:
298
299 ```shell
300 --target /nix/store/asdfasdfsadf-thumb-crazy.json # contains {"foo":"","bar":""}
301 ```
302
303Note that currently custom targets aren't compiled with `std`, so `cargo test`
304will fail. This can be ignored by adding `doCheck = false;` to your derivation.
305
306### Running package tests {#running-package-tests}
307
308When using `buildRustPackage`, the `checkPhase` is enabled by default and runs
309`cargo test` on the package to build. To make sure that we don't compile the
310sources twice and to actually test the artifacts that will be used at runtime,
311the tests will be ran in the `release` mode by default.
312
313However, in some cases the test-suite of a package doesn't work properly in the
314`release` mode. For these situations, the mode for `checkPhase` can be changed like
315so:
316
317```nix
318rustPlatform.buildRustPackage {
319 # ...
320 checkType = "debug";
321}
322```
323
324Please note that the code will be compiled twice here: once in `release` mode
325for the `buildPhase`, and again in `debug` mode for the `checkPhase`.
326
327Test flags, e.g., `--package foo`, can be passed to `cargo test` via the
328`cargoTestFlags` attribute.
329
330Another attribute, called `checkFlags`, is used to pass arguments to the test
331binary itself, as stated
332[here](https://doc.rust-lang.org/cargo/commands/cargo-test.html).
333
334#### Tests relying on the structure of the `target/` directory {#tests-relying-on-the-structure-of-the-target-directory}
335
336Some tests may rely on the structure of the `target/` directory. Those tests
337are likely to fail because we use `cargo --target` during the build. This means that
338the artifacts
339[are stored in `target/<architecture>/release/`](https://doc.rust-lang.org/cargo/guide/build-cache.html),
340rather than in `target/release/`.
341
342This can only be worked around by patching the affected tests accordingly.
343
344#### Disabling package-tests {#disabling-package-tests}
345
346In some instances, it may be necessary to disable testing altogether (with `doCheck = false;`):
347
348* If no tests exist -- the `checkPhase` should be explicitly disabled to skip
349 unnecessary build steps to speed up the build.
350* If tests are highly impure (e.g. due to network usage).
351
352There will obviously be some corner-cases not listed above where it's sensible to disable tests.
353The above are just guidelines, and exceptions may be granted on a case-by-case basis.
354
355However, please check if it's possible to disable a problematic subset of the
356test suite and leave a comment explaining your reasoning.
357
358This can be achieved with `--skip` in `checkFlags`:
359
360```nix
361rustPlatform.buildRustPackage {
362 # ...
363 checkFlags = [
364 # reason for disabling test
365 "--skip=example::tests:example_test"
366 ];
367}
368```
369
370#### Using `cargo-nextest` {#using-cargo-nextest}
371
372Tests can be run with [cargo-nextest](https://github.com/nextest-rs/nextest)
373by setting `useNextest = true`. The same options still apply, but nextest
374accepts a different set of arguments and the settings might need to be
375adapted to be compatible with cargo-nextest.
376
377```nix
378rustPlatform.buildRustPackage {
379 # ...
380 useNextest = true;
381}
382```
383
384#### Setting `test-threads` {#setting-test-threads}
385
386`buildRustPackage` will use parallel test threads by default,
387sometimes it may be necessary to disable this so the tests run consecutively.
388
389```nix
390rustPlatform.buildRustPackage {
391 # ...
392 dontUseCargoParallelTests = true;
393}
394```
395
396### Building a package in `debug` mode {#building-a-package-in-debug-mode}
397
398By default, `buildRustPackage` will use `release` mode for builds. If a package
399should be built in `debug` mode, it can be configured like so:
400
401```nix
402rustPlatform.buildRustPackage {
403 # ...
404 buildType = "debug";
405}
406```
407
408In this scenario, the `checkPhase` will be ran in `debug` mode as well.
409
410### Custom `build`/`install`-procedures {#custom-buildinstall-procedures}
411
412Some packages may use custom scripts for building/installing, e.g. with a `Makefile`.
413In these cases, it's recommended to override the `buildPhase`/`installPhase`/`checkPhase`.
414
415Otherwise, some steps may fail because of the modified directory structure of `target/`.
416
417### 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}
418
419`buildRustPackage` needs a `Cargo.lock` file to get all dependencies in the
420source code in a reproducible way. If it is missing or out of date, one can use
421the `cargoPatches` attribute to update or add it.
422
423```nix
424rustPlatform.buildRustPackage {
425 # ...
426 cargoPatches = [
427 # a patch file to add/update Cargo.lock in the source code
428 ./add-Cargo.lock.patch
429 ];
430}
431```
432
433### Compiling non-Rust packages that include Rust code {#compiling-non-rust-packages-that-include-rust-code}
434
435Several non-Rust packages incorporate Rust code for performance- or
436security-sensitive parts. `rustPlatform` exposes several functions and
437hooks that can be used to integrate Cargo in non-Rust packages.
438
439#### Vendoring of dependencies {#vendoring-of-dependencies}
440
441Since network access is not allowed in sandboxed builds, Rust crate
442dependencies need to be retrieved using a fetcher. `rustPlatform`
443provides the `fetchCargoVendor` fetcher, which vendors all
444dependencies of a crate. For example, given a source path `src`
445containing `Cargo.toml` and `Cargo.lock`, `fetchCargoVendor`
446can be used as follows:
447
448```nix
449{
450 cargoDeps = rustPlatform.fetchCargoVendor {
451 inherit src;
452 hash = "sha256-BoHIN/519Top1NUBjpB/oEMqi86Omt3zTQcXFWqrek0=";
453 };
454}
455```
456
457The `src` attribute is required, as well as a hash specified through
458one of the `hash` attribute. The following optional attributes can
459also be used:
460
461* `name`: the name that is used for the dependencies tarball. If
462 `name` is not specified, then the name `cargo-deps` will be used.
463* `sourceRoot`: when the `Cargo.lock`/`Cargo.toml` are in a
464 subdirectory, `sourceRoot` specifies the relative path to these
465 files.
466* `patches`: patches to apply before vendoring. This is useful when
467 the `Cargo.lock`/`Cargo.toml` files need to be patched before
468 vendoring.
469
470If a `Cargo.lock` file is available, you can alternatively use the
471`importCargoLock` function. In contrast to `fetchCargoVendor`, this
472function does not require a hash (unless git dependencies are used)
473and fetches every dependency as a separate fixed-output derivation.
474`importCargoLock` can be used as follows:
475
476```nix
477{ cargoDeps = rustPlatform.importCargoLock { lockFile = ./Cargo.lock; }; }
478```
479
480If the `Cargo.lock` file includes git dependencies, then their output
481hashes need to be specified since they are not available through the
482lock file. For example:
483
484```nix
485{
486 cargoDeps = rustPlatform.importCargoLock {
487 lockFile = ./Cargo.lock;
488 outputHashes = {
489 "rand-0.8.3" = "0ya2hia3cn31qa8894s3av2s8j5bjwb6yq92k0jsnlx7jid0jwqa";
490 };
491 };
492}
493```
494
495If you do not specify an output hash for a git dependency, building
496`cargoDeps` will fail and inform you of which crate needs to be
497added. To find the correct hash, you can first use `lib.fakeSha256` or
498`lib.fakeHash` as a stub hash. Building `cargoDeps` will then inform
499you of the correct hash.
500
501#### Hooks {#hooks}
502
503`rustPlatform` provides the following hooks to automate Cargo builds:
504
505* `cargoSetupHook`: configure Cargo to use dependencies vendored
506 through `fetchCargoVendor` or `importCargoLock`. This hook uses the
507 `cargoDeps` environment variable to find the vendored
508 dependencies. If a project already vendors its dependencies, the
509 variable `cargoVendorDir` can be used instead. When the
510 `Cargo.toml`/`Cargo.lock` files are not in `sourceRoot`, then the
511 optional `cargoRoot` is used to specify the Cargo root directory
512 relative to `sourceRoot`.
513* `cargoBuildHook`: use Cargo to build a crate. If the crate to be
514 built is a crate in e.g. a Cargo workspace, the relative path to the
515 crate to build can be set through the optional `buildAndTestSubdir`
516 environment variable. Features can be specified with
517 `cargoBuildNoDefaultFeatures` and `cargoBuildFeatures`. Additional
518 Cargo build flags can be passed through `cargoBuildFlags`.
519* `maturinBuildHook`: use [Maturin](https://github.com/PyO3/maturin)
520 to build a Python wheel. Similar to `cargoBuildHook`, the optional
521 variable `buildAndTestSubdir` can be used to build a crate in a
522 Cargo workspace. Additional Maturin flags can be passed through
523 `maturinBuildFlags`.
524* `cargoCheckHook`: run tests using Cargo. The build type for checks
525 can be set using `cargoCheckType`. Features can be specified with
526 `cargoCheckNoDefaultFeatures` and `cargoCheckFeatures`. Additional
527 flags can be passed to the tests using `checkFlags` and
528 `checkFlagsArray`. By default, tests are run in parallel. This can
529 be disabled by setting `dontUseCargoParallelTests`.
530* `cargoNextestHook`: run tests using
531 [cargo-nextest](https://github.com/nextest-rs/nextest). The same
532 options for `cargoCheckHook` also applies to `cargoNextestHook`.
533* `cargoInstallHook`: install binaries and static/shared libraries
534 that were built using `cargoBuildHook`.
535* `bindgenHook`: for crates which use `bindgen` as a build dependency, lets
536 `bindgen` find `libclang` and `libclang` find the libraries in `buildInputs`.
537
538#### Examples {#examples}
539
540#### Python package using `setuptools-rust` {#python-package-using-setuptools-rust}
541
542For Python packages using `setuptools-rust`, you can use
543`fetchCargoVendor` and `cargoSetupHook` to retrieve and set up Cargo
544dependencies. The build itself is then performed by
545`buildPythonPackage`.
546
547The following example outlines how the `tokenizers` Python package is
548built. Since the Python package is in the `source/bindings/python`
549directory of the `tokenizers` project's source archive, we use
550`sourceRoot` to point the tooling to this directory:
551
552```nix
553{
554 fetchFromGitHub,
555 buildPythonPackage,
556 cargo,
557 rustPlatform,
558 rustc,
559 setuptools-rust,
560}:
561
562buildPythonPackage rec {
563 pname = "tokenizers";
564 version = "0.10.0";
565
566 src = fetchFromGitHub {
567 owner = "huggingface";
568 repo = "tokenizers";
569 tag = "python-v${version}";
570 hash = "sha256-rQ2hRV52naEf6PvRsWVCTN7B1oXAQGmnpJw4iIdhamw=";
571 };
572
573 cargoDeps = rustPlatform.fetchCargoVendor {
574 inherit
575 pname
576 version
577 src
578 sourceRoot
579 ;
580 hash = "sha256-RO1m8wEd5Ic2M9q+zFHeCJWhCr4Sv3CEWd08mkxsBec=";
581 };
582
583 sourceRoot = "${src.name}/bindings/python";
584
585 nativeBuildInputs = [
586 cargo
587 rustPlatform.cargoSetupHook
588 rustc
589 setuptools-rust
590 ];
591
592 # ...
593}
594```
595
596In some projects, the Rust crate is not in the main Python source
597directory. In such cases, the `cargoRoot` attribute can be used to
598specify the crate's directory relative to `sourceRoot`. In the
599following example, the crate is in `src/rust`, as specified in the
600`cargoRoot` attribute. Note that we also need to pass in `cargoRoot`
601to `fetchCargoVendor`.
602
603```nix
604{
605 buildPythonPackage,
606 fetchPypi,
607 rustPlatform,
608 setuptools-rust,
609 openssl,
610}:
611
612buildPythonPackage rec {
613 pname = "cryptography";
614 version = "3.4.2"; # Also update the hash in vectors.nix
615
616 src = fetchPypi {
617 inherit pname version;
618 hash = "sha256-xGDilsjLOnls3MfVbGKnj80KCUCczZxlis5PmHzpNcQ=";
619 };
620
621 cargoDeps = rustPlatform.fetchCargoVendor {
622 inherit
623 pname
624 version
625 src
626 cargoRoot
627 ;
628 hash = "sha256-ctUt8maCjnGddKPf+Ii++wKsAXA1h+JM6zKQNXXwJqQ=";
629 };
630
631 cargoRoot = "src/rust";
632
633 # ...
634}
635```
636
637#### Python package using `maturin` {#python-package-using-maturin}
638
639Python packages that use [Maturin](https://github.com/PyO3/maturin)
640can be built with `fetchCargoVendor`, `cargoSetupHook`, and
641`maturinBuildHook`. For example, the following (partial) derivation
642builds the `retworkx` Python package. `fetchCargoVendor` and
643`cargoSetupHook` are used to fetch and set up the crate dependencies.
644`maturinBuildHook` is used to perform the build.
645
646```nix
647{
648 lib,
649 buildPythonPackage,
650 rustPlatform,
651 fetchFromGitHub,
652}:
653
654buildPythonPackage rec {
655 pname = "retworkx";
656 version = "0.6.0";
657 pyproject = true;
658
659 src = fetchFromGitHub {
660 owner = "Qiskit";
661 repo = "retworkx";
662 tag = version;
663 hash = "sha256-11n30ldg3y3y6qxg3hbj837pnbwjkqw3nxq6frds647mmmprrd20=";
664 };
665
666 cargoDeps = rustPlatform.fetchCargoVendor {
667 inherit pname version src;
668 hash = "sha256-QsPCQhNZKYCAogQriQX6pBYQUDAIUsEdRX/63dAqTzg=";
669 };
670
671 nativeBuildInputs = with rustPlatform; [
672 cargoSetupHook
673 maturinBuildHook
674 ];
675
676 # ...
677}
678```
679
680#### Rust package built with `meson` {#rust-package-built-with-meson}
681
682Some 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.
683
684```nix
685{
686 lib,
687 stdenv,
688 fetchFromGitLab,
689 meson,
690 ninja,
691 pkg-config,
692 rustPlatform,
693 rustc,
694 cargo,
695 wrapGAppsHook4,
696 blueprint-compiler,
697 libadwaita,
698 libsecret,
699 tinysparql,
700}:
701
702stdenv.mkDerivation (finalAttrs: {
703 pname = "health";
704 version = "0.95.0";
705
706 src = fetchFromGitLab {
707 domain = "gitlab.gnome.org";
708 owner = "World";
709 repo = "health";
710 tag = finalAttrs.version;
711 hash = "sha256-PrNPprSS98yN8b8yw2G6hzTSaoE65VbsM3q7FVB4mds=";
712 };
713
714 cargoDeps = rustPlatform.fetchCargoVendor {
715 inherit (finalAttrs) pname version src;
716 hash = "sha256-eR1ZGtTZQNhofFUEjI7IX16sMKPJmAl7aIFfPJukecg=";
717 };
718
719 nativeBuildInputs = [
720 meson
721 ninja
722 pkg-config
723 rustPlatform.cargoSetupHook
724 rustc
725 cargo
726 wrapGAppsHook4
727 blueprint-compiler
728 ];
729
730 buildInputs = [
731 libadwaita
732 libsecret
733 tinysparql
734 ];
735
736 # ...
737})
738```
739
740## `buildRustCrate`: Compiling Rust crates using Nix instead of Cargo {#compiling-rust-crates-using-nix-instead-of-cargo}
741
742### Simple operation {#simple-operation}
743
744When run, `cargo build` produces a file called `Cargo.lock`,
745containing pinned versions of all dependencies. Nixpkgs contains a
746tool called `crate2Nix` (`nix-shell -p crate2nix`), which can be
747used to turn a `Cargo.lock` into a Nix expression. That Nix
748expression calls `rustc` directly (hence bypassing Cargo), and can
749be used to compile a crate and all its dependencies.
750
751See [`crate2nix`'s documentation](https://github.com/kolloch/crate2nix#known-restrictions)
752for instructions on how to use it.
753
754### Handling external dependencies {#handling-external-dependencies}
755
756Some crates require external libraries. For crates from
757[crates.io](https://crates.io), such libraries can be specified in
758`defaultCrateOverrides` package in nixpkgs itself.
759
760Starting from that file, one can add more overrides, to add features
761or build inputs by overriding the hello crate in a separate file.
762
763```nix
764with import <nixpkgs> { };
765((import ./hello.nix).hello { }).override {
766 crateOverrides = defaultCrateOverrides // {
767 hello = attrs: { buildInputs = [ openssl ]; };
768 };
769}
770```
771
772Here, `crateOverrides` is expected to be a attribute set, where the
773key is the crate name without version number and the value a function.
774The function gets all attributes passed to `buildRustCrate` as first
775argument and returns a set that contains all attribute that should be
776overwritten.
777
778For more complicated cases, such as when parts of the crate's
779derivation depend on the crate's version, the `attrs` argument of
780the override above can be read, as in the following example, which
781patches the derivation:
782
783```nix
784with import <nixpkgs> { };
785((import ./hello.nix).hello { }).override {
786 crateOverrides = defaultCrateOverrides // {
787 hello =
788 attrs:
789 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
884 cargo
885
886 # Example Build-time Additional Dependencies
887 pkg-config
888 ];
889 buildInputs = [
890 # Example Run-time Additional Dependencies
891 openssl
892 ];
893
894 # Set Environment Variables
895 RUST_BACKTRACE = 1;
896}
897```
898
899You should now be able to run the following:
900
901```ShellSession
902$ nix-shell --pure
903$ cargo build
904$ cargo test
905```
906
907## Using community maintained Rust toolchains {#using-community-maintained-rust-toolchains}
908
909::: {.note}
910The 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.
911To package things that require Rust nightly, `RUSTC_BOOTSTRAP = true;` can sometimes be used as a hack.
912:::
913
914There are two community maintained approaches to Rust toolchain management:
915- [oxalica's Rust overlay](https://github.com/oxalica/rust-overlay)
916- [fenix](https://github.com/nix-community/fenix)
917
918Despite their names, both projects provides a similar set of packages and overlays under different APIs.
919
920Oxalica's overlay allows you to select a particular Rust version without you providing a hash or a flake input,
921but comes with a larger git repository than fenix.
922
923Fenix also provides `rust-analyzer` nightly in addition to the Rust toolchains.
924
925Both oxalica's overlay and fenix better integrate with nix and cache optimizations.
926Because of this and ergonomics, either of those community projects
927should be preferred to the Mozilla's Rust overlay ([nixpkgs-mozilla](https://github.com/mozilla/nixpkgs-mozilla)).
928
929The following documentation demonstrates examples using fenix and oxalica's Rust overlay
930with `nix-shell` and building derivations. More advanced usages like flake usage
931are documented in their own repositories.
932
933### Using Rust nightly with `nix-shell` {#using-rust-nightly-with-nix-shell}
934
935Here is a simple `shell.nix` that provides Rust nightly (default profile) using fenix:
936
937```nix
938with import <nixpkgs> { };
939let
940 fenix = callPackage (fetchFromGitHub {
941 owner = "nix-community";
942 repo = "fenix";
943 # commit from: 2023-03-03
944 rev = "e2ea04982b892263c4d939f1cc3bf60a9c4deaa1";
945 hash = "sha256-AsOim1A8KKtMWIxG+lXh5Q4P2bhOZjoUhFWJ1EuZNNk=";
946 }) { };
947in
948mkShell {
949 name = "rust-env";
950 nativeBuildInputs = [
951 # Note: to use stable, just replace `default` with `stable`
952 fenix.default.toolchain
953
954 # Example Build-time Additional Dependencies
955 pkg-config
956 ];
957 buildInputs = [
958 # Example Run-time Additional Dependencies
959 openssl
960 ];
961
962 # Set Environment Variables
963 RUST_BACKTRACE = 1;
964}
965```
966
967Save this to `shell.nix`, then run:
968
969```ShellSession
970$ rustc --version
971rustc 1.69.0-nightly (13471d3b2 2023-03-02)
972```
973
974To see that you are using nightly.
975
976Oxalica's Rust overlay has more complete examples of `shell.nix` (and cross compilation) under its
977[`examples` directory](https://github.com/oxalica/rust-overlay/tree/e53e8853aa7b0688bc270e9e6a681d22e01cf299/examples).
978
979### Using Rust nightly in a derivation with `buildRustPackage` {#using-rust-nightly-in-a-derivation-with-buildrustpackage}
980
981You can also use Rust nightly to build rust packages using `makeRustPlatform`.
982The below snippet demonstrates invoking `buildRustPackage` with a Rust toolchain from oxalica's overlay:
983
984```nix
985with import <nixpkgs> {
986 overlays = [
987 (import (fetchTarball "https://github.com/oxalica/rust-overlay/archive/master.tar.gz"))
988 ];
989};
990let
991 rustPlatform = makeRustPlatform {
992 cargo = rust-bin.selectLatestNightlyWith (toolchain: toolchain.default);
993 rustc = rust-bin.selectLatestNightlyWith (toolchain: toolchain.default);
994 };
995
996in
997rustPlatform.buildRustPackage (finalAttrs: {
998 pname = "ripgrep";
999 version = "14.1.1";
1000
1001 src = fetchFromGitHub {
1002 owner = "BurntSushi";
1003 repo = "ripgrep";
1004 tag = finalAttrs.version;
1005 hash = "sha256-gyWnahj1A+iXUQlQ1O1H1u7K5euYQOld9qWm99Vjaeg=";
1006 };
1007
1008 cargoHash = "sha256-9atn5qyBDy4P6iUoHFhg+TV6Ur71fiah4oTJbBMeEy4=";
1009
1010 # Tests require network access. Skipping.
1011 doCheck = false;
1012
1013 meta = {
1014 description = "Fast line-oriented regex search tool, similar to ag and ack";
1015 homepage = "https://github.com/BurntSushi/ripgrep";
1016 license = with lib.licenses; [
1017 mit
1018 unlicense
1019 ];
1020 maintainers = with lib.maintainers; [ ];
1021 };
1022})
1023```
1024
1025Follow the below steps to try that snippet.
10261. save the above snippet as `default.nix` in that directory
10272. cd into that directory and run `nix-build`
1028
1029Fenix also has examples with `buildRustPackage`,
1030[crane](https://github.com/ipetkov/crane),
1031[naersk](https://github.com/nix-community/naersk),
1032and cross compilation in its [Examples](https://github.com/nix-community/fenix#examples) section.
1033
1034## Using `git bisect` on the Rust compiler {#using-git-bisect-on-the-rust-compiler}
1035
1036Sometimes an upgrade of the Rust compiler (`rustc`) will break a
1037downstream package. In these situations, being able to `git bisect`
1038the `rustc` version history to find the offending commit is quite
1039useful. Nixpkgs makes it easy to do this.
1040
1041First, roll back your nixpkgs to a commit in which its `rustc` used
1042*the most recent one which doesn't have the problem.* You'll need
1043to do this because of `rustc`'s extremely aggressive
1044version-pinning.
1045
1046Next, add the following overlay, updating the Rust version to the
1047one in your rolled-back nixpkgs, and replacing `/git/scratch/rust`
1048with the path into which you have `git clone`d the `rustc` git
1049repository:
1050
1051```nix
1052(
1053 final: prev: # lib.optionalAttrs prev.stdenv.targetPlatform.isAarch64
1054 {
1055 rust_1_72 = lib.updateManyAttrsByPath [
1056 {
1057 path = [
1058 "packages"
1059 "stable"
1060 ];
1061 update =
1062 old:
1063 old.overrideScope (
1064 final: prev: {
1065 rustc-unwrapped = prev.rustc-unwrapped.overrideAttrs (_: {
1066 src = lib.cleanSource /git/scratch/rust;
1067 # do *not* put passthru.isReleaseTarball=true here
1068 });
1069 }
1070 );
1071 }
1072 ] prev.rust_1_72;
1073 })
1074```
1075
1076If the problem you're troubleshooting only manifests when
1077cross-compiling you can uncomment the `lib.optionalAttrs` in the
1078example above, and replace `isAarch64` with the target that is
1079having problems. This will speed up your bisect quite a bit, since
1080the host compiler won't need to be rebuilt.
1081
1082Now, you can start a `git bisect` in the directory where you checked
1083out the `rustc` source code. It is recommended to select the
1084endpoint commits by searching backwards from `origin/master` for the
1085*commits which added the release notes for the versions in
1086question.* If you set the endpoints to commits on the release
1087branches (i.e. the release tags), git-bisect will often get confused
1088by the complex merge-commit structures it will need to traverse.
1089
1090The command loop you'll want to use for bisecting looks like this:
1091
1092```bash
1093git bisect {good,bad} # depending on result of last build
1094git submodule update --init
1095CARGO_NET_OFFLINE=false cargo vendor \
1096 --sync ./src/tools/cargo/Cargo.toml \
1097 --sync ./src/tools/rust-analyzer/Cargo.toml \
1098 --sync ./compiler/rustc_codegen_cranelift/Cargo.toml \
1099 --sync ./src/bootstrap/Cargo.toml
1100nix-build $NIXPKGS -A package-broken-by-rust-changes
1101```
1102
1103The `git submodule update --init` and `cargo vendor` commands above
1104require network access, so they can't be performed from within the
1105`rustc` derivation, unfortunately.