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