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