diff options
Diffstat (limited to 'doc/languages-frameworks/rust.section.md')
-rw-r--r-- | doc/languages-frameworks/rust.section.md | 605 |
1 files changed, 522 insertions, 83 deletions
diff --git a/doc/languages-frameworks/rust.section.md b/doc/languages-frameworks/rust.section.md index 6c51da87cab..f5c664bec20 100644 --- a/doc/languages-frameworks/rust.section.md +++ b/doc/languages-frameworks/rust.section.md @@ -1,44 +1,41 @@ ---- -title: Rust -author: Matthias Beyer -date: 2017-03-05 ---- - -# Rust +# Rust {#rust} To install the rust compiler and cargo put -``` -rustc -cargo +```nix +environment.systemPackages = [ + rustc + cargo +]; ``` -into the `environment.systemPackages` or bring them into -scope with `nix-shell -p rustc cargo`. +into your `configuration.nix` or bring them into scope with `nix-shell -p rustc cargo`. -For daily builds (beta and nightly) use either rustup from -nixpkgs or use the [Rust nightlies -overlay](#using-the-rust-nightlies-overlay). +For other versions such as daily builds (beta and nightly), +use either `rustup` from nixpkgs (which will manage the rust installation in your home directory), +or use Mozilla's [Rust nightlies overlay](#using-the-rust-nightlies-overlay). -## Compiling Rust applications with Cargo +## Compiling Rust applications with Cargo {#compiling-rust-applications-with-cargo} Rust applications are packaged by using the `buildRustPackage` helper from `rustPlatform`: -``` +```nix +{ lib, rustPlatform }: + rustPlatform.buildRustPackage rec { pname = "ripgrep"; - version = "11.0.2"; + version = "12.1.1"; src = fetchFromGitHub { owner = "BurntSushi"; repo = pname; rev = version; - sha256 = "1iga3320mgi7m853la55xip514a3chqsdi1a1rwv25lr9b1p7vd3"; + sha256 = "1hqps7l5qrjh9f914r5i6kmcz6f1yb951nv4lby0cjnp5l253kps"; }; - cargoSha256 = "17ldqr3asrdcsh4l29m3b5r37r5d0b3npq1lrgjmxb6vlx6a36qh"; + cargoSha256 = "03wf9r2csi6jpa7v5sw5lpxkrk4wfzwmzx7k3991q3bdjzcwnnwp"; - meta = with stdenv.lib; { + meta = with lib; { description = "A fast line-oriented regex search tool, similar to ag and ack"; homepage = "https://github.com/BurntSushi/ripgrep"; license = licenses.unlicense; @@ -47,34 +44,189 @@ rustPlatform.buildRustPackage rec { } ``` -`buildRustPackage` requires a `cargoSha256` attribute which is computed over -all crate sources of this package. Currently it is obtained by inserting a -fake checksum into the expression and building the package once. The correct -checksum can be then take from the failed build. +`buildRustPackage` requires either the `cargoSha256` or the +`cargoHash` attribute which is computed over all crate sources of this +package. `cargoHash256` is used for traditional Nix SHA-256 hashes, +such as the one in the example above. `cargoHash` should instead be +used for [SRI](https://www.w3.org/TR/SRI/) hashes. For example: + +```nix + cargoHash = "sha256-l1vL2ZdtDRxSGvP0X/l3nMw8+6WF67KPutJEzUROjg8="; +``` + +Both types of hashes are permitted when contributing to nixpkgs. The +Cargo hash is obtained by inserting a fake checksum into the +expression and building the package once. The correct checksum can +then be taken from the failed build. A fake hash can be used for +`cargoSha256` as follows: + +```nix + cargoSha256 = lib.fakeSha256; +``` + +For `cargoHash` you can use: + +```nix + cargoHash = lib.fakeHash; +``` Per the instructions in the [Cargo Book](https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html) best practices guide, Rust applications should always commit the `Cargo.lock` file in git to ensure a reproducible build. However, a few packages do not, and -Nix depends on this file, so if it missing you can use `cargoPatches` to apply -it in the `patchPhase`. Consider sending a PR upstream with a note to the +Nix depends on this file, so if it is missing you can use `cargoPatches` to +apply it in the `patchPhase`. Consider sending a PR upstream with a note to the maintainer describing why it's important to include in the application. The fetcher will verify that the `Cargo.lock` file is in sync with the `src` attribute, and fail the build if not. It will also will compress the vendor directory into a tar.gz archive. -### Building a crate for a different target +The tarball with vendored dependencies contains a directory with the +package's `name`, which is normally composed of `pname` and +`version`. This means that the vendored dependencies hash +(`cargoSha256`/`cargoHash`) is dependent on the package name and +version. The `cargoDepsName` attribute can be used to use another name +for the directory of vendored dependencies. For example, the hash can +be made invariant to the version by setting `cargoDepsName` to +`pname`: + +```nix +rustPlatform.buildRustPackage rec { + pname = "broot"; + version = "1.2.0"; + + src = fetchCrate { + inherit pname version; + sha256 = "1mqaynrqaas82f5957lx31x80v74zwmwmjxxlbywajb61vh00d38"; + }; + + cargoHash = "sha256-JmBZcDVYJaK1cK05cxx5BrnGWp4t8ca6FLUbvIot67s="; + cargoDepsName = pname; + + # ... +} +``` + +### Importing a `Cargo.lock` file {#importing-a-cargo.lock-file} + +Using `cargoSha256` or `cargoHash` is tedious when using +`buildRustPackage` within a project, since it requires that the hash +is updated after every change to `Cargo.lock`. Therefore, +`buildRustPackage` also supports vendoring dependencies directly from +a `Cargo.lock` file using the `cargoLock` argument. For example: + +```nix +rustPlatform.buildRustPackage rec { + pname = "myproject"; + version = "1.0.0"; + + cargoLock = { + lockFile = ./Cargo.lock; + } + + # ... +} +``` + +This will retrieve the dependencies using fixed-output derivations from +the specified lockfile. + +The output hash of each dependency that uses a git source must be +specified in the `outputHashes` attribute. For example: + +```nix +rustPlatform.buildRustPackage rec { + pname = "myproject"; + version = "1.0.0"; + + cargoLock = { + lockFile = ./Cargo.lock; + outputHashes = { + "finalfusion-0.14.0" = "17f4bsdzpcshwh74w5z119xjy2if6l2wgyjy56v621skr2r8y904"; + }; + } + + # ... +} +``` + +If you do not specify an output hash for a git dependency, building +the package will fail and inform you of which crate needs to be +added. To find the correct hash, you can first use `lib.fakeSha256` or +`lib.fakeHash` as a stub hash. Building the package (and thus the +vendored dependencies) will then inform you of the correct hash. -To build your crate with a different cargo `--target` simply specify the `target` attribute: +### Cross compilation {#cross-compilation} + +By default, Rust packages are compiled for the host platform, just like any +other package is. The `--target` passed to rust tools is computed from this. +By default, it takes the `stdenv.hostPlatform.config` and replaces components +where they are known to differ. But there are ways to customize the argument: + + - To choose a different target by name, define + `stdenv.hostPlatform.rustc.config` as that name (a string), and that + name will be used instead. + + For example: + + ```nix + import <nixpkgs> { + crossSystem = (import <nixpkgs/lib>).systems.examples.armhf-embedded // { + rustc.config = "thumbv7em-none-eabi"; + }; + } + ``` + + will result in: + + ```shell + --target thumbv7em-none-eabi + ``` + + - To pass a completely custom target, define + `stdenv.hostPlatform.rustc.config` with its name, and + `stdenv.hostPlatform.rustc.platform` with the value. The value will be + serialized to JSON in a file called + `${stdenv.hostPlatform.rustc.config}.json`, and the path of that file + will be used instead. + + For example: + + ```nix + import <nixpkgs> { + crossSystem = (import <nixpkgs/lib>).systems.examples.armhf-embedded // { + rustc.config = "thumb-crazy"; + rustc.platform = { foo = ""; bar = ""; }; + }; + } + ``` + + will result in: + + ```shell + --target /nix/store/asdfasdfsadf-thumb-crazy.json # contains {"foo":"","bar":""} + ``` + +Finally, as an ad-hoc escape hatch, a computed target (string or JSON file +path) can be passed directly to `buildRustPackage`: ```nix pkgs.rustPlatform.buildRustPackage { - (...) + /* ... */ target = "x86_64-fortanix-unknown-sgx"; } ``` -### Running package tests +This is useful to avoid rebuilding Rust tools, since they are actually target +agnostic and don't need to be rebuilt. But in the future, we should always +build the Rust tools and standard library crates separately so there is no +reason not to take the `stdenv.hostPlatform.rustc`-modifying approach, and the +ad-hoc escape hatch to `buildRustPackage` can be removed. + +Note that currently custom targets aren't compiled with `std`, so `cargo test` +will fail. This can be ignored by adding `doCheck = false;` to your derivation. + +### Running package tests {#running-package-tests} When using `buildRustPackage`, the `checkPhase` is enabled by default and runs `cargo test` on the package to build. To make sure that we don't compile the @@ -95,7 +247,14 @@ rustPlatform.buildRustPackage { Please note that the code will be compiled twice here: once in `release` mode for the `buildPhase`, and again in `debug` mode for the `checkPhase`. -#### Tests relying on the structure of the `target/` directory +Test flags, e.g., `--features xxx/yyy`, can be passed to `cargo test` via the +`cargoTestFlags` attribute. + +Another attribute, called `checkFlags`, is used to pass arguments to the test +binary itself, as stated +(here)[https://doc.rust-lang.org/cargo/commands/cargo-test.html]. + +#### Tests relying on the structure of the `target/` directory {#tests-relying-on-the-structure-of-the-target-directory} Some tests may rely on the structure of the `target/` directory. Those tests are likely to fail because we use `cargo --target` during the build. This means that @@ -105,7 +264,7 @@ rather than in `target/release/`. This can only be worked around by patching the affected tests accordingly. -#### Disabling package-tests +#### Disabling package-tests {#disabling-package-tests} In some instances, it may be necessary to disable testing altogether (with `doCheck = false;`): @@ -119,7 +278,19 @@ The above are just guidelines, and exceptions may be granted on a case-by-case b However, please check if it's possible to disable a problematic subset of the test suite and leave a comment explaining your reasoning. -### Building a package in `debug` mode +#### Setting `test-threads` {#setting-test-threads} + +`buildRustPackage` will use parallel test threads by default, +sometimes it may be necessary to disable this so the tests run consecutively. + +```nix +rustPlatform.buildRustPackage { + /* ... */ + dontUseCargoParallelTests = true; +} +``` + +### Building a package in `debug` mode {#building-a-package-in-debug-mode} By default, `buildRustPackage` will use `release` mode for builds. If a package should be built in `debug` mode, it can be configured like so: @@ -133,22 +304,20 @@ rustPlatform.buildRustPackage { In this scenario, the `checkPhase` will be ran in `debug` mode as well. -### Custom `build`/`install`-procedures +### Custom `build`/`install`-procedures {#custom-buildinstall-procedures} Some packages may use custom scripts for building/installing, e.g. with a `Makefile`. In these cases, it's recommended to override the `buildPhase`/`installPhase`/`checkPhase`. Otherwise, some steps may fail because of the modified directory structure of `target/`. -### 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 {#building-a-crate-with-an-absent-or-out-of-date-cargo.lock-file} `buildRustPackage` needs a `Cargo.lock` file to get all dependencies in the source code in a reproducible way. If it is missing or out-of-date one can use the `cargoPatches` attribute to update or add it. -``` -{ lib, rustPlatform, fetchFromGitHub }: - +```nix rustPlatform.buildRustPackage rec { (...) cargoPatches = [ @@ -158,9 +327,233 @@ rustPlatform.buildRustPackage rec { } ``` -## Compiling Rust crates using Nix instead of Cargo +## Compiling non-Rust packages that include Rust code {#compiling-non-rust-packages-that-include-rust-code} + +Several non-Rust packages incorporate Rust code for performance- or +security-sensitive parts. `rustPlatform` exposes several functions and +hooks that can be used to integrate Cargo in non-Rust packages. + +### Vendoring of dependencies {#vendoring-of-dependencies} + +Since network access is not allowed in sandboxed builds, Rust crate +dependencies need to be retrieved using a fetcher. `rustPlatform` +provides the `fetchCargoTarball` fetcher, which vendors all +dependencies of a crate. For example, given a source path `src` +containing `Cargo.toml` and `Cargo.lock`, `fetchCargoTarball` +can be used as follows: + +```nix +cargoDeps = rustPlatform.fetchCargoTarball { + inherit src; + hash = "sha256-BoHIN/519Top1NUBjpB/oEMqi86Omt3zTQcXFWqrek0="; +}; +``` -### Simple operation +The `src` attribute is required, as well as a hash specified through +one of the `sha256` or `hash` attributes. The following optional +attributes can also be used: + +* `name`: the name that is used for the dependencies tarball. If + `name` is not specified, then the name `cargo-deps` will be used. +* `sourceRoot`: when the `Cargo.lock`/`Cargo.toml` are in a + subdirectory, `sourceRoot` specifies the relative path to these + files. +* `patches`: patches to apply before vendoring. This is useful when + the `Cargo.lock`/`Cargo.toml` files need to be patched before + vendoring. + +If a `Cargo.lock` file is available, you can alternatively use the +`importCargoLock` function. In contrast to `fetchCargoTarball`, this +function does not require a hash (unless git dependencies are used) +and fetches every dependency as a separate fixed-output derivation. +`importCargoLock` can be used as follows: + +``` +cargoDeps = rustPlatform.importCargoLock { + lockFile = ./Cargo.lock; +}; +``` + +If the `Cargo.lock` file includes git dependencies, then their output +hashes need to be specified since they are not available through the +lock file. For example: + +``` +cargoDeps = rustPlatform.importCargoLock { + lockFile = ./Cargo.lock; + outputHashes = { + "rand-0.8.3" = "0ya2hia3cn31qa8894s3av2s8j5bjwb6yq92k0jsnlx7jid0jwqa"; + }; +}; +``` + +If you do not specify an output hash for a git dependency, building +`cargoDeps` will fail and inform you of which crate needs to be +added. To find the correct hash, you can first use `lib.fakeSha256` or +`lib.fakeHash` as a stub hash. Building `cargoDeps` will then inform +you of the correct hash. + +### Hooks {#hooks} + +`rustPlatform` provides the following hooks to automate Cargo builds: + +* `cargoSetupHook`: configure Cargo to use depenencies vendored + through `fetchCargoTarball`. This hook uses the `cargoDeps` + environment variable to find the vendored dependencies. If a project + already vendors its dependencies, the variable `cargoVendorDir` can + be used instead. When the `Cargo.toml`/`Cargo.lock` files are not in + `sourceRoot`, then the optional `cargoRoot` is used to specify the + Cargo root directory relative to `sourceRoot`. +* `cargoBuildHook`: use Cargo to build a crate. If the crate to be + built is a crate in e.g. a Cargo workspace, the relative path to the + crate to build can be set through the optional `buildAndTestSubdir` + environment variable. Additional Cargo build flags can be passed + through `cargoBuildFlags`. +* `maturinBuildHook`: use [Maturin](https://github.com/PyO3/maturin) + to build a Python wheel. Similar to `cargoBuildHook`, the optional + variable `buildAndTestSubdir` can be used to build a crate in a + Cargo workspace. Additional maturin flags can be passed through + `maturinBuildFlags`. +* `cargoCheckHook`: run tests using Cargo. The build type for checks + can be set using `cargoCheckType`. Additional flags can be passed to + the tests using `checkFlags` and `checkFlagsArray`. By default, + tests are run in parallel. This can be disabled by setting + `dontUseCargoParallelTests`. +* `cargoInstallHook`: install binaries and static/shared libraries + that were built using `cargoBuildHook`. + +### Examples {#examples} + +#### Python package using `setuptools-rust` {#python-package-using-setuptools-rust} + +For Python packages using `setuptools-rust`, you can use +`fetchCargoTarball` and `cargoSetupHook` to retrieve and set up Cargo +dependencies. The build itself is then performed by +`buildPythonPackage`. + +The following example outlines how the `tokenizers` Python package is +built. Since the Python package is in the `source/bindings/python` +directory of the *tokenizers* project's source archive, we use +`sourceRoot` to point the tooling to this directory: + +```nix +{ fetchFromGitHub +, buildPythonPackage +, rustPlatform +, setuptools-rust +}: + +buildPythonPackage rec { + pname = "tokenizers"; + version = "0.10.0"; + + src = fetchFromGitHub { + owner = "huggingface"; + repo = pname; + rev = "python-v${version}"; + hash = "sha256-rQ2hRV52naEf6PvRsWVCTN7B1oXAQGmnpJw4iIdhamw="; + }; + + cargoDeps = rustPlatform.fetchCargoTarball { + inherit src sourceRoot; + name = "${pname}-${version}"; + hash = "sha256-BoHIN/519Top1NUBjpB/oEMqi86Omt3zTQcXFWqrek0="; + }; + + sourceRoot = "source/bindings/python"; + + nativeBuildInputs = [ setuptools-rust ] ++ (with rustPlatform; [ + cargoSetupHook + rust.cargo + rust.rustc + ]); + + # ... +} +``` + +In some projects, the Rust crate is not in the main Python source +directory. In such cases, the `cargoRoot` attribute can be used to +specify the crate's directory relative to `sourceRoot`. In the +following example, the crate is in `src/rust`, as specified in the +`cargoRoot` attribute. Note that we also need to specify the correct +path for `fetchCargoTarball`. + +```nix + +{ buildPythonPackage +, fetchPypi +, rustPlatform +, setuptools-rust +, openssl +}: + +buildPythonPackage rec { + pname = "cryptography"; + version = "3.4.2"; # Also update the hash in vectors.nix + + src = fetchPypi { + inherit pname version; + sha256 = "1i1mx5y9hkyfi9jrrkcw804hmkcglxi6rmf7vin7jfnbr2bf4q64"; + }; + + cargoDeps = rustPlatform.fetchCargoTarball { + inherit src; + sourceRoot = "${pname}-${version}/${cargoRoot}"; + name = "${pname}-${version}"; + hash = "sha256-PS562W4L1NimqDV2H0jl5vYhL08H9est/pbIxSdYVfo="; + }; + + cargoRoot = "src/rust"; + + # ... +} +``` + +#### Python package using `maturin` {#python-package-using-maturin} + +Python packages that use [Maturin](https://github.com/PyO3/maturin) +can be built with `fetchCargoTarball`, `cargoSetupHook`, and +`maturinBuildHook`. For example, the following (partial) derivation +builds the `retworkx` Python package. `fetchCargoTarball` and +`cargoSetupHook` are used to fetch and set up the crate dependencies. +`maturinBuildHook` is used to perform the build. + +```nix +{ lib +, buildPythonPackage +, rustPlatform +, fetchFromGitHub +}: + +buildPythonPackage rec { + pname = "retworkx"; + version = "0.6.0"; + + src = fetchFromGitHub { + owner = "Qiskit"; + repo = "retworkx"; + rev = version; + sha256 = "11n30ldg3y3y6qxg3hbj837pnbwjkqw3nxq6frds647mmmprrd20"; + }; + + cargoDeps = rustPlatform.fetchCargoTarball { + inherit src; + name = "${pname}-${version}"; + hash = "sha256-heOBK8qi2nuc/Ib+I/vLzZ1fUUD/G/KTw9d7M4Hz5O0="; + }; + + format = "pyproject"; + + nativeBuildInputs = with rustPlatform; [ cargoSetupHook maturinBuildHook ]; + + # ... +} +``` + +## Compiling Rust crates using Nix instead of Cargo {#compiling-rust-crates-using-nix-instead-of-cargo} + +### Simple operation {#simple-operation} When run, `cargo build` produces a file called `Cargo.lock`, containing pinned versions of all dependencies. Nixpkgs contains a @@ -171,20 +564,21 @@ That Nix expression calls `rustc` directly (hence bypassing Cargo), and can be used to compile a crate and all its dependencies. Here is an example for a minimal `hello` crate: - - $ cargo new hello - $ cd hello - $ cargo build +```ShellSession +$ cargo new hello +$ cd hello +$ cargo build Compiling hello v0.1.0 (file:///tmp/hello) - Finished dev [unoptimized + debuginfo] target(s) in 0.20 secs - $ carnix -o hello.nix --src ./. Cargo.lock --standalone - $ nix-build hello.nix -A hello_0_1_0 + Finished dev [unoptimized + debuginfo] target(s) in 0.20 secs +$ carnix -o hello.nix --src ./. Cargo.lock --standalone +$ nix-build hello.nix -A hello_0_1_0 +``` Now, the file produced by the call to `carnix`, called `hello.nix`, looks like: -``` +```nix # Generated by carnix 0.6.5: carnix -o hello.nix --src ./. Cargo.lock --standalone -{ lib, stdenv, buildRustCrate, fetchgit }: +{ stdenv, buildRustCrate, fetchgit }: let kernel = stdenv.buildPlatform.parsed.kernel.name; # ... (content skipped) in @@ -211,9 +605,9 @@ dependencies, for instance by adding a single line `libc="*"` to our `Cargo.lock`. Then, `carnix` needs to be run again, and produces the following nix file: -``` +```nix # Generated by carnix 0.6.5: carnix -o hello.nix --src ./. Cargo.lock --standalone -{ lib, stdenv, buildRustCrate, fetchgit }: +{ stdenv, buildRustCrate, fetchgit }: let kernel = stdenv.buildPlatform.parsed.kernel.name; # ... (content skipped) in @@ -257,7 +651,7 @@ Here, the `libc` crate has no `src` attribute, so `buildRustCrate` will fetch it from [crates.io](https://crates.io). A `sha256` attribute is still needed for Nix purity. -### Handling external dependencies +### Handling external dependencies {#handling-external-dependencies} Some crates require external libraries. For crates from [crates.io](https://crates.io), such libraries can be specified in @@ -266,7 +660,7 @@ Some crates require external libraries. For crates from Starting from that file, one can add more overrides, to add features or build inputs by overriding the hello crate in a seperate file. -``` +```nix with import <nixpkgs> {}; ((import ./hello.nix).hello {}).override { crateOverrides = defaultCrateOverrides // { @@ -286,7 +680,7 @@ derivation depend on the crate's version, the `attrs` argument of the override above can be read, as in the following example, which patches the derivation: -``` +```nix with import <nixpkgs> {}; ((import ./hello.nix).hello {}).override { crateOverrides = defaultCrateOverrides // { @@ -307,7 +701,7 @@ dependencies. For instance, to override the build inputs for crate `libc` in the example above, where `libc` is a dependency of the main crate, we could do: -``` +```nix with import <nixpkgs> {}; ((import hello.nix).hello {}).override { crateOverrides = defaultCrateOverrides // { @@ -316,34 +710,34 @@ with import <nixpkgs> {}; } ``` -### Options and phases configuration +### Options and phases configuration {#options-and-phases-configuration} Actually, the overrides introduced in the previous section are more general. A number of other parameters can be overridden: - The version of rustc used to compile the crate: - ``` + ```nix (hello {}).override { rust = pkgs.rust; }; ``` - Whether to build in release mode or debug mode (release mode by default): - ``` + ```nix (hello {}).override { release = false; }; ``` - Whether to print the commands sent to rustc when building (equivalent to `--verbose` in cargo: - ``` + ```nix (hello {}).override { verbose = false; }; ``` - Extra arguments to be passed to `rustc`: - ``` + ```nix (hello {}).override { extraRustcOpts = "-Z debuginfo=2"; }; ``` @@ -355,7 +749,7 @@ general. A number of other parameters can be overridden: `postInstall`. As an example, here is how to create a new module before running the build script: - ``` + ```nix (hello {}).override { preConfigure = '' echo "pub const PATH=\"${hi.out}\";" >> src/path.rs" @@ -363,13 +757,13 @@ general. A number of other parameters can be overridden: }; ``` -### Features +### Features {#features} One can also supply features switches. For example, if we want to compile `diesel_cli` only with the `postgres` feature, and no default features, we would write: -``` +```nix (callPackage ./diesel.nix {}).diesel { default = false; postgres = true; @@ -378,21 +772,22 @@ features, we would write: Where `diesel.nix` is the file generated by Carnix, as explained above. +## Setting Up `nix-shell` {#setting-up-nix-shell} -## Setting Up `nix-shell` Oftentimes you want to develop code from within `nix-shell`. Unfortunately `buildRustCrate` does not support common `nix-shell` operations directly (see [this issue](https://github.com/NixOS/nixpkgs/issues/37945)) so we will use `stdenv.mkDerivation` instead. Using the example `hello` project above, we want to do the following: + - Have access to `cargo` and `rustc` - Have the `openssl` library available to a crate through it's _normal_ compilation mechanism (`pkg-config`). A typical `shell.nix` might look like: -``` +```nix with import <nixpkgs> {}; stdenv.mkDerivation { @@ -401,7 +796,7 @@ stdenv.mkDerivation { rustc cargo # Example Build-time Additional Dependencies - pkgconfig + pkg-config ]; buildInputs = [ # Example Run-time Additional Dependencies @@ -414,17 +809,19 @@ stdenv.mkDerivation { ``` You should now be able to run the following: -``` + +```ShellSession $ nix-shell --pure $ cargo build $ cargo test ``` -### Controlling Rust Version Inside `nix-shell` +### Controlling Rust Version Inside `nix-shell` {#controlling-rust-version-inside-nix-shell} + To control your rust version (i.e. use nightly) from within `shell.nix` (or other nix expressions) you can use the following `shell.nix` -``` +```nix # Latest Nightly with import <nixpkgs> {}; let src = fetchFromGitHub { @@ -439,11 +836,11 @@ with import "${src.out}/rust-overlay.nix" pkgs pkgs; stdenv.mkDerivation { name = "rust-env"; buildInputs = [ - # Note: to use use stable, just replace `nightly` with `stable` + # Note: to use stable, just replace `nightly` with `stable` latest.rustChannels.nightly.rust # Add some extra dependencies from `pkgs` - pkgconfig openssl + pkg-config openssl ]; # Set Environment Variables @@ -452,38 +849,80 @@ stdenv.mkDerivation { ``` Now run: -``` + +```ShellSession $ rustc --version rustc 1.26.0-nightly (188e693b3 2018-03-26) ``` To see that you are using nightly. - -## Using the Rust nightlies overlay +## Using the Rust nightlies overlay {#using-the-rust-nightlies-overlay} Mozilla provides an overlay for nixpkgs to bring a nightly version of Rust into scope. This overlay can _also_ be used to install recent unstable or stable versions of Rust, if desired. -To use this overlay, clone -[nixpkgs-mozilla](https://github.com/mozilla/nixpkgs-mozilla), +### Rust overlay installation {#rust-overlay-installation} + +You can use this overlay by either changing your local nixpkgs configuration, +or by adding the overlay declaratively in a nix expression, e.g. in `configuration.nix`. +For more information see [the manual on installing overlays](#sec-overlays-install). + +#### Imperative rust overlay installation {#imperative-rust-overlay-installation} + +Clone [nixpkgs-mozilla](https://github.com/mozilla/nixpkgs-mozilla), and create a symbolic link to the file [rust-overlay.nix](https://github.com/mozilla/nixpkgs-mozilla/blob/master/rust-overlay.nix) in the `~/.config/nixpkgs/overlays` directory. - $ git clone https://github.com/mozilla/nixpkgs-mozilla.git - $ mkdir -p ~/.config/nixpkgs/overlays - $ ln -s $(pwd)/nixpkgs-mozilla/rust-overlay.nix ~/.config/nixpkgs/overlays/rust-overlay.nix +```ShellSession +$ git clone https://github.com/mozilla/nixpkgs-mozilla.git +$ mkdir -p ~/.config/nixpkgs/overlays +$ ln -s $(pwd)/nixpkgs-mozilla/rust-overlay.nix ~/.config/nixpkgs/overlays/rust-overlay.nix +``` + +### Declarative rust overlay installation {#declarative-rust-overlay-installation} + +Add the following to your `configuration.nix`, `home-configuration.nix`, `shell.nix`, or similar: -The latest version can be installed with the following command: +```nix +{ pkgs ? import <nixpkgs> { + overlays = [ + (import (builtins.fetchTarball https://github.com/mozilla/nixpkgs-mozilla/archive/master.tar.gz)) + # Further overlays go here + ]; + }; +}; +``` + +Note that this will fetch the latest overlay version when rebuilding your system. + +### Rust overlay usage {#rust-overlay-usage} + +The overlay contains attribute sets corresponding to different versions of the rust toolchain, such as: - $ nix-env -Ai nixos.latest.rustChannels.stable.rust +* `latest.rustChannels.stable` +* `latest.rustChannels.nightly` +* a function `rustChannelOf`, called as `(rustChannelOf { date = "2018-04-11"; channel = "nightly"; })`, or... +* `(nixpkgs.rustChannelOf { rustToolchain = ./rust-toolchain; })` if you have a local `rust-toolchain` file (see https://github.com/mozilla/nixpkgs-mozilla#using-in-nix-expressions for an example) + +Each of these contain packages such as `rust`, which contains your usual rust development tools with the respective toolchain chosen. +For example, you might want to add `latest.rustChannels.stable.rust` to the list of packages in your configuration. + +Imperatively, the latest stable version can be installed with the following command: + +```ShellSession +$ nix-env -Ai nixpkgs.latest.rustChannels.stable.rust +``` Or using the attribute with nix-shell: - $ nix-shell -p nixos.latest.rustChannels.stable.rust +```ShellSession +$ nix-shell -p nixpkgs.latest.rustChannels.stable.rust +``` +Substitute the `nixpkgs` prefix with `nixos` on NixOS. To install the beta or nightly channel, "stable" should be substituted by "nightly" or "beta", or use the function provided by this overlay to pull a version based on a |