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/).