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