mirror of
https://github.com/NixOS/nixpkgs.git
synced 2025-06-25 02:26:19 +03:00

This has several advantages: 1. It takes up less space on disk in-between builds in the nix store. 2. It uses less space in the binary cache for vendor derivation packages. 3. It uses less network traffic downloading from the binary cache. 4. It plays nicely with hashed mirrors like tarballs.nixos.org, which only substitute --flat hashes on single files (not recursive directory hashes). 5. It's consistent with how simple `fetchurl` src derivations work. 6. It provides a stronger abstraction between input src-package and output package, e.g., it's harder to accidentally depend on the src derivation at runtime by referencing something like `${src}/etc/index.html`. Likewise, in the store it's harder to get confused with something that is just there as a build-time dependency vs. a runtime dependency, since the build-time src dependencies are tarred up. Disadvantages are: 1. It takes slightly longer to untar at the start of a build. As currently implemented, this attaches the compacted vendor.tar.gz feature as a rider on `verifyCargoDeps`, since both of them are relatively newly implemented behavior that change the `cargoSha256`. If this PR is accepted, I will push forward the remaining rust packages with a series of treewide PRs to update the `cargoSha256`s.
419 lines
13 KiB
Markdown
419 lines
13 KiB
Markdown
---
|
|
title: Rust
|
|
author: Matthias Beyer
|
|
date: 2017-03-05
|
|
---
|
|
|
|
# Rust
|
|
|
|
To install the rust compiler and cargo put
|
|
|
|
```
|
|
rustc
|
|
cargo
|
|
```
|
|
|
|
into the `environment.systemPackages` 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).
|
|
|
|
## Compiling Rust applications with Cargo
|
|
|
|
Rust applications are packaged by using the `buildRustPackage` helper from `rustPlatform`:
|
|
|
|
```
|
|
rustPlatform.buildRustPackage rec {
|
|
pname = "ripgrep";
|
|
version = "11.0.2";
|
|
|
|
src = fetchFromGitHub {
|
|
owner = "BurntSushi";
|
|
repo = pname;
|
|
rev = version;
|
|
sha256 = "1iga3320mgi7m853la55xip514a3chqsdi1a1rwv25lr9b1p7vd3";
|
|
};
|
|
|
|
cargoSha256 = "17ldqr3asrdcsh4l29m3b5r37r5d0b3npq1lrgjmxb6vlx6a36qh";
|
|
legacyCargoFetcher = false;
|
|
|
|
meta = with stdenv.lib; {
|
|
description = "A fast line-oriented regex search tool, similar to ag and ack";
|
|
homepage = https://github.com/BurntSushi/ripgrep;
|
|
license = licenses.unlicense;
|
|
maintainers = [ maintainers.tailhook ];
|
|
platforms = platforms.all;
|
|
};
|
|
}
|
|
```
|
|
|
|
`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.
|
|
|
|
When the `Cargo.lock`, provided by upstream, is not in sync with the
|
|
`Cargo.toml`, it is possible to use `cargoPatches` to update it. All patches
|
|
added in `cargoPatches` will also be prepended to the patches in `patches` at
|
|
build-time.
|
|
|
|
Setting `legacyCargoFetcher` to `false` enables the following behavior:
|
|
|
|
1. The `Cargo.lock` file is copied into the cargo vendor directory.
|
|
2. At buildtime, `buildRustPackage` will ensure that the `src` and `cargoSha256`
|
|
are consistent. This avoids errors where one but not the other is updated.
|
|
3. The builder will compress the vendored cargo src directory into a tar.gz file
|
|
for storage after vendoring, and decompress it before the build. This saves
|
|
disk space and enables hashed mirrors for Rust dependencies.
|
|
|
|
Note that this option changes the value of `cargoSha256`, so it is currently
|
|
defaulted to `false`. When updating a Rust package, please set it to `true`;
|
|
eventually we will default this to true and update the remaining Rust packages,
|
|
then delete the option from all individual Rust package expressions.
|
|
|
|
### Building a crate for a different target
|
|
|
|
To build your crate with a different cargo `--target` simply specify the `target` attribute:
|
|
|
|
```nix
|
|
pkgs.rustPlatform.buildRustPackage {
|
|
(...)
|
|
target = "x86_64-fortanix-unknown-sgx";
|
|
}
|
|
```
|
|
|
|
## Compiling Rust crates using Nix instead of Cargo
|
|
|
|
### Simple operation
|
|
|
|
When run, `cargo build` produces a file called `Cargo.lock`,
|
|
containing pinned versions of all dependencies. Nixpkgs contains a
|
|
tool called `carnix` (`nix-env -iA nixos.carnix`), which can be used
|
|
to turn a `Cargo.lock` into a Nix expression.
|
|
|
|
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
|
|
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
|
|
|
|
Now, the file produced by the call to `carnix`, called `hello.nix`, looks like:
|
|
|
|
```
|
|
# Generated by carnix 0.6.5: carnix -o hello.nix --src ./. Cargo.lock --standalone
|
|
{ lib, stdenv, buildRustCrate, fetchgit }:
|
|
let kernel = stdenv.buildPlatform.parsed.kernel.name;
|
|
# ... (content skipped)
|
|
in
|
|
rec {
|
|
hello = f: hello_0_1_0 { features = hello_0_1_0_features { hello_0_1_0 = f; }; };
|
|
hello_0_1_0_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate {
|
|
crateName = "hello";
|
|
version = "0.1.0";
|
|
authors = [ "pe@pijul.org <pe@pijul.org>" ];
|
|
src = ./.;
|
|
inherit dependencies buildDependencies features;
|
|
};
|
|
hello_0_1_0 = { features?(hello_0_1_0_features {}) }: hello_0_1_0_ {};
|
|
hello_0_1_0_features = f: updateFeatures f (rec {
|
|
hello_0_1_0.default = (f.hello_0_1_0.default or true);
|
|
}) [ ];
|
|
}
|
|
```
|
|
|
|
In particular, note that the argument given as `--src` is copied
|
|
verbatim to the source. If we look at a more complicated
|
|
dependencies, for instance by adding a single line `libc="*"` to our
|
|
`Cargo.toml`, we first need to run `cargo build` to update the
|
|
`Cargo.lock`. Then, `carnix` needs to be run again, and produces the
|
|
following nix file:
|
|
|
|
```
|
|
# Generated by carnix 0.6.5: carnix -o hello.nix --src ./. Cargo.lock --standalone
|
|
{ lib, stdenv, buildRustCrate, fetchgit }:
|
|
let kernel = stdenv.buildPlatform.parsed.kernel.name;
|
|
# ... (content skipped)
|
|
in
|
|
rec {
|
|
hello = f: hello_0_1_0 { features = hello_0_1_0_features { hello_0_1_0 = f; }; };
|
|
hello_0_1_0_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate {
|
|
crateName = "hello";
|
|
version = "0.1.0";
|
|
authors = [ "pe@pijul.org <pe@pijul.org>" ];
|
|
src = ./.;
|
|
inherit dependencies buildDependencies features;
|
|
};
|
|
libc_0_2_36_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate {
|
|
crateName = "libc";
|
|
version = "0.2.36";
|
|
authors = [ "The Rust Project Developers" ];
|
|
sha256 = "01633h4yfqm0s302fm0dlba469bx8y6cs4nqc8bqrmjqxfxn515l";
|
|
inherit dependencies buildDependencies features;
|
|
};
|
|
hello_0_1_0 = { features?(hello_0_1_0_features {}) }: hello_0_1_0_ {
|
|
dependencies = mapFeatures features ([ libc_0_2_36 ]);
|
|
};
|
|
hello_0_1_0_features = f: updateFeatures f (rec {
|
|
hello_0_1_0.default = (f.hello_0_1_0.default or true);
|
|
libc_0_2_36.default = true;
|
|
}) [ libc_0_2_36_features ];
|
|
libc_0_2_36 = { features?(libc_0_2_36_features {}) }: libc_0_2_36_ {
|
|
features = mkFeatures (features.libc_0_2_36 or {});
|
|
};
|
|
libc_0_2_36_features = f: updateFeatures f (rec {
|
|
libc_0_2_36.default = (f.libc_0_2_36.default or true);
|
|
libc_0_2_36.use_std =
|
|
(f.libc_0_2_36.use_std or false) ||
|
|
(f.libc_0_2_36.default or false) ||
|
|
(libc_0_2_36.default or false);
|
|
}) [];
|
|
}
|
|
```
|
|
|
|
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
|
|
|
|
Some crates require external libraries. For crates from
|
|
[crates.io](https://crates.io), such libraries can be specified in
|
|
`defaultCrateOverrides` package in nixpkgs itself.
|
|
|
|
Starting from that file, one can add more overrides, to add features
|
|
or build inputs by overriding the hello crate in a seperate file.
|
|
|
|
```
|
|
with import <nixpkgs> {};
|
|
((import ./hello.nix).hello {}).override {
|
|
crateOverrides = defaultCrateOverrides // {
|
|
hello = attrs: { buildInputs = [ openssl ]; };
|
|
};
|
|
}
|
|
```
|
|
|
|
Here, `crateOverrides` is expected to be a attribute set, where the
|
|
key is the crate name without version number and the value a function.
|
|
The function gets all attributes passed to `buildRustCrate` as first
|
|
argument and returns a set that contains all attribute that should be
|
|
overwritten.
|
|
|
|
For more complicated cases, such as when parts of the crate's
|
|
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:
|
|
|
|
```
|
|
with import <nixpkgs> {};
|
|
((import ./hello.nix).hello {}).override {
|
|
crateOverrides = defaultCrateOverrides // {
|
|
hello = attrs: lib.optionalAttrs (lib.versionAtLeast attrs.version "1.0") {
|
|
postPatch = ''
|
|
substituteInPlace lib/zoneinfo.rs \
|
|
--replace "/usr/share/zoneinfo" "${tzdata}/share/zoneinfo"
|
|
'';
|
|
};
|
|
};
|
|
}
|
|
```
|
|
|
|
Another situation is when we want to override a nested
|
|
dependency. This actually works in the exact same way, since the
|
|
`crateOverrides` parameter is forwarded to the crate's
|
|
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:
|
|
|
|
```
|
|
with import <nixpkgs> {};
|
|
((import hello.nix).hello {}).override {
|
|
crateOverrides = defaultCrateOverrides // {
|
|
libc = attrs: { buildInputs = []; };
|
|
};
|
|
}
|
|
```
|
|
|
|
### 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:
|
|
|
|
```
|
|
(hello {}).override { rust = pkgs.rust; };
|
|
```
|
|
|
|
- Whether to build in release mode or debug mode (release mode by
|
|
default):
|
|
|
|
```
|
|
(hello {}).override { release = false; };
|
|
```
|
|
|
|
- Whether to print the commands sent to rustc when building
|
|
(equivalent to `--verbose` in cargo:
|
|
|
|
```
|
|
(hello {}).override { verbose = false; };
|
|
```
|
|
|
|
- Extra arguments to be passed to `rustc`:
|
|
|
|
```
|
|
(hello {}).override { extraRustcOpts = "-Z debuginfo=2"; };
|
|
```
|
|
|
|
- Phases, just like in any other derivation, can be specified using
|
|
the following attributes: `preUnpack`, `postUnpack`, `prePatch`,
|
|
`patches`, `postPatch`, `preConfigure` (in the case of a Rust crate,
|
|
this is run before calling the "build" script), `postConfigure`
|
|
(after the "build" script),`preBuild`, `postBuild`, `preInstall` and
|
|
`postInstall`. As an example, here is how to create a new module
|
|
before running the build script:
|
|
|
|
```
|
|
(hello {}).override {
|
|
preConfigure = ''
|
|
echo "pub const PATH=\"${hi.out}\";" >> src/path.rs"
|
|
'';
|
|
};
|
|
```
|
|
|
|
### 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:
|
|
|
|
```
|
|
(callPackage ./diesel.nix {}).diesel {
|
|
default = false;
|
|
postgres = true;
|
|
}
|
|
```
|
|
|
|
Where `diesel.nix` is the file generated by Carnix, as explained above.
|
|
|
|
|
|
## 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:
|
|
|
|
```
|
|
with import <nixpkgs> {};
|
|
|
|
stdenv.mkDerivation {
|
|
name = "rust-env";
|
|
nativeBuildInputs = [
|
|
rustc cargo
|
|
|
|
# Example Build-time Additional Dependencies
|
|
pkgconfig
|
|
];
|
|
buildInputs = [
|
|
# Example Run-time Additional Dependencies
|
|
openssl
|
|
];
|
|
|
|
# Set Environment Variables
|
|
RUST_BACKTRACE = 1;
|
|
}
|
|
```
|
|
|
|
You should now be able to run the following:
|
|
```
|
|
$ nix-shell --pure
|
|
$ cargo build
|
|
$ cargo test
|
|
```
|
|
|
|
### 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`
|
|
|
|
```
|
|
# Latest Nightly
|
|
with import <nixpkgs> {};
|
|
let src = fetchFromGitHub {
|
|
owner = "mozilla";
|
|
repo = "nixpkgs-mozilla";
|
|
# commit from: 2019-05-15
|
|
rev = "9f35c4b09fd44a77227e79ff0c1b4b6a69dff533";
|
|
sha256 = "18h0nvh55b5an4gmlgfbvwbyqj91bklf1zymis6lbdh75571qaz0";
|
|
};
|
|
in
|
|
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`
|
|
latest.rustChannels.nightly.rust
|
|
|
|
# Add some extra dependencies from `pkgs`
|
|
pkgconfig openssl
|
|
];
|
|
|
|
# Set Environment Variables
|
|
RUST_BACKTRACE = 1;
|
|
}
|
|
```
|
|
|
|
Now run:
|
|
```
|
|
$ rustc --version
|
|
rustc 1.26.0-nightly (188e693b3 2018-03-26)
|
|
```
|
|
|
|
To see that you are using nightly.
|
|
|
|
|
|
## 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),
|
|
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
|
|
|
|
The latest version can be installed with the following command:
|
|
|
|
$ nix-env -Ai nixos.latest.rustChannels.stable.rust
|
|
|
|
Or using the attribute with nix-shell:
|
|
|
|
$ nix-shell -p nixos.latest.rustChannels.stable.rust
|
|
|
|
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
|
|
build date.
|
|
|
|
The overlay automatically updates itself as it uses the same source as
|
|
[rustup](https://www.rustup.rs/).
|