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