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