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