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## `buildRustPackage`: 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 322This can be achived with `--skip` in `checkFlags`: 323 324```nix 325rustPlatform.buildRustPackage { 326 /* ... */ 327 checkFlags = [ 328 # reason for disabling test 329 "--skip=example::tests:example_test" 330 ]; 331} 332``` 333 334#### Setting `test-threads` {#setting-test-threads} 335 336`buildRustPackage` will use parallel test threads by default, 337sometimes it may be necessary to disable this so the tests run consecutively. 338 339```nix 340rustPlatform.buildRustPackage { 341 /* ... */ 342 dontUseCargoParallelTests = true; 343} 344``` 345 346### Building a package in `debug` mode {#building-a-package-in-debug-mode} 347 348By default, `buildRustPackage` will use `release` mode for builds. If a package 349should be built in `debug` mode, it can be configured like so: 350 351```nix 352rustPlatform.buildRustPackage { 353 /* ... */ 354 buildType = "debug"; 355} 356``` 357 358In this scenario, the `checkPhase` will be ran in `debug` mode as well. 359 360### Custom `build`/`install`-procedures {#custom-buildinstall-procedures} 361 362Some packages may use custom scripts for building/installing, e.g. with a `Makefile`. 363In these cases, it's recommended to override the `buildPhase`/`installPhase`/`checkPhase`. 364 365Otherwise, some steps may fail because of the modified directory structure of `target/`. 366 367### 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} 368 369`buildRustPackage` needs a `Cargo.lock` file to get all dependencies in the 370source code in a reproducible way. If it is missing or out-of-date one can use 371the `cargoPatches` attribute to update or add it. 372 373```nix 374rustPlatform.buildRustPackage rec { 375 (...) 376 cargoPatches = [ 377 # a patch file to add/update Cargo.lock in the source code 378 ./add-Cargo.lock.patch 379 ]; 380} 381``` 382 383## Compiling non-Rust packages that include Rust code {#compiling-non-rust-packages-that-include-rust-code} 384 385Several non-Rust packages incorporate Rust code for performance- or 386security-sensitive parts. `rustPlatform` exposes several functions and 387hooks that can be used to integrate Cargo in non-Rust packages. 388 389### Vendoring of dependencies {#vendoring-of-dependencies} 390 391Since network access is not allowed in sandboxed builds, Rust crate 392dependencies need to be retrieved using a fetcher. `rustPlatform` 393provides the `fetchCargoTarball` fetcher, which vendors all 394dependencies of a crate. For example, given a source path `src` 395containing `Cargo.toml` and `Cargo.lock`, `fetchCargoTarball` 396can be used as follows: 397 398```nix 399cargoDeps = rustPlatform.fetchCargoTarball { 400 inherit src; 401 hash = "sha256-BoHIN/519Top1NUBjpB/oEMqi86Omt3zTQcXFWqrek0="; 402}; 403``` 404 405The `src` attribute is required, as well as a hash specified through 406one of the `sha256` or `hash` attributes. The following optional 407attributes can also be used: 408 409* `name`: the name that is used for the dependencies tarball. If 410 `name` is not specified, then the name `cargo-deps` will be used. 411* `sourceRoot`: when the `Cargo.lock`/`Cargo.toml` are in a 412 subdirectory, `sourceRoot` specifies the relative path to these 413 files. 414* `patches`: patches to apply before vendoring. This is useful when 415 the `Cargo.lock`/`Cargo.toml` files need to be patched before 416 vendoring. 417 418If a `Cargo.lock` file is available, you can alternatively use the 419`importCargoLock` function. In contrast to `fetchCargoTarball`, this 420function does not require a hash (unless git dependencies are used) 421and fetches every dependency as a separate fixed-output derivation. 422`importCargoLock` can be used as follows: 423 424``` 425cargoDeps = rustPlatform.importCargoLock { 426 lockFile = ./Cargo.lock; 427}; 428``` 429 430If the `Cargo.lock` file includes git dependencies, then their output 431hashes need to be specified since they are not available through the 432lock file. For example: 433 434``` 435cargoDeps = rustPlatform.importCargoLock { 436 lockFile = ./Cargo.lock; 437 outputHashes = { 438 "rand-0.8.3" = "0ya2hia3cn31qa8894s3av2s8j5bjwb6yq92k0jsnlx7jid0jwqa"; 439 }; 440}; 441``` 442 443If you do not specify an output hash for a git dependency, building 444`cargoDeps` will fail and inform you of which crate needs to be 445added. To find the correct hash, you can first use `lib.fakeSha256` or 446`lib.fakeHash` as a stub hash. Building `cargoDeps` will then inform 447you of the correct hash. 448 449### Hooks {#hooks} 450 451`rustPlatform` provides the following hooks to automate Cargo builds: 452 453* `cargoSetupHook`: configure Cargo to use dependencies vendored 454 through `fetchCargoTarball`. This hook uses the `cargoDeps` 455 environment variable to find the vendored dependencies. If a project 456 already vendors its dependencies, the variable `cargoVendorDir` can 457 be used instead. When the `Cargo.toml`/`Cargo.lock` files are not in 458 `sourceRoot`, then the optional `cargoRoot` is used to specify the 459 Cargo root directory relative to `sourceRoot`. 460* `cargoBuildHook`: use Cargo to build a crate. If the crate to be 461 built is a crate in e.g. a Cargo workspace, the relative path to the 462 crate to build can be set through the optional `buildAndTestSubdir` 463 environment variable. Features can be specified with 464 `cargoBuildNoDefaultFeatures` and `cargoBuildFeatures`. Additional 465 Cargo build flags can be passed through `cargoBuildFlags`. 466* `maturinBuildHook`: use [Maturin](https://github.com/PyO3/maturin) 467 to build a Python wheel. Similar to `cargoBuildHook`, the optional 468 variable `buildAndTestSubdir` can be used to build a crate in a 469 Cargo workspace. Additional Maturin flags can be passed through 470 `maturinBuildFlags`. 471* `cargoCheckHook`: run tests using Cargo. The build type for checks 472 can be set using `cargoCheckType`. Features can be specified with 473 `cargoCheckNoDefaultFeatures` and `cargoCheckFeatures`. Additional 474 flags can be passed to the tests using `checkFlags` and 475 `checkFlagsArray`. By default, tests are run in parallel. This can 476 be disabled by setting `dontUseCargoParallelTests`. 477* `cargoInstallHook`: install binaries and static/shared libraries 478 that were built using `cargoBuildHook`. 479* `bindgenHook`: for crates which use `bindgen` as a build dependency, lets 480 `bindgen` find `libclang` and `libclang` find the libraries in `buildInputs`. 481 482### Examples {#examples} 483 484#### Python package using `setuptools-rust` {#python-package-using-setuptools-rust} 485 486For Python packages using `setuptools-rust`, you can use 487`fetchCargoTarball` and `cargoSetupHook` to retrieve and set up Cargo 488dependencies. The build itself is then performed by 489`buildPythonPackage`. 490 491The following example outlines how the `tokenizers` Python package is 492built. Since the Python package is in the `source/bindings/python` 493directory of the `tokenizers` project's source archive, we use 494`sourceRoot` to point the tooling to this directory: 495 496```nix 497{ fetchFromGitHub 498, buildPythonPackage 499, rustPlatform 500, setuptools-rust 501}: 502 503buildPythonPackage rec { 504 pname = "tokenizers"; 505 version = "0.10.0"; 506 507 src = fetchFromGitHub { 508 owner = "huggingface"; 509 repo = pname; 510 rev = "python-v${version}"; 511 hash = "sha256-rQ2hRV52naEf6PvRsWVCTN7B1oXAQGmnpJw4iIdhamw="; 512 }; 513 514 cargoDeps = rustPlatform.fetchCargoTarball { 515 inherit src sourceRoot; 516 name = "${pname}-${version}"; 517 hash = "sha256-BoHIN/519Top1NUBjpB/oEMqi86Omt3zTQcXFWqrek0="; 518 }; 519 520 sourceRoot = "source/bindings/python"; 521 522 nativeBuildInputs = [ setuptools-rust ] ++ (with rustPlatform; [ 523 cargoSetupHook 524 rust.cargo 525 rust.rustc 526 ]); 527 528 # ... 529} 530``` 531 532In some projects, the Rust crate is not in the main Python source 533directory. In such cases, the `cargoRoot` attribute can be used to 534specify the crate's directory relative to `sourceRoot`. In the 535following example, the crate is in `src/rust`, as specified in the 536`cargoRoot` attribute. Note that we also need to specify the correct 537path for `fetchCargoTarball`. 538 539```nix 540 541{ buildPythonPackage 542, fetchPypi 543, rustPlatform 544, setuptools-rust 545, openssl 546}: 547 548buildPythonPackage rec { 549 pname = "cryptography"; 550 version = "3.4.2"; # Also update the hash in vectors.nix 551 552 src = fetchPypi { 553 inherit pname version; 554 sha256 = "1i1mx5y9hkyfi9jrrkcw804hmkcglxi6rmf7vin7jfnbr2bf4q64"; 555 }; 556 557 cargoDeps = rustPlatform.fetchCargoTarball { 558 inherit src; 559 sourceRoot = "${pname}-${version}/${cargoRoot}"; 560 name = "${pname}-${version}"; 561 hash = "sha256-PS562W4L1NimqDV2H0jl5vYhL08H9est/pbIxSdYVfo="; 562 }; 563 564 cargoRoot = "src/rust"; 565 566 # ... 567} 568``` 569 570#### Python package using `maturin` {#python-package-using-maturin} 571 572Python packages that use [Maturin](https://github.com/PyO3/maturin) 573can be built with `fetchCargoTarball`, `cargoSetupHook`, and 574`maturinBuildHook`. For example, the following (partial) derivation 575builds the `retworkx` Python package. `fetchCargoTarball` and 576`cargoSetupHook` are used to fetch and set up the crate dependencies. 577`maturinBuildHook` is used to perform the build. 578 579```nix 580{ lib 581, buildPythonPackage 582, rustPlatform 583, fetchFromGitHub 584}: 585 586buildPythonPackage rec { 587 pname = "retworkx"; 588 version = "0.6.0"; 589 590 src = fetchFromGitHub { 591 owner = "Qiskit"; 592 repo = "retworkx"; 593 rev = version; 594 sha256 = "11n30ldg3y3y6qxg3hbj837pnbwjkqw3nxq6frds647mmmprrd20"; 595 }; 596 597 cargoDeps = rustPlatform.fetchCargoTarball { 598 inherit src; 599 name = "${pname}-${version}"; 600 hash = "sha256-heOBK8qi2nuc/Ib+I/vLzZ1fUUD/G/KTw9d7M4Hz5O0="; 601 }; 602 603 format = "pyproject"; 604 605 nativeBuildInputs = with rustPlatform; [ cargoSetupHook maturinBuildHook ]; 606 607 # ... 608} 609``` 610 611## `buildRustCrate`: Compiling Rust crates using Nix instead of Cargo {#compiling-rust-crates-using-nix-instead-of-cargo} 612 613### Simple operation {#simple-operation} 614 615When run, `cargo build` produces a file called `Cargo.lock`, 616containing pinned versions of all dependencies. Nixpkgs contains a 617tool called `carnix` (`nix-env -iA nixos.carnix`), which can be used 618to turn a `Cargo.lock` into a Nix expression. 619 620That Nix expression calls `rustc` directly (hence bypassing Cargo), 621and can be used to compile a crate and all its dependencies. Here is 622an example for a minimal `hello` crate: 623 624```ShellSession 625$ cargo new hello 626$ cd hello 627$ cargo build 628 Compiling hello v0.1.0 (file:///tmp/hello) 629 Finished dev [unoptimized + debuginfo] target(s) in 0.20 secs 630$ carnix -o hello.nix --src ./. Cargo.lock --standalone 631$ nix-build hello.nix -A hello_0_1_0 632``` 633 634Now, the file produced by the call to `carnix`, called `hello.nix`, looks like: 635 636```nix 637# Generated by carnix 0.6.5: carnix -o hello.nix --src ./. Cargo.lock --standalone 638{ stdenv, buildRustCrate, fetchgit }: 639let kernel = stdenv.buildPlatform.parsed.kernel.name; 640 # ... (content skipped) 641in 642rec { 643 hello = f: hello_0_1_0 { features = hello_0_1_0_features { hello_0_1_0 = f; }; }; 644 hello_0_1_0_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate { 645 crateName = "hello"; 646 version = "0.1.0"; 647 authors = [ "pe@pijul.org <pe@pijul.org>" ]; 648 src = ./.; 649 inherit dependencies buildDependencies features; 650 }; 651 hello_0_1_0 = { features?(hello_0_1_0_features {}) }: hello_0_1_0_ {}; 652 hello_0_1_0_features = f: updateFeatures f (rec { 653 hello_0_1_0.default = (f.hello_0_1_0.default or true); 654 }) [ ]; 655} 656``` 657 658In particular, note that the argument given as `--src` is copied 659verbatim to the source. If we look at a more complicated 660dependencies, for instance by adding a single line `libc="*"` to our 661`Cargo.toml`, we first need to run `cargo build` to update the 662`Cargo.lock`. Then, `carnix` needs to be run again, and produces the 663following nix file: 664 665```nix 666# Generated by carnix 0.6.5: carnix -o hello.nix --src ./. Cargo.lock --standalone 667{ stdenv, buildRustCrate, fetchgit }: 668let kernel = stdenv.buildPlatform.parsed.kernel.name; 669 # ... (content skipped) 670in 671rec { 672 hello = f: hello_0_1_0 { features = hello_0_1_0_features { hello_0_1_0 = f; }; }; 673 hello_0_1_0_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate { 674 crateName = "hello"; 675 version = "0.1.0"; 676 authors = [ "pe@pijul.org <pe@pijul.org>" ]; 677 src = ./.; 678 inherit dependencies buildDependencies features; 679 }; 680 libc_0_2_36_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate { 681 crateName = "libc"; 682 version = "0.2.36"; 683 authors = [ "The Rust Project Developers" ]; 684 sha256 = "01633h4yfqm0s302fm0dlba469bx8y6cs4nqc8bqrmjqxfxn515l"; 685 inherit dependencies buildDependencies features; 686 }; 687 hello_0_1_0 = { features?(hello_0_1_0_features {}) }: hello_0_1_0_ { 688 dependencies = mapFeatures features ([ libc_0_2_36 ]); 689 }; 690 hello_0_1_0_features = f: updateFeatures f (rec { 691 hello_0_1_0.default = (f.hello_0_1_0.default or true); 692 libc_0_2_36.default = true; 693 }) [ libc_0_2_36_features ]; 694 libc_0_2_36 = { features?(libc_0_2_36_features {}) }: libc_0_2_36_ { 695 features = mkFeatures (features.libc_0_2_36 or {}); 696 }; 697 libc_0_2_36_features = f: updateFeatures f (rec { 698 libc_0_2_36.default = (f.libc_0_2_36.default or true); 699 libc_0_2_36.use_std = 700 (f.libc_0_2_36.use_std or false) || 701 (f.libc_0_2_36.default or false) || 702 (libc_0_2_36.default or false); 703 }) []; 704} 705``` 706 707Here, the `libc` crate has no `src` attribute, so `buildRustCrate` 708will fetch it from [crates.io](https://crates.io). A `sha256` 709attribute is still needed for Nix purity. 710 711### Handling external dependencies {#handling-external-dependencies} 712 713Some crates require external libraries. For crates from 714[crates.io](https://crates.io), such libraries can be specified in 715`defaultCrateOverrides` package in nixpkgs itself. 716 717Starting from that file, one can add more overrides, to add features 718or build inputs by overriding the hello crate in a separate file. 719 720```nix 721with import <nixpkgs> {}; 722((import ./hello.nix).hello {}).override { 723 crateOverrides = defaultCrateOverrides // { 724 hello = attrs: { buildInputs = [ openssl ]; }; 725 }; 726} 727``` 728 729Here, `crateOverrides` is expected to be a attribute set, where the 730key is the crate name without version number and the value a function. 731The function gets all attributes passed to `buildRustCrate` as first 732argument and returns a set that contains all attribute that should be 733overwritten. 734 735For more complicated cases, such as when parts of the crate's 736derivation depend on the crate's version, the `attrs` argument of 737the override above can be read, as in the following example, which 738patches the derivation: 739 740```nix 741with import <nixpkgs> {}; 742((import ./hello.nix).hello {}).override { 743 crateOverrides = defaultCrateOverrides // { 744 hello = attrs: lib.optionalAttrs (lib.versionAtLeast attrs.version "1.0") { 745 postPatch = '' 746 substituteInPlace lib/zoneinfo.rs \ 747 --replace "/usr/share/zoneinfo" "${tzdata}/share/zoneinfo" 748 ''; 749 }; 750 }; 751} 752``` 753 754Another situation is when we want to override a nested 755dependency. This actually works in the exact same way, since the 756`crateOverrides` parameter is forwarded to the crate's 757dependencies. For instance, to override the build inputs for crate 758`libc` in the example above, where `libc` is a dependency of the main 759crate, we could do: 760 761```nix 762with import <nixpkgs> {}; 763((import hello.nix).hello {}).override { 764 crateOverrides = defaultCrateOverrides // { 765 libc = attrs: { buildInputs = []; }; 766 }; 767} 768``` 769 770### Options and phases configuration {#options-and-phases-configuration} 771 772Actually, the overrides introduced in the previous section are more 773general. A number of other parameters can be overridden: 774 775- The version of `rustc` used to compile the crate: 776 777 ```nix 778 (hello {}).override { rust = pkgs.rust; }; 779 ``` 780 781- Whether to build in release mode or debug mode (release mode by 782 default): 783 784 ```nix 785 (hello {}).override { release = false; }; 786 ``` 787 788- Whether to print the commands sent to `rustc` when building 789 (equivalent to `--verbose` in cargo: 790 791 ```nix 792 (hello {}).override { verbose = false; }; 793 ``` 794 795- Extra arguments to be passed to `rustc`: 796 797 ```nix 798 (hello {}).override { extraRustcOpts = "-Z debuginfo=2"; }; 799 ``` 800 801- Phases, just like in any other derivation, can be specified using 802 the following attributes: `preUnpack`, `postUnpack`, `prePatch`, 803 `patches`, `postPatch`, `preConfigure` (in the case of a Rust crate, 804 this is run before calling the "build" script), `postConfigure` 805 (after the "build" script),`preBuild`, `postBuild`, `preInstall` and 806 `postInstall`. As an example, here is how to create a new module 807 before running the build script: 808 809 ```nix 810 (hello {}).override { 811 preConfigure = '' 812 echo "pub const PATH=\"${hi.out}\";" >> src/path.rs" 813 ''; 814 }; 815 ``` 816 817### Features {#features} 818 819One can also supply features switches. For example, if we want to 820compile `diesel_cli` only with the `postgres` feature, and no default 821features, we would write: 822 823```nix 824(callPackage ./diesel.nix {}).diesel { 825 default = false; 826 postgres = true; 827} 828``` 829 830Where `diesel.nix` is the file generated by Carnix, as explained above. 831 832## Setting Up `nix-shell` {#setting-up-nix-shell} 833 834Oftentimes you want to develop code from within `nix-shell`. Unfortunately 835`buildRustCrate` does not support common `nix-shell` operations directly 836(see [this issue](https://github.com/NixOS/nixpkgs/issues/37945)) 837so we will use `stdenv.mkDerivation` instead. 838 839Using the example `hello` project above, we want to do the following: 840 841- Have access to `cargo` and `rustc` 842- Have the `openssl` library available to a crate through it's _normal_ 843 compilation mechanism (`pkg-config`). 844 845A typical `shell.nix` might look like: 846 847```nix 848with import <nixpkgs> {}; 849 850stdenv.mkDerivation { 851 name = "rust-env"; 852 nativeBuildInputs = [ 853 rustc cargo 854 855 # Example Build-time Additional Dependencies 856 pkg-config 857 ]; 858 buildInputs = [ 859 # Example Run-time Additional Dependencies 860 openssl 861 ]; 862 863 # Set Environment Variables 864 RUST_BACKTRACE = 1; 865} 866``` 867 868You should now be able to run the following: 869 870```ShellSession 871$ nix-shell --pure 872$ cargo build 873$ cargo test 874``` 875 876### Controlling Rust Version Inside `nix-shell` {#controlling-rust-version-inside-nix-shell} 877 878To control your rust version (i.e. use nightly) from within `shell.nix` (or 879other nix expressions) you can use the following `shell.nix` 880 881```nix 882# Latest Nightly 883with import <nixpkgs> {}; 884let src = fetchFromGitHub { 885 owner = "mozilla"; 886 repo = "nixpkgs-mozilla"; 887 # commit from: 2019-05-15 888 rev = "9f35c4b09fd44a77227e79ff0c1b4b6a69dff533"; 889 sha256 = "18h0nvh55b5an4gmlgfbvwbyqj91bklf1zymis6lbdh75571qaz0"; 890 }; 891in 892with import "${src.out}/rust-overlay.nix" pkgs pkgs; 893stdenv.mkDerivation { 894 name = "rust-env"; 895 buildInputs = [ 896 # Note: to use stable, just replace `nightly` with `stable` 897 latest.rustChannels.nightly.rust 898 899 # Add some extra dependencies from `pkgs` 900 pkg-config openssl 901 ]; 902 903 # Set Environment Variables 904 RUST_BACKTRACE = 1; 905} 906``` 907 908Now run: 909 910```ShellSession 911$ rustc --version 912rustc 1.26.0-nightly (188e693b3 2018-03-26) 913``` 914 915To see that you are using nightly. 916 917## Using community Rust overlays {#using-community-rust-overlays} 918 919There are two community maintained approaches to Rust toolchain management: 920- [oxalica's Rust overlay](https://github.com/oxalica/rust-overlay) 921- [fenix](https://github.com/nix-community/fenix) 922 923Oxalica's overlay allows you to select a particular Rust version and components. 924See [their documentation](https://github.com/oxalica/rust-overlay#rust-overlay) for more 925detailed usage. 926 927Fenix is an alternative to `rustup` and can also be used as an overlay. 928 929Both oxalica's overlay and fenix better integrate with nix and cache optimizations. 930Because of this and ergonomics, either of those community projects 931should be preferred to the Mozilla's Rust overlay (`nixpkgs-mozilla`). 932 933### How to select a specific `rustc` and toolchain version {#how-to-select-a-specific-rustc-and-toolchain-version} 934 935You can consume the oxalica overlay and use it to grab a specific Rust toolchain version. 936Here is an example `shell.nix` showing how to grab the current stable toolchain: 937```nix 938{ pkgs ? import <nixpkgs> { 939 overlays = [ 940 (import (fetchTarball "https://github.com/oxalica/rust-overlay/archive/master.tar.gz")) 941 ]; 942 } 943}: 944pkgs.mkShell { 945 nativeBuildInputs = with pkgs; [ 946 pkg-config 947 rust-bin.stable.latest.minimal 948 ]; 949} 950``` 951 952You can try this out by: 9531. Saving that to `shell.nix` 9542. Executing `nix-shell --pure --command 'rustc --version'` 955 956As of writing, this prints out `rustc 1.56.0 (09c42c458 2021-10-18)`. 957 958### How to use an overlay toolchain in a derivation {#how-to-use-an-overlay-toolchain-in-a-derivation} 959 960You can also use an overlay's Rust toolchain with `buildRustPackage`. 961The below snippet demonstrates invoking `buildRustPackage` with an oxalica overlay selected Rust toolchain: 962```nix 963with import <nixpkgs> { 964 overlays = [ 965 (import (fetchTarball "https://github.com/oxalica/rust-overlay/archive/master.tar.gz")) 966 ]; 967}; 968 969rustPlatform.buildRustPackage rec { 970 pname = "ripgrep"; 971 version = "12.1.1"; 972 nativeBuildInputs = [ 973 rust-bin.stable.latest.minimal 974 ]; 975 976 src = fetchFromGitHub { 977 owner = "BurntSushi"; 978 repo = "ripgrep"; 979 rev = version; 980 sha256 = "1hqps7l5qrjh9f914r5i6kmcz6f1yb951nv4lby0cjnp5l253kps"; 981 }; 982 983 cargoSha256 = "03wf9r2csi6jpa7v5sw5lpxkrk4wfzwmzx7k3991q3bdjzcwnnwp"; 984 985 meta = with lib; { 986 description = "A fast line-oriented regex search tool, similar to ag and ack"; 987 homepage = "https://github.com/BurntSushi/ripgrep"; 988 license = licenses.unlicense; 989 maintainers = [ maintainers.tailhook ]; 990 }; 991} 992``` 993 994Follow the below steps to try that snippet. 9951. create a new directory 9961. save the above snippet as `default.nix` in that directory 9971. cd into that directory and run `nix-build` 998 999### Rust overlay installation {#rust-overlay-installation} 1000 1001You can use this overlay by either changing your local nixpkgs configuration, 1002or by adding the overlay declaratively in a nix expression, e.g. in `configuration.nix`. 1003For more information see [the manual on installing overlays](#sec-overlays-install). 1004 1005### Declarative Rust overlay installation {#declarative-rust-overlay-installation} 1006 1007This snippet shows how to use oxalica's Rust overlay. 1008Add the following to your `configuration.nix`, `home-configuration.nix`, `shell.nix`, or similar: 1009 1010```nix 1011{ pkgs ? import <nixpkgs> { 1012 overlays = [ 1013 (import (builtins.fetchTarball "https://github.com/oxalica/rust-overlay/archive/master.tar.gz")) 1014 # Further overlays go here 1015 ]; 1016 }; 1017}; 1018``` 1019 1020Note that this will fetch the latest overlay version when rebuilding your system.