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