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