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