1# Rust {#rust} 2 3To install the rust compiler and cargo put 4 5```nix 6environment.systemPackages = [ 7 rustc 8 cargo 9]; 10``` 11 12into your `configuration.nix` or bring them into scope with `nix-shell -p rustc cargo`. 13 14For other versions such as daily builds (beta and nightly), 15use either `rustup` from nixpkgs (which will manage the rust installation in your home directory), 16or use a community maintained [Rust overlay](#using-community-rust-overlays). 17 18## Compiling Rust applications with Cargo {#compiling-rust-applications-with-cargo} 19 20Rust applications are packaged by using the `buildRustPackage` helper from `rustPlatform`: 21 22```nix 23{ lib, fetchFromGitHub, rustPlatform }: 24 25rustPlatform.buildRustPackage rec { 26 pname = "ripgrep"; 27 version = "12.1.1"; 28 29 src = fetchFromGitHub { 30 owner = "BurntSushi"; 31 repo = pname; 32 rev = version; 33 sha256 = "1hqps7l5qrjh9f914r5i6kmcz6f1yb951nv4lby0cjnp5l253kps"; 34 }; 35 36 cargoSha256 = "03wf9r2csi6jpa7v5sw5lpxkrk4wfzwmzx7k3991q3bdjzcwnnwp"; 37 38 meta = with lib; { 39 description = "A fast line-oriented regex search tool, similar to ag and ack"; 40 homepage = "https://github.com/BurntSushi/ripgrep"; 41 license = licenses.unlicense; 42 maintainers = [ maintainers.tailhook ]; 43 }; 44} 45``` 46 47`buildRustPackage` requires either the `cargoSha256` or the 48`cargoHash` attribute which is computed over all crate sources of this 49package. `cargoHash256` is used for traditional Nix SHA-256 hashes, 50such as the one in the example above. `cargoHash` should instead be 51used for [SRI](https://www.w3.org/TR/SRI/) hashes. For example: 52 53```nix 54 cargoHash = "sha256-l1vL2ZdtDRxSGvP0X/l3nMw8+6WF67KPutJEzUROjg8="; 55``` 56 57Both types of hashes are permitted when contributing to nixpkgs. The 58Cargo hash is obtained by inserting a fake checksum into the 59expression and building the package once. The correct checksum can 60then be taken from the failed build. A fake hash can be used for 61`cargoSha256` as follows: 62 63```nix 64 cargoSha256 = lib.fakeSha256; 65``` 66 67For `cargoHash` you can use: 68 69```nix 70 cargoHash = lib.fakeHash; 71``` 72 73Per the instructions in the [Cargo Book](https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html) 74best practices guide, Rust applications should always commit the `Cargo.lock` 75file in git to ensure a reproducible build. However, a few packages do not, and 76Nix depends on this file, so if it is missing you can use `cargoPatches` to 77apply it in the `patchPhase`. Consider sending a PR upstream with a note to the 78maintainer describing why it's important to include in the application. 79 80The fetcher will verify that the `Cargo.lock` file is in sync with the `src` 81attribute, and fail the build if not. It will also will compress the vendor 82directory into a tar.gz archive. 83 84The tarball with vendored dependencies contains a directory with the 85package's `name`, which is normally composed of `pname` and 86`version`. This means that the vendored dependencies hash 87(`cargoSha256`/`cargoHash`) is dependent on the package name and 88version. The `cargoDepsName` attribute can be used to use another name 89for the directory of vendored dependencies. For example, the hash can 90be made invariant to the version by setting `cargoDepsName` to 91`pname`: 92 93```nix 94rustPlatform.buildRustPackage rec { 95 pname = "broot"; 96 version = "1.2.0"; 97 98 src = fetchCrate { 99 inherit pname version; 100 sha256 = "1mqaynrqaas82f5957lx31x80v74zwmwmjxxlbywajb61vh00d38"; 101 }; 102 103 cargoHash = "sha256-JmBZcDVYJaK1cK05cxx5BrnGWp4t8ca6FLUbvIot67s="; 104 cargoDepsName = pname; 105 106 # ... 107} 108``` 109 110### Importing a `Cargo.lock` file {#importing-a-cargo.lock-file} 111 112Using `cargoSha256` or `cargoHash` is tedious when using 113`buildRustPackage` within a project, since it requires that the hash 114is updated after every change to `Cargo.lock`. Therefore, 115`buildRustPackage` also supports vendoring dependencies directly from 116a `Cargo.lock` file using the `cargoLock` argument. For example: 117 118```nix 119rustPlatform.buildRustPackage { 120 pname = "myproject"; 121 version = "1.0.0"; 122 123 cargoLock = { 124 lockFile = ./Cargo.lock; 125 }; 126 127 # ... 128} 129``` 130 131This will retrieve the dependencies using fixed-output derivations from 132the specified lockfile. 133 134One caveat is that `Cargo.lock` cannot be patched in the `patchPhase` 135because it runs after the dependencies have already been fetched. If 136you need to patch or generate the lockfile you can alternatively set 137`cargoLock.lockFileContents` to a string of its contents: 138 139```nix 140rustPlatform.buildRustPackage { 141 pname = "myproject"; 142 version = "1.0.0"; 143 144 cargoLock = let 145 fixupLockFile = path: f (builtins.readFile path); 146 in { 147 lockFileContents = fixupLockFile ./Cargo.lock; 148 }; 149 150 # ... 151} 152``` 153 154Note that setting `cargoLock.lockFile` or `cargoLock.lockFileContents` 155doesn't add a `Cargo.lock` to your `src`, and a `Cargo.lock` is still 156required to build a rust package. A simple fix is to use: 157 158```nix 159postPatch = '' 160 cp ${./Cargo.lock} Cargo.lock 161''; 162``` 163 164The output hash of each dependency that uses a git source must be 165specified in the `outputHashes` attribute. For example: 166 167```nix 168rustPlatform.buildRustPackage rec { 169 pname = "myproject"; 170 version = "1.0.0"; 171 172 cargoLock = { 173 lockFile = ./Cargo.lock; 174 outputHashes = { 175 "finalfusion-0.14.0" = "17f4bsdzpcshwh74w5z119xjy2if6l2wgyjy56v621skr2r8y904"; 176 }; 177 }; 178 179 # ... 180} 181``` 182 183If you do not specify an output hash for a git dependency, building 184the package will fail and inform you of which crate needs to be 185added. To find the correct hash, you can first use `lib.fakeSha256` or 186`lib.fakeHash` as a stub hash. Building the package (and thus the 187vendored dependencies) will then inform you of the correct hash. 188 189### Cargo features {#cargo-features} 190 191You can disable default features using `buildNoDefaultFeatures`, and 192extra features can be added with `buildFeatures`. 193 194If you want to use different features for check phase, you can use 195`checkNoDefaultFeatures` and `checkFeatures`. They are only passed to 196`cargo test` and not `cargo build`. If left unset, they default to 197`buildNoDefaultFeatures` and `buildFeatures`. 198 199For example: 200 201```nix 202rustPlatform.buildRustPackage rec { 203 pname = "myproject"; 204 version = "1.0.0"; 205 206 buildNoDefaultFeatures = true; 207 buildFeatures = [ "color" "net" ]; 208 209 # disable network features in tests 210 checkFeatures = [ "color" ]; 211 212 # ... 213} 214``` 215 216### Cross compilation {#cross-compilation} 217 218By default, Rust packages are compiled for the host platform, just like any 219other package is. The `--target` passed to rust tools is computed from this. 220By default, it takes the `stdenv.hostPlatform.config` and replaces components 221where they are known to differ. But there are ways to customize the argument: 222 223 - To choose a different target by name, define 224 `stdenv.hostPlatform.rustc.config` as that name (a string), and that 225 name will be used instead. 226 227 For example: 228 229 ```nix 230 import <nixpkgs> { 231 crossSystem = (import <nixpkgs/lib>).systems.examples.armhf-embedded // { 232 rustc.config = "thumbv7em-none-eabi"; 233 }; 234 } 235 ``` 236 237 will result in: 238 239 ```shell 240 --target thumbv7em-none-eabi 241 ``` 242 243 - To pass a completely custom target, define 244 `stdenv.hostPlatform.rustc.config` with its name, and 245 `stdenv.hostPlatform.rustc.platform` with the value. The value will be 246 serialized to JSON in a file called 247 `${stdenv.hostPlatform.rustc.config}.json`, and the path of that file 248 will be used instead. 249 250 For example: 251 252 ```nix 253 import <nixpkgs> { 254 crossSystem = (import <nixpkgs/lib>).systems.examples.armhf-embedded // { 255 rustc.config = "thumb-crazy"; 256 rustc.platform = { foo = ""; bar = ""; }; 257 }; 258 } 259 ``` 260 261 will result in: 262 263 ```shell 264 --target /nix/store/asdfasdfsadf-thumb-crazy.json # contains {"foo":"","bar":""} 265 ``` 266 267Note that currently custom targets aren't compiled with `std`, so `cargo test` 268will fail. This can be ignored by adding `doCheck = false;` to your derivation. 269 270### Running package tests {#running-package-tests} 271 272When using `buildRustPackage`, the `checkPhase` is enabled by default and runs 273`cargo test` on the package to build. To make sure that we don't compile the 274sources twice and to actually test the artifacts that will be used at runtime, 275the tests will be ran in the `release` mode by default. 276 277However, in some cases the test-suite of a package doesn't work properly in the 278`release` mode. For these situations, the mode for `checkPhase` can be changed like 279so: 280 281```nix 282rustPlatform.buildRustPackage { 283 /* ... */ 284 checkType = "debug"; 285} 286``` 287 288Please note that the code will be compiled twice here: once in `release` mode 289for the `buildPhase`, and again in `debug` mode for the `checkPhase`. 290 291Test flags, e.g., `--package foo`, can be passed to `cargo test` via the 292`cargoTestFlags` attribute. 293 294Another attribute, called `checkFlags`, is used to pass arguments to the test 295binary itself, as stated 296(here)[https://doc.rust-lang.org/cargo/commands/cargo-test.html]. 297 298#### Tests relying on the structure of the `target/` directory {#tests-relying-on-the-structure-of-the-target-directory} 299 300Some tests may rely on the structure of the `target/` directory. Those tests 301are likely to fail because we use `cargo --target` during the build. This means that 302the artifacts 303[are stored in `target/<architecture>/release/`](https://doc.rust-lang.org/cargo/guide/build-cache.html), 304rather than in `target/release/`. 305 306This can only be worked around by patching the affected tests accordingly. 307 308#### Disabling package-tests {#disabling-package-tests} 309 310In some instances, it may be necessary to disable testing altogether (with `doCheck = false;`): 311 312* If no tests exist -- the `checkPhase` should be explicitly disabled to skip 313 unnecessary build steps to speed up the build. 314* If tests are highly impure (e.g. due to network usage). 315 316There will obviously be some corner-cases not listed above where it's sensible to disable tests. 317The above are just guidelines, and exceptions may be granted on a case-by-case basis. 318 319However, please check if it's possible to disable a problematic subset of the 320test suite and leave a comment explaining your reasoning. 321 322#### Setting `test-threads` {#setting-test-threads} 323 324`buildRustPackage` will use parallel test threads by default, 325sometimes it may be necessary to disable this so the tests run consecutively. 326 327```nix 328rustPlatform.buildRustPackage { 329 /* ... */ 330 dontUseCargoParallelTests = true; 331} 332``` 333 334### Building a package in `debug` mode {#building-a-package-in-debug-mode} 335 336By default, `buildRustPackage` will use `release` mode for builds. If a package 337should be built in `debug` mode, it can be configured like so: 338 339```nix 340rustPlatform.buildRustPackage { 341 /* ... */ 342 buildType = "debug"; 343} 344``` 345 346In this scenario, the `checkPhase` will be ran in `debug` mode as well. 347 348### Custom `build`/`install`-procedures {#custom-buildinstall-procedures} 349 350Some packages may use custom scripts for building/installing, e.g. with a `Makefile`. 351In these cases, it's recommended to override the `buildPhase`/`installPhase`/`checkPhase`. 352 353Otherwise, some steps may fail because of the modified directory structure of `target/`. 354 355### 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} 356 357`buildRustPackage` needs a `Cargo.lock` file to get all dependencies in the 358source code in a reproducible way. If it is missing or out-of-date one can use 359the `cargoPatches` attribute to update or add it. 360 361```nix 362rustPlatform.buildRustPackage rec { 363 (...) 364 cargoPatches = [ 365 # a patch file to add/update Cargo.lock in the source code 366 ./add-Cargo.lock.patch 367 ]; 368} 369``` 370 371## Compiling non-Rust packages that include Rust code {#compiling-non-rust-packages-that-include-rust-code} 372 373Several non-Rust packages incorporate Rust code for performance- or 374security-sensitive parts. `rustPlatform` exposes several functions and 375hooks that can be used to integrate Cargo in non-Rust packages. 376 377### Vendoring of dependencies {#vendoring-of-dependencies} 378 379Since network access is not allowed in sandboxed builds, Rust crate 380dependencies need to be retrieved using a fetcher. `rustPlatform` 381provides the `fetchCargoTarball` fetcher, which vendors all 382dependencies of a crate. For example, given a source path `src` 383containing `Cargo.toml` and `Cargo.lock`, `fetchCargoTarball` 384can be used as follows: 385 386```nix 387cargoDeps = rustPlatform.fetchCargoTarball { 388 inherit src; 389 hash = "sha256-BoHIN/519Top1NUBjpB/oEMqi86Omt3zTQcXFWqrek0="; 390}; 391``` 392 393The `src` attribute is required, as well as a hash specified through 394one of the `sha256` or `hash` attributes. The following optional 395attributes can also be used: 396 397* `name`: the name that is used for the dependencies tarball. If 398 `name` is not specified, then the name `cargo-deps` will be used. 399* `sourceRoot`: when the `Cargo.lock`/`Cargo.toml` are in a 400 subdirectory, `sourceRoot` specifies the relative path to these 401 files. 402* `patches`: patches to apply before vendoring. This is useful when 403 the `Cargo.lock`/`Cargo.toml` files need to be patched before 404 vendoring. 405 406If a `Cargo.lock` file is available, you can alternatively use the 407`importCargoLock` function. In contrast to `fetchCargoTarball`, this 408function does not require a hash (unless git dependencies are used) 409and fetches every dependency as a separate fixed-output derivation. 410`importCargoLock` can be used as follows: 411 412``` 413cargoDeps = rustPlatform.importCargoLock { 414 lockFile = ./Cargo.lock; 415}; 416``` 417 418If the `Cargo.lock` file includes git dependencies, then their output 419hashes need to be specified since they are not available through the 420lock file. For example: 421 422``` 423cargoDeps = rustPlatform.importCargoLock { 424 lockFile = ./Cargo.lock; 425 outputHashes = { 426 "rand-0.8.3" = "0ya2hia3cn31qa8894s3av2s8j5bjwb6yq92k0jsnlx7jid0jwqa"; 427 }; 428}; 429``` 430 431If you do not specify an output hash for a git dependency, building 432`cargoDeps` will fail and inform you of which crate needs to be 433added. To find the correct hash, you can first use `lib.fakeSha256` or 434`lib.fakeHash` as a stub hash. Building `cargoDeps` will then inform 435you of the correct hash. 436 437### Hooks {#hooks} 438 439`rustPlatform` provides the following hooks to automate Cargo builds: 440 441* `cargoSetupHook`: configure Cargo to use dependencies vendored 442 through `fetchCargoTarball`. This hook uses the `cargoDeps` 443 environment variable to find the vendored dependencies. If a project 444 already vendors its dependencies, the variable `cargoVendorDir` can 445 be used instead. When the `Cargo.toml`/`Cargo.lock` files are not in 446 `sourceRoot`, then the optional `cargoRoot` is used to specify the 447 Cargo root directory relative to `sourceRoot`. 448* `cargoBuildHook`: use Cargo to build a crate. If the crate to be 449 built is a crate in e.g. a Cargo workspace, the relative path to the 450 crate to build can be set through the optional `buildAndTestSubdir` 451 environment variable. Features can be specified with 452 `cargoBuildNoDefaultFeatures` and `cargoBuildFeatures`. Additional 453 Cargo build flags can be passed through `cargoBuildFlags`. 454* `maturinBuildHook`: use [Maturin](https://github.com/PyO3/maturin) 455 to build a Python wheel. Similar to `cargoBuildHook`, the optional 456 variable `buildAndTestSubdir` can be used to build a crate in a 457 Cargo workspace. Additional Maturin flags can be passed through 458 `maturinBuildFlags`. 459* `cargoCheckHook`: run tests using Cargo. The build type for checks 460 can be set using `cargoCheckType`. Features can be specified with 461 `cargoCheckNoDefaultFeaatures` and `cargoCheckFeatures`. Additional 462 flags can be passed to the tests using `checkFlags` and 463 `checkFlagsArray`. By default, tests are run in parallel. This can 464 be disabled by setting `dontUseCargoParallelTests`. 465* `cargoInstallHook`: install binaries and static/shared libraries 466 that were built using `cargoBuildHook`. 467 468### Examples {#examples} 469 470#### Python package using `setuptools-rust` {#python-package-using-setuptools-rust} 471 472For Python packages using `setuptools-rust`, you can use 473`fetchCargoTarball` and `cargoSetupHook` to retrieve and set up Cargo 474dependencies. The build itself is then performed by 475`buildPythonPackage`. 476 477The following example outlines how the `tokenizers` Python package is 478built. Since the Python package is in the `source/bindings/python` 479directory of the `tokenizers` project's source archive, we use 480`sourceRoot` to point the tooling to this directory: 481 482```nix 483{ fetchFromGitHub 484, buildPythonPackage 485, rustPlatform 486, setuptools-rust 487}: 488 489buildPythonPackage rec { 490 pname = "tokenizers"; 491 version = "0.10.0"; 492 493 src = fetchFromGitHub { 494 owner = "huggingface"; 495 repo = pname; 496 rev = "python-v${version}"; 497 hash = "sha256-rQ2hRV52naEf6PvRsWVCTN7B1oXAQGmnpJw4iIdhamw="; 498 }; 499 500 cargoDeps = rustPlatform.fetchCargoTarball { 501 inherit src sourceRoot; 502 name = "${pname}-${version}"; 503 hash = "sha256-BoHIN/519Top1NUBjpB/oEMqi86Omt3zTQcXFWqrek0="; 504 }; 505 506 sourceRoot = "source/bindings/python"; 507 508 nativeBuildInputs = [ setuptools-rust ] ++ (with rustPlatform; [ 509 cargoSetupHook 510 rust.cargo 511 rust.rustc 512 ]); 513 514 # ... 515} 516``` 517 518In some projects, the Rust crate is not in the main Python source 519directory. In such cases, the `cargoRoot` attribute can be used to 520specify the crate's directory relative to `sourceRoot`. In the 521following example, the crate is in `src/rust`, as specified in the 522`cargoRoot` attribute. Note that we also need to specify the correct 523path for `fetchCargoTarball`. 524 525```nix 526 527{ buildPythonPackage 528, fetchPypi 529, rustPlatform 530, setuptools-rust 531, openssl 532}: 533 534buildPythonPackage rec { 535 pname = "cryptography"; 536 version = "3.4.2"; # Also update the hash in vectors.nix 537 538 src = fetchPypi { 539 inherit pname version; 540 sha256 = "1i1mx5y9hkyfi9jrrkcw804hmkcglxi6rmf7vin7jfnbr2bf4q64"; 541 }; 542 543 cargoDeps = rustPlatform.fetchCargoTarball { 544 inherit src; 545 sourceRoot = "${pname}-${version}/${cargoRoot}"; 546 name = "${pname}-${version}"; 547 hash = "sha256-PS562W4L1NimqDV2H0jl5vYhL08H9est/pbIxSdYVfo="; 548 }; 549 550 cargoRoot = "src/rust"; 551 552 # ... 553} 554``` 555 556#### Python package using `maturin` {#python-package-using-maturin} 557 558Python packages that use [Maturin](https://github.com/PyO3/maturin) 559can be built with `fetchCargoTarball`, `cargoSetupHook`, and 560`maturinBuildHook`. For example, the following (partial) derivation 561builds the `retworkx` Python package. `fetchCargoTarball` and 562`cargoSetupHook` are used to fetch and set up the crate dependencies. 563`maturinBuildHook` is used to perform the build. 564 565```nix 566{ lib 567, buildPythonPackage 568, rustPlatform 569, fetchFromGitHub 570}: 571 572buildPythonPackage rec { 573 pname = "retworkx"; 574 version = "0.6.0"; 575 576 src = fetchFromGitHub { 577 owner = "Qiskit"; 578 repo = "retworkx"; 579 rev = version; 580 sha256 = "11n30ldg3y3y6qxg3hbj837pnbwjkqw3nxq6frds647mmmprrd20"; 581 }; 582 583 cargoDeps = rustPlatform.fetchCargoTarball { 584 inherit src; 585 name = "${pname}-${version}"; 586 hash = "sha256-heOBK8qi2nuc/Ib+I/vLzZ1fUUD/G/KTw9d7M4Hz5O0="; 587 }; 588 589 format = "pyproject"; 590 591 nativeBuildInputs = with rustPlatform; [ cargoSetupHook maturinBuildHook ]; 592 593 # ... 594} 595``` 596 597## Compiling Rust crates using Nix instead of Cargo {#compiling-rust-crates-using-nix-instead-of-cargo} 598 599### Simple operation {#simple-operation} 600 601When run, `cargo build` produces a file called `Cargo.lock`, 602containing pinned versions of all dependencies. Nixpkgs contains a 603tool called `carnix` (`nix-env -iA nixos.carnix`), which can be used 604to turn a `Cargo.lock` into a Nix expression. 605 606That Nix expression calls `rustc` directly (hence bypassing Cargo), 607and can be used to compile a crate and all its dependencies. Here is 608an example for a minimal `hello` crate: 609 610```ShellSession 611$ cargo new hello 612$ cd hello 613$ cargo build 614 Compiling hello v0.1.0 (file:///tmp/hello) 615 Finished dev [unoptimized + debuginfo] target(s) in 0.20 secs 616$ carnix -o hello.nix --src ./. Cargo.lock --standalone 617$ nix-build hello.nix -A hello_0_1_0 618``` 619 620Now, the file produced by the call to `carnix`, called `hello.nix`, looks like: 621 622```nix 623# Generated by carnix 0.6.5: carnix -o hello.nix --src ./. Cargo.lock --standalone 624{ stdenv, buildRustCrate, fetchgit }: 625let kernel = stdenv.buildPlatform.parsed.kernel.name; 626 # ... (content skipped) 627in 628rec { 629 hello = f: hello_0_1_0 { features = hello_0_1_0_features { hello_0_1_0 = f; }; }; 630 hello_0_1_0_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate { 631 crateName = "hello"; 632 version = "0.1.0"; 633 authors = [ "pe@pijul.org <pe@pijul.org>" ]; 634 src = ./.; 635 inherit dependencies buildDependencies features; 636 }; 637 hello_0_1_0 = { features?(hello_0_1_0_features {}) }: hello_0_1_0_ {}; 638 hello_0_1_0_features = f: updateFeatures f (rec { 639 hello_0_1_0.default = (f.hello_0_1_0.default or true); 640 }) [ ]; 641} 642``` 643 644In particular, note that the argument given as `--src` is copied 645verbatim to the source. If we look at a more complicated 646dependencies, for instance by adding a single line `libc="*"` to our 647`Cargo.toml`, we first need to run `cargo build` to update the 648`Cargo.lock`. Then, `carnix` needs to be run again, and produces the 649following nix file: 650 651```nix 652# Generated by carnix 0.6.5: carnix -o hello.nix --src ./. Cargo.lock --standalone 653{ stdenv, buildRustCrate, fetchgit }: 654let kernel = stdenv.buildPlatform.parsed.kernel.name; 655 # ... (content skipped) 656in 657rec { 658 hello = f: hello_0_1_0 { features = hello_0_1_0_features { hello_0_1_0 = f; }; }; 659 hello_0_1_0_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate { 660 crateName = "hello"; 661 version = "0.1.0"; 662 authors = [ "pe@pijul.org <pe@pijul.org>" ]; 663 src = ./.; 664 inherit dependencies buildDependencies features; 665 }; 666 libc_0_2_36_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate { 667 crateName = "libc"; 668 version = "0.2.36"; 669 authors = [ "The Rust Project Developers" ]; 670 sha256 = "01633h4yfqm0s302fm0dlba469bx8y6cs4nqc8bqrmjqxfxn515l"; 671 inherit dependencies buildDependencies features; 672 }; 673 hello_0_1_0 = { features?(hello_0_1_0_features {}) }: hello_0_1_0_ { 674 dependencies = mapFeatures features ([ libc_0_2_36 ]); 675 }; 676 hello_0_1_0_features = f: updateFeatures f (rec { 677 hello_0_1_0.default = (f.hello_0_1_0.default or true); 678 libc_0_2_36.default = true; 679 }) [ libc_0_2_36_features ]; 680 libc_0_2_36 = { features?(libc_0_2_36_features {}) }: libc_0_2_36_ { 681 features = mkFeatures (features.libc_0_2_36 or {}); 682 }; 683 libc_0_2_36_features = f: updateFeatures f (rec { 684 libc_0_2_36.default = (f.libc_0_2_36.default or true); 685 libc_0_2_36.use_std = 686 (f.libc_0_2_36.use_std or false) || 687 (f.libc_0_2_36.default or false) || 688 (libc_0_2_36.default or false); 689 }) []; 690} 691``` 692 693Here, the `libc` crate has no `src` attribute, so `buildRustCrate` 694will fetch it from [crates.io](https://crates.io). A `sha256` 695attribute is still needed for Nix purity. 696 697### Handling external dependencies {#handling-external-dependencies} 698 699Some crates require external libraries. For crates from 700[crates.io](https://crates.io), such libraries can be specified in 701`defaultCrateOverrides` package in nixpkgs itself. 702 703Starting from that file, one can add more overrides, to add features 704or build inputs by overriding the hello crate in a separate file. 705 706```nix 707with import <nixpkgs> {}; 708((import ./hello.nix).hello {}).override { 709 crateOverrides = defaultCrateOverrides // { 710 hello = attrs: { buildInputs = [ openssl ]; }; 711 }; 712} 713``` 714 715Here, `crateOverrides` is expected to be a attribute set, where the 716key is the crate name without version number and the value a function. 717The function gets all attributes passed to `buildRustCrate` as first 718argument and returns a set that contains all attribute that should be 719overwritten. 720 721For more complicated cases, such as when parts of the crate's 722derivation depend on the crate's version, the `attrs` argument of 723the override above can be read, as in the following example, which 724patches the derivation: 725 726```nix 727with import <nixpkgs> {}; 728((import ./hello.nix).hello {}).override { 729 crateOverrides = defaultCrateOverrides // { 730 hello = attrs: lib.optionalAttrs (lib.versionAtLeast attrs.version "1.0") { 731 postPatch = '' 732 substituteInPlace lib/zoneinfo.rs \ 733 --replace "/usr/share/zoneinfo" "${tzdata}/share/zoneinfo" 734 ''; 735 }; 736 }; 737} 738``` 739 740Another situation is when we want to override a nested 741dependency. This actually works in the exact same way, since the 742`crateOverrides` parameter is forwarded to the crate's 743dependencies. For instance, to override the build inputs for crate 744`libc` in the example above, where `libc` is a dependency of the main 745crate, we could do: 746 747```nix 748with import <nixpkgs> {}; 749((import hello.nix).hello {}).override { 750 crateOverrides = defaultCrateOverrides // { 751 libc = attrs: { buildInputs = []; }; 752 }; 753} 754``` 755 756### Options and phases configuration {#options-and-phases-configuration} 757 758Actually, the overrides introduced in the previous section are more 759general. A number of other parameters can be overridden: 760 761- The version of `rustc` used to compile the crate: 762 763 ```nix 764 (hello {}).override { rust = pkgs.rust; }; 765 ``` 766 767- Whether to build in release mode or debug mode (release mode by 768 default): 769 770 ```nix 771 (hello {}).override { release = false; }; 772 ``` 773 774- Whether to print the commands sent to `rustc` when building 775 (equivalent to `--verbose` in cargo: 776 777 ```nix 778 (hello {}).override { verbose = false; }; 779 ``` 780 781- Extra arguments to be passed to `rustc`: 782 783 ```nix 784 (hello {}).override { extraRustcOpts = "-Z debuginfo=2"; }; 785 ``` 786 787- Phases, just like in any other derivation, can be specified using 788 the following attributes: `preUnpack`, `postUnpack`, `prePatch`, 789 `patches`, `postPatch`, `preConfigure` (in the case of a Rust crate, 790 this is run before calling the "build" script), `postConfigure` 791 (after the "build" script),`preBuild`, `postBuild`, `preInstall` and 792 `postInstall`. As an example, here is how to create a new module 793 before running the build script: 794 795 ```nix 796 (hello {}).override { 797 preConfigure = '' 798 echo "pub const PATH=\"${hi.out}\";" >> src/path.rs" 799 ''; 800 }; 801 ``` 802 803### Features {#features} 804 805One can also supply features switches. For example, if we want to 806compile `diesel_cli` only with the `postgres` feature, and no default 807features, we would write: 808 809```nix 810(callPackage ./diesel.nix {}).diesel { 811 default = false; 812 postgres = true; 813} 814``` 815 816Where `diesel.nix` is the file generated by Carnix, as explained above. 817 818## Setting Up `nix-shell` {#setting-up-nix-shell} 819 820Oftentimes you want to develop code from within `nix-shell`. Unfortunately 821`buildRustCrate` does not support common `nix-shell` operations directly 822(see [this issue](https://github.com/NixOS/nixpkgs/issues/37945)) 823so we will use `stdenv.mkDerivation` instead. 824 825Using the example `hello` project above, we want to do the following: 826 827- Have access to `cargo` and `rustc` 828- Have the `openssl` library available to a crate through it's _normal_ 829 compilation mechanism (`pkg-config`). 830 831A typical `shell.nix` might look like: 832 833```nix 834with import <nixpkgs> {}; 835 836stdenv.mkDerivation { 837 name = "rust-env"; 838 nativeBuildInputs = [ 839 rustc cargo 840 841 # Example Build-time Additional Dependencies 842 pkg-config 843 ]; 844 buildInputs = [ 845 # Example Run-time Additional Dependencies 846 openssl 847 ]; 848 849 # Set Environment Variables 850 RUST_BACKTRACE = 1; 851} 852``` 853 854You should now be able to run the following: 855 856```ShellSession 857$ nix-shell --pure 858$ cargo build 859$ cargo test 860``` 861 862### Controlling Rust Version Inside `nix-shell` {#controlling-rust-version-inside-nix-shell} 863 864To control your rust version (i.e. use nightly) from within `shell.nix` (or 865other nix expressions) you can use the following `shell.nix` 866 867```nix 868# Latest Nightly 869with import <nixpkgs> {}; 870let src = fetchFromGitHub { 871 owner = "mozilla"; 872 repo = "nixpkgs-mozilla"; 873 # commit from: 2019-05-15 874 rev = "9f35c4b09fd44a77227e79ff0c1b4b6a69dff533"; 875 sha256 = "18h0nvh55b5an4gmlgfbvwbyqj91bklf1zymis6lbdh75571qaz0"; 876 }; 877in 878with import "${src.out}/rust-overlay.nix" pkgs pkgs; 879stdenv.mkDerivation { 880 name = "rust-env"; 881 buildInputs = [ 882 # Note: to use stable, just replace `nightly` with `stable` 883 latest.rustChannels.nightly.rust 884 885 # Add some extra dependencies from `pkgs` 886 pkg-config openssl 887 ]; 888 889 # Set Environment Variables 890 RUST_BACKTRACE = 1; 891} 892``` 893 894Now run: 895 896```ShellSession 897$ rustc --version 898rustc 1.26.0-nightly (188e693b3 2018-03-26) 899``` 900 901To see that you are using nightly. 902 903## Using community Rust overlays {#using-community-rust-overlays} 904 905There are two community maintained approaches to Rust toolchain management: 906- [oxalica's Rust overlay](https://github.com/oxalica/rust-overlay) 907- [fenix](https://github.com/nix-community/fenix) 908 909Oxalica's overlay allows you to select a particular Rust version and components. 910See [their documentation](https://github.com/oxalica/rust-overlay#rust-overlay) for more 911detailed usage. 912 913Fenix is an alternative to `rustup` and can also be used as an overlay. 914 915Both oxalica's overlay and fenix better integrate with nix and cache optimizations. 916Because of this and ergonomics, either of those community projects 917should be preferred to the Mozilla's Rust overlay (`nixpkgs-mozilla`). 918 919### How to select a specific `rustc` and toolchain version {#how-to-select-a-specific-rustc-and-toolchain-version} 920 921You can consume the oxalica overlay and use it to grab a specific Rust toolchain version. 922Here is an example `shell.nix` showing how to grab the current stable toolchain: 923```nix 924{ pkgs ? import <nixpkgs> { 925 overlays = [ 926 (import (fetchTarball "https://github.com/oxalica/rust-overlay/archive/master.tar.gz")) 927 ]; 928 } 929}: 930pkgs.mkShell { 931 nativeBuildInputs = with pkgs; [ 932 pkg-config 933 rust-bin.stable.latest.minimal 934 ]; 935} 936``` 937 938You can try this out by: 9391. Saving that to `shell.nix` 9402. Executing `nix-shell --pure --command 'rustc --version'` 941 942As of writing, this prints out `rustc 1.56.0 (09c42c458 2021-10-18)`. 943 944### How to use an overlay toolchain in a derivation {#how-to-use-an-overlay-toolchain-in-a-derivation} 945 946You can also use an overlay's Rust toolchain with `buildRustPackage`. 947The below snippet demonstrates invoking `buildRustPackage` with an oxalica overlay selected Rust toolchain: 948```nix 949with import <nixpkgs> { 950 overlays = [ 951 (import (fetchTarball "https://github.com/oxalica/rust-overlay/archive/master.tar.gz")) 952 ]; 953}; 954 955rustPlatform.buildRustPackage rec { 956 pname = "ripgrep"; 957 version = "12.1.1"; 958 nativeBuildInputs = [ 959 rust-bin.stable.latest.minimal 960 ]; 961 962 src = fetchFromGitHub { 963 owner = "BurntSushi"; 964 repo = "ripgrep"; 965 rev = version; 966 sha256 = "1hqps7l5qrjh9f914r5i6kmcz6f1yb951nv4lby0cjnp5l253kps"; 967 }; 968 969 cargoSha256 = "03wf9r2csi6jpa7v5sw5lpxkrk4wfzwmzx7k3991q3bdjzcwnnwp"; 970 971 meta = with lib; { 972 description = "A fast line-oriented regex search tool, similar to ag and ack"; 973 homepage = "https://github.com/BurntSushi/ripgrep"; 974 license = licenses.unlicense; 975 maintainers = [ maintainers.tailhook ]; 976 }; 977} 978``` 979 980Follow the below steps to try that snippet. 9811. create a new directory 9821. save the above snippet as `default.nix` in that directory 9831. cd into that directory and run `nix-build` 984 985### Rust overlay installation {#rust-overlay-installation} 986 987You can use this overlay by either changing your local nixpkgs configuration, 988or by adding the overlay declaratively in a nix expression, e.g. in `configuration.nix`. 989For more information see [the manual on installing overlays](#sec-overlays-install). 990 991### Declarative Rust overlay installation {#declarative-rust-overlay-installation} 992 993This snippet shows how to use oxalica's Rust overlay. 994Add the following to your `configuration.nix`, `home-configuration.nix`, `shell.nix`, or similar: 995 996```nix 997{ pkgs ? import <nixpkgs> { 998 overlays = [ 999 (import (builtins.fetchTarball "https://github.com/oxalica/rust-overlay/archive/master.tar.gz")) 1000 # Further overlays go here 1001 ]; 1002 }; 1003}; 1004``` 1005 1006Note that this will fetch the latest overlay version when rebuilding your system.