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