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