1--- 2title: Rust 3author: Matthias Beyer 4date: 2017-03-05 5--- 6 7# User's Guide to the Rust Infrastructure 8 9To install the rust compiler and cargo put 10 11``` 12rustc 13cargo 14``` 15 16into the `environment.systemPackages` or bring them into 17scope with `nix-shell -p rustc cargo`. 18 19For daily builds (beta and nightly) use either rustup from 20nixpkgs or use the [Rust nightlies 21overlay](#using-the-rust-nightlies-overlay). 22 23## Compiling Rust applications with Cargo 24 25Rust applications are packaged by using the `buildRustPackage` helper from `rustPlatform`: 26 27``` 28rustPlatform.buildRustPackage rec { 29 name = "ripgrep-${version}"; 30 version = "0.4.0"; 31 32 src = fetchFromGitHub { 33 owner = "BurntSushi"; 34 repo = "ripgrep"; 35 rev = "${version}"; 36 sha256 = "0y5d1n6hkw85jb3rblcxqas2fp82h3nghssa4xqrhqnz25l799pj"; 37 }; 38 39 cargoSha256 = "0q68qyl2h6i0qsz82z840myxlnjay8p1w5z7hfyr8fqp7wgwa9cx"; 40 41 meta = with stdenv.lib; { 42 description = "A fast line-oriented regex search tool, similar to ag and ack"; 43 homepage = https://github.com/BurntSushi/ripgrep; 44 license = licenses.unlicense; 45 maintainers = [ maintainers.tailhook ]; 46 platforms = platforms.all; 47 }; 48} 49``` 50 51`buildRustPackage` requires a `cargoSha256` attribute which is computed over 52all crate sources of this package. Currently it is obtained by inserting a 53fake checksum into the expression and building the package once. The correct 54checksum can be then take from the failed build. 55 56To install crates with nix there is also an experimental project called 57[nixcrates](https://github.com/fractalide/nixcrates). 58 59## Compiling Rust crates using Nix instead of Cargo 60 61### Simple operation 62 63When run, `cargo build` produces a file called `Cargo.lock`, 64containing pinned versions of all dependencies. Nixpkgs contains a 65tool called `carnix` (`nix-env -iA nixos.carnix`), which can be used 66to turn a `Cargo.lock` into a Nix expression. 67 68That Nix expression calls `rustc` directly (hence bypassing Cargo), 69and can be used to compile a crate and all its dependencies. Here is 70an example for a minimal `hello` crate: 71 72 73 $ cargo new hello 74 $ cd hello 75 $ cargo build 76 Compiling hello v0.1.0 (file:///tmp/hello) 77 Finished dev [unoptimized + debuginfo] target(s) in 0.20 secs 78 $ carnix -o hello.nix --src ./. Cargo.lock --standalone 79 $ nix-build hello.nix 80 81Now, the file produced by the call to `carnix`, called `hello.nix`, looks like: 82 83``` 84# Generated by carnix 0.6.5: carnix -o hello.nix --src ./. Cargo.lock --standalone 85{ lib, buildPlatform, buildRustCrate, fetchgit }: 86let kernel = buildPlatform.parsed.kernel.name; 87 # ... (content skipped) 88in 89rec { 90 hello = f: hello_0_1_0 { features = hello_0_1_0_features { hello_0_1_0 = f; }; }; 91 hello_0_1_0_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate { 92 crateName = "hello"; 93 version = "0.1.0"; 94 authors = [ "pe@pijul.org <pe@pijul.org>" ]; 95 src = ./.; 96 inherit dependencies buildDependencies features; 97 }; 98 hello_0_1_0 = { features?(hello_0_1_0_features {}) }: hello_0_1_0_ {}; 99 hello_0_1_0_features = f: updateFeatures f (rec { 100 hello_0_1_0.default = (f.hello_0_1_0.default or true); 101 }) [ ]; 102} 103``` 104 105In particular, note that the argument given as `--src` is copied 106verbatim to the source. If we look at a more complicated 107dependencies, for instance by adding a single line `libc="*"` to our 108`Cargo.toml`, we first need to run `cargo build` to update the 109`Cargo.lock`. Then, `carnix` needs to be run again, and produces the 110following nix file: 111 112``` 113# Generated by carnix 0.6.5: carnix -o hello.nix --src ./. Cargo.lock --standalone 114{ lib, buildPlatform, buildRustCrate, fetchgit }: 115let kernel = buildPlatform.parsed.kernel.name; 116 # ... (content skipped) 117in 118rec { 119 hello = f: hello_0_1_0 { features = hello_0_1_0_features { hello_0_1_0 = f; }; }; 120 hello_0_1_0_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate { 121 crateName = "hello"; 122 version = "0.1.0"; 123 authors = [ "pe@pijul.org <pe@pijul.org>" ]; 124 src = ./.; 125 inherit dependencies buildDependencies features; 126 }; 127 libc_0_2_36_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate { 128 crateName = "libc"; 129 version = "0.2.36"; 130 authors = [ "The Rust Project Developers" ]; 131 sha256 = "01633h4yfqm0s302fm0dlba469bx8y6cs4nqc8bqrmjqxfxn515l"; 132 inherit dependencies buildDependencies features; 133 }; 134 hello_0_1_0 = { features?(hello_0_1_0_features {}) }: hello_0_1_0_ { 135 dependencies = mapFeatures features ([ libc_0_2_36 ]); 136 }; 137 hello_0_1_0_features = f: updateFeatures f (rec { 138 hello_0_1_0.default = (f.hello_0_1_0.default or true); 139 libc_0_2_36.default = true; 140 }) [ libc_0_2_36_features ]; 141 libc_0_2_36 = { features?(libc_0_2_36_features {}) }: libc_0_2_36_ { 142 features = mkFeatures (features.libc_0_2_36 or {}); 143 }; 144 libc_0_2_36_features = f: updateFeatures f (rec { 145 libc_0_2_36.default = (f.libc_0_2_36.default or true); 146 libc_0_2_36.use_std = 147 (f.libc_0_2_36.use_std or false) || 148 (f.libc_0_2_36.default or false) || 149 (libc_0_2_36.default or false); 150 }) []; 151} 152``` 153 154Here, the `libc` crate has no `src` attribute, so `buildRustCrate` 155will fetch it from [crates.io](https://crates.io). A `sha256` 156attribute is still needed for Nix purity. 157 158### Handling external dependencies 159 160Some crates require external libraries. For crates from 161[crates.io](https://crates.io), such libraries can be specified in 162`defaultCrateOverrides` package in nixpkgs itself. 163 164Starting from that file, one can add more overrides, to add features 165or build inputs by overriding the hello crate in a seperate file. 166 167``` 168with import <nixpkgs> {}; 169((import ./hello.nix).hello {}).override { 170 crateOverrides = defaultCrateOverrides // { 171 hello = attrs: { buildInputs = [ openssl ]; }; 172 }; 173} 174``` 175 176Here, `crateOverrides` is expected to be a attribute set, where the 177key is the crate name without version number and the value a function. 178The function gets all attributes passed to `buildRustCrate` as first 179argument and returns a set that contains all attribute that should be 180overwritten. 181 182For more complicated cases, such as when parts of the crate's 183derivation depend on the the crate's version, the `attrs` argument of 184the override above can be read, as in the following example, which 185patches the derivation: 186 187``` 188with import <nixpkgs> {}; 189((import ./hello.nix).hello {}).override { 190 crateOverrides = defaultCrateOverrides // { 191 hello = attrs: lib.optionalAttrs (lib.versionAtLeast attrs.version "1.0") { 192 postPatch = '' 193 substituteInPlace lib/zoneinfo.rs \ 194 --replace "/usr/share/zoneinfo" "${tzdata}/share/zoneinfo" 195 ''; 196 }; 197 }; 198} 199``` 200 201Another situation is when we want to override a nested 202dependency. This actually works in the exact same way, since the 203`crateOverrides` parameter is forwarded to the crate's 204dependencies. For instance, to override the build inputs for crate 205`libc` in the example above, where `libc` is a dependency of the main 206crate, we could do: 207 208``` 209with import <nixpkgs> {}; 210((import hello.nix).hello {}).override { 211 crateOverrides = defaultCrateOverrides // { 212 libc = attrs: { buildInputs = []; }; 213 }; 214} 215``` 216 217### Options and phases configuration 218 219Actually, the overrides introduced in the previous section are more 220general. A number of other parameters can be overridden: 221 222- The version of rustc used to compile the crate: 223 224 ``` 225 (hello {}).override { rust = pkgs.rust; }; 226 ``` 227 228- Whether to build in release mode or debug mode (release mode by 229 default): 230 231 ``` 232 (hello {}).override { release = false; }; 233 ``` 234 235- Whether to print the commands sent to rustc when building 236 (equivalent to `--verbose` in cargo: 237 238 ``` 239 (hello {}).override { verbose = false; }; 240 ``` 241 242- Extra arguments to be passed to `rustc`: 243 244 ``` 245 (hello {}).override { extraRustcOpts = "-Z debuginfo=2"; }; 246 ``` 247 248- Phases, just like in any other derivation, can be specified using 249 the following attributes: `preUnpack`, `postUnpack`, `prePatch`, 250 `patches`, `postPatch`, `preConfigure` (in the case of a Rust crate, 251 this is run before calling the "build" script), `postConfigure` 252 (after the "build" script),`preBuild`, `postBuild`, `preInstall` and 253 `postInstall`. As an example, here is how to create a new module 254 before running the build script: 255 256 ``` 257 (hello {}).override { 258 preConfigure = '' 259 echo "pub const PATH=\"${hi.out}\";" >> src/path.rs" 260 ''; 261 }; 262 ``` 263 264### Features 265 266One can also supply features switches. For example, if we want to 267compile `diesel_cli` only with the `postgres` feature, and no default 268features, we would write: 269 270``` 271(callPackage ./diesel.nix {}).diesel { 272 default = false; 273 postgres = true; 274} 275``` 276 277Where `diesel.nix` is the file generated by Carnix, as explained above. 278 279## Using the Rust nightlies overlay 280 281Mozilla provides an overlay for nixpkgs to bring a nightly version of Rust into scope. 282This overlay can _also_ be used to install recent unstable or stable versions 283of Rust, if desired. 284 285To use this overlay, clone 286[nixpkgs-mozilla](https://github.com/mozilla/nixpkgs-mozilla), 287and create a symbolic link to the file 288[rust-overlay.nix](https://github.com/mozilla/nixpkgs-mozilla/blob/master/rust-overlay.nix) 289in the `~/.config/nixpkgs/overlays` directory. 290 291 $ git clone https://github.com/mozilla/nixpkgs-mozilla.git 292 $ mkdir -p ~/.config/nixpkgs/overlays 293 $ ln -s $(pwd)/nixpkgs-mozilla/rust-overlay.nix ~/.config/nixpkgs/overlays/rust-overlay.nix 294 295The latest version can be installed with the following command: 296 297 $ nix-env -Ai nixos.latest.rustChannels.stable.rust 298 299Or using the attribute with nix-shell: 300 301 $ nix-shell -p nixos.latest.rustChannels.stable.rust 302 303To install the beta or nightly channel, "stable" should be substituted by 304"nightly" or "beta", or 305use the function provided by this overlay to pull a version based on a 306build date. 307 308The overlay automatically updates itself as it uses the same source as 309[rustup](https://www.rustup.rs/).