Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
at release-18.03 393 lines 12 kB view raw view rendered
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 19> If you are using NixOS and you want to use rust without a nix expression you 20> probably want to add the following in your `configuration.nix` to build 21> crates with C dependencies. 22> 23> environment.systemPackages = [binutils gcc gnumake openssl pkgconfig] 24 25For daily builds (beta and nightly) use either rustup from 26nixpkgs or use the [Rust nightlies 27overlay](#using-the-rust-nightlies-overlay). 28 29## Compiling Rust applications with Cargo 30 31Rust applications are packaged by using the `buildRustPackage` helper from `rustPlatform`: 32 33``` 34rustPlatform.buildRustPackage rec { 35 name = "ripgrep-${version}"; 36 version = "0.4.0"; 37 38 src = fetchFromGitHub { 39 owner = "BurntSushi"; 40 repo = "ripgrep"; 41 rev = "${version}"; 42 sha256 = "0y5d1n6hkw85jb3rblcxqas2fp82h3nghssa4xqrhqnz25l799pj"; 43 }; 44 45 cargoSha256 = "0q68qyl2h6i0qsz82z840myxlnjay8p1w5z7hfyr8fqp7wgwa9cx"; 46 47 meta = with stdenv.lib; { 48 description = "A fast line-oriented regex search tool, similar to ag and ack"; 49 homepage = https://github.com/BurntSushi/ripgrep; 50 license = licenses.unlicense; 51 maintainers = [ maintainers.tailhook ]; 52 platforms = platforms.all; 53 }; 54} 55``` 56 57`buildRustPackage` requires a `cargoSha256` attribute which is computed over 58all crate sources of this package. Currently it is obtained by inserting a 59fake checksum into the expression and building the package once. The correct 60checksum can be then take from the failed build. 61 62To install crates with nix there is also an experimental project called 63[nixcrates](https://github.com/fractalide/nixcrates). 64 65## Compiling Rust crates using Nix instead of Cargo 66 67### Simple operation 68 69When run, `cargo build` produces a file called `Cargo.lock`, 70containing pinned versions of all dependencies. Nixpkgs contains a 71tool called `carnix` (`nix-env -iA nixos.carnix`), which can be used 72to turn a `Cargo.lock` into a Nix expression. 73 74That Nix expression calls `rustc` directly (hence bypassing Cargo), 75and can be used to compile a crate and all its dependencies. Here is 76an example for a minimal `hello` crate: 77 78 79 $ cargo new hello 80 $ cd hello 81 $ cargo build 82 Compiling hello v0.1.0 (file:///tmp/hello) 83 Finished dev [unoptimized + debuginfo] target(s) in 0.20 secs 84 $ carnix -o hello.nix --src ./. Cargo.lock --standalone 85 $ nix-build hello.nix -A hello_0_1_0 86 87Now, the file produced by the call to `carnix`, called `hello.nix`, looks like: 88 89``` 90# Generated by carnix 0.6.5: carnix -o hello.nix --src ./. Cargo.lock --standalone 91{ lib, buildPlatform, buildRustCrate, fetchgit }: 92let kernel = buildPlatform.parsed.kernel.name; 93 # ... (content skipped) 94in 95rec { 96 hello = f: hello_0_1_0 { features = hello_0_1_0_features { hello_0_1_0 = f; }; }; 97 hello_0_1_0_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate { 98 crateName = "hello"; 99 version = "0.1.0"; 100 authors = [ "pe@pijul.org <pe@pijul.org>" ]; 101 src = ./.; 102 inherit dependencies buildDependencies features; 103 }; 104 hello_0_1_0 = { features?(hello_0_1_0_features {}) }: hello_0_1_0_ {}; 105 hello_0_1_0_features = f: updateFeatures f (rec { 106 hello_0_1_0.default = (f.hello_0_1_0.default or true); 107 }) [ ]; 108} 109``` 110 111In particular, note that the argument given as `--src` is copied 112verbatim to the source. If we look at a more complicated 113dependencies, for instance by adding a single line `libc="*"` to our 114`Cargo.toml`, we first need to run `cargo build` to update the 115`Cargo.lock`. Then, `carnix` needs to be run again, and produces the 116following nix file: 117 118``` 119# Generated by carnix 0.6.5: carnix -o hello.nix --src ./. Cargo.lock --standalone 120{ lib, buildPlatform, buildRustCrate, fetchgit }: 121let kernel = buildPlatform.parsed.kernel.name; 122 # ... (content skipped) 123in 124rec { 125 hello = f: hello_0_1_0 { features = hello_0_1_0_features { hello_0_1_0 = f; }; }; 126 hello_0_1_0_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate { 127 crateName = "hello"; 128 version = "0.1.0"; 129 authors = [ "pe@pijul.org <pe@pijul.org>" ]; 130 src = ./.; 131 inherit dependencies buildDependencies features; 132 }; 133 libc_0_2_36_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate { 134 crateName = "libc"; 135 version = "0.2.36"; 136 authors = [ "The Rust Project Developers" ]; 137 sha256 = "01633h4yfqm0s302fm0dlba469bx8y6cs4nqc8bqrmjqxfxn515l"; 138 inherit dependencies buildDependencies features; 139 }; 140 hello_0_1_0 = { features?(hello_0_1_0_features {}) }: hello_0_1_0_ { 141 dependencies = mapFeatures features ([ libc_0_2_36 ]); 142 }; 143 hello_0_1_0_features = f: updateFeatures f (rec { 144 hello_0_1_0.default = (f.hello_0_1_0.default or true); 145 libc_0_2_36.default = true; 146 }) [ libc_0_2_36_features ]; 147 libc_0_2_36 = { features?(libc_0_2_36_features {}) }: libc_0_2_36_ { 148 features = mkFeatures (features.libc_0_2_36 or {}); 149 }; 150 libc_0_2_36_features = f: updateFeatures f (rec { 151 libc_0_2_36.default = (f.libc_0_2_36.default or true); 152 libc_0_2_36.use_std = 153 (f.libc_0_2_36.use_std or false) || 154 (f.libc_0_2_36.default or false) || 155 (libc_0_2_36.default or false); 156 }) []; 157} 158``` 159 160Here, the `libc` crate has no `src` attribute, so `buildRustCrate` 161will fetch it from [crates.io](https://crates.io). A `sha256` 162attribute is still needed for Nix purity. 163 164### Handling external dependencies 165 166Some crates require external libraries. For crates from 167[crates.io](https://crates.io), such libraries can be specified in 168`defaultCrateOverrides` package in nixpkgs itself. 169 170Starting from that file, one can add more overrides, to add features 171or build inputs by overriding the hello crate in a seperate file. 172 173``` 174with import <nixpkgs> {}; 175((import ./hello.nix).hello {}).override { 176 crateOverrides = defaultCrateOverrides // { 177 hello = attrs: { buildInputs = [ openssl ]; }; 178 }; 179} 180``` 181 182Here, `crateOverrides` is expected to be a attribute set, where the 183key is the crate name without version number and the value a function. 184The function gets all attributes passed to `buildRustCrate` as first 185argument and returns a set that contains all attribute that should be 186overwritten. 187 188For more complicated cases, such as when parts of the crate's 189derivation depend on the the crate's version, the `attrs` argument of 190the override above can be read, as in the following example, which 191patches the derivation: 192 193``` 194with import <nixpkgs> {}; 195((import ./hello.nix).hello {}).override { 196 crateOverrides = defaultCrateOverrides // { 197 hello = attrs: lib.optionalAttrs (lib.versionAtLeast attrs.version "1.0") { 198 postPatch = '' 199 substituteInPlace lib/zoneinfo.rs \ 200 --replace "/usr/share/zoneinfo" "${tzdata}/share/zoneinfo" 201 ''; 202 }; 203 }; 204} 205``` 206 207Another situation is when we want to override a nested 208dependency. This actually works in the exact same way, since the 209`crateOverrides` parameter is forwarded to the crate's 210dependencies. For instance, to override the build inputs for crate 211`libc` in the example above, where `libc` is a dependency of the main 212crate, we could do: 213 214``` 215with import <nixpkgs> {}; 216((import hello.nix).hello {}).override { 217 crateOverrides = defaultCrateOverrides // { 218 libc = attrs: { buildInputs = []; }; 219 }; 220} 221``` 222 223### Options and phases configuration 224 225Actually, the overrides introduced in the previous section are more 226general. A number of other parameters can be overridden: 227 228- The version of rustc used to compile the crate: 229 230 ``` 231 (hello {}).override { rust = pkgs.rust; }; 232 ``` 233 234- Whether to build in release mode or debug mode (release mode by 235 default): 236 237 ``` 238 (hello {}).override { release = false; }; 239 ``` 240 241- Whether to print the commands sent to rustc when building 242 (equivalent to `--verbose` in cargo: 243 244 ``` 245 (hello {}).override { verbose = false; }; 246 ``` 247 248- Extra arguments to be passed to `rustc`: 249 250 ``` 251 (hello {}).override { extraRustcOpts = "-Z debuginfo=2"; }; 252 ``` 253 254- Phases, just like in any other derivation, can be specified using 255 the following attributes: `preUnpack`, `postUnpack`, `prePatch`, 256 `patches`, `postPatch`, `preConfigure` (in the case of a Rust crate, 257 this is run before calling the "build" script), `postConfigure` 258 (after the "build" script),`preBuild`, `postBuild`, `preInstall` and 259 `postInstall`. As an example, here is how to create a new module 260 before running the build script: 261 262 ``` 263 (hello {}).override { 264 preConfigure = '' 265 echo "pub const PATH=\"${hi.out}\";" >> src/path.rs" 266 ''; 267 }; 268 ``` 269 270### Features 271 272One can also supply features switches. For example, if we want to 273compile `diesel_cli` only with the `postgres` feature, and no default 274features, we would write: 275 276``` 277(callPackage ./diesel.nix {}).diesel { 278 default = false; 279 postgres = true; 280} 281``` 282 283Where `diesel.nix` is the file generated by Carnix, as explained above. 284 285 286## Setting Up `nix-shell` 287Oftentimes you want to develop code from within `nix-shell`. Unfortunately 288`buildRustCrate` does not support common `nix-shell` operations directly 289(see [this issue](https://github.com/NixOS/nixpkgs/issues/37945)) 290so we will use `stdenv.mkDerivation` instead. 291 292Using the example `hello` project above, we want to do the following: 293- Have access to `cargo` and `rustc` 294- Have the `openssl` library available to a crate through it's _normal_ 295 compilation mechanism (`pkg-config`). 296 297A typical `shell.nix` might look like: 298 299``` 300with import <nixpkgs> {}; 301 302stdenv.mkDerivation { 303 name = "rust-env"; 304 buildInputs = [ 305 rustc cargo 306 307 # Example Additional Dependencies 308 pkgconfig openssl 309 ]; 310 311 # Set Environment Variables 312 RUST_BACKTRACE = 1; 313} 314``` 315 316You should now be able to run the following: 317``` 318$ nix-shell --pure 319$ cargo build 320$ cargo test 321``` 322 323### Controlling Rust Version Inside `nix-shell` 324To control your rust version (i.e. use nightly) from within `shell.nix` (or 325other nix expressions) you can use the following `shell.nix` 326 327``` 328# Latest Nightly 329with import <nixpkgs> {}; 330let src = fetchFromGitHub { 331 owner = "mozilla"; 332 repo = "nixpkgs-mozilla"; 333 # commit from: 2018-03-27 334 rev = "2945b0b6b2fd19e7d23bac695afd65e320efcebe"; 335 sha256 = "034m1dryrzh2lmjvk3c0krgip652dql46w5yfwpvh7gavd3iypyw"; 336 }; 337in 338with import "${src.out}/rust-overlay.nix" pkgs pkgs; 339stdenv.mkDerivation { 340 name = "rust-env"; 341 buildInputs = [ 342 # Note: to use use stable, just replace `nightly` with `stable` 343 latest.rustChannels.nightly.rust 344 345 # Add some extra dependencies from `pkgs` 346 pkgconfig openssl 347 ]; 348 349 # Set Environment Variables 350 RUST_BACKTRACE = 1; 351} 352``` 353 354Now run: 355``` 356$ rustc --version 357rustc 1.26.0-nightly (188e693b3 2018-03-26) 358``` 359 360To see that you are using nightly. 361 362 363## Using the Rust nightlies overlay 364 365Mozilla provides an overlay for nixpkgs to bring a nightly version of Rust into scope. 366This overlay can _also_ be used to install recent unstable or stable versions 367of Rust, if desired. 368 369To use this overlay, clone 370[nixpkgs-mozilla](https://github.com/mozilla/nixpkgs-mozilla), 371and create a symbolic link to the file 372[rust-overlay.nix](https://github.com/mozilla/nixpkgs-mozilla/blob/master/rust-overlay.nix) 373in the `~/.config/nixpkgs/overlays` directory. 374 375 $ git clone https://github.com/mozilla/nixpkgs-mozilla.git 376 $ mkdir -p ~/.config/nixpkgs/overlays 377 $ ln -s $(pwd)/nixpkgs-mozilla/rust-overlay.nix ~/.config/nixpkgs/overlays/rust-overlay.nix 378 379The latest version can be installed with the following command: 380 381 $ nix-env -Ai nixos.latest.rustChannels.stable.rust 382 383Or using the attribute with nix-shell: 384 385 $ nix-shell -p nixos.latest.rustChannels.stable.rust 386 387To install the beta or nightly channel, "stable" should be substituted by 388"nightly" or "beta", or 389use the function provided by this overlay to pull a version based on a 390build date. 391 392The overlay automatically updates itself as it uses the same source as 393[rustup](https://www.rustup.rs/).