-
-
Notifications
You must be signed in to change notification settings - Fork 14.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Reintroducing mkRustCrate #31150
Reintroducing mkRustCrate #31150
Changes from 41 commits
a20704c
7979239
2d85124
00e93d5
4b5aa82
08046ce
6088db3
235a48e
6846126
1917e32
655f44a
cf4ec94
a694f61
d0a68ff
ca81cad
b4c5585
4ce91ee
1f338c1
4121d59
428f66a
01645cf
2d2490a
0387786
6ffd5b4
7b212b8
f7bed04
95ed173
099e713
68b7867
50b984f
993d376
a99ef12
7e6e3b5
c82be14
ea0cf4b
4c788cc
240fc52
0e8ef4b
5555123
457f9f5
c21a241
59d16ef
7d7fe21
fc84be3
1cd1fca
cd0f359
bf70097
f84ad34
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,7 +19,7 @@ For daily builds (beta and nightly) use either rustup from | |
nixpkgs or use the [Rust nightlies | ||
overlay](#using-the-rust-nightlies-overlay). | ||
|
||
## Packaging Rust applications | ||
## Compiling Rust applications with Cargo | ||
|
||
Rust applications are packaged by using the `buildRustPackage` helper from `rustPlatform`: | ||
|
||
|
@@ -57,6 +57,173 @@ checksum can be then take from the failed build. | |
To install crates with nix there is also an experimental project called | ||
[nixcrates](https://github.com/fractalide/nixcrates). | ||
|
||
## Compiling Rust crates using Nix instead of Cargo | ||
|
||
When run, `cargo build` produces a file called `Cargo.lock`, | ||
containing pinned versions of all dependencies. Nixpkgs contains a | ||
tool called `carnix` (`nix-env -iA nixos.carnix`), which can be used | ||
to turn a `Cargo.lock` into a Nix expression. | ||
|
||
That Nix expression calls `rustc` directly (hence bypassing Cargo), | ||
and can be used to compile a crate and all its dependencies. Here is | ||
an example for a minimal `hello` crate: | ||
|
||
|
||
$ cargo new hello | ||
$ cd hello | ||
$ cargo build | ||
Compiling hello v0.1.0 (file:///tmp/hello) | ||
Finished dev [unoptimized + debuginfo] target(s) in 0.20 secs | ||
$ carnix -o hello.nix --src ./. Cargo.lock --standalone | ||
$ nix-build hello.nix | ||
|
||
Now, the file produced by the call to `carnix`, called `hello.nix`, looks like: | ||
|
||
``` | ||
with import <nixpkgs> {}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a reminder to update all |
||
let release = true; | ||
verbose = true; | ||
hello_0_1_0_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate { | ||
crateName = "hello"; | ||
version = "0.1.0"; | ||
src = ./.; | ||
inherit dependencies buildDependencies features release verbose; | ||
}; | ||
|
||
in | ||
rec { | ||
hello_0_1_0 = hello_0_1_0_ {}; | ||
} | ||
``` | ||
|
||
In particular, note that the argument given as `--src` is copied | ||
verbatim to the source. If we look at a more complicated | ||
dependencies, for instance by adding a single line `libc="*"` to our | ||
`Cargo.toml`, we first need to run `cargo build` to update the | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it be better to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no, this might update dependencies, which should not be updated. |
||
`Cargo.lock`. Then, `carnix` needs to be run again, and produces the | ||
following nix file: | ||
|
||
``` | ||
with import <nixpkgs> {}; | ||
let release = true; | ||
verbose = true; | ||
hello_0_1_0_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate { | ||
crateName = "hello"; | ||
version = "0.1.0"; | ||
src = ./.; | ||
inherit dependencies buildDependencies features release verbose; | ||
}; | ||
libc_0_2_33_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate { | ||
crateName = "libc"; | ||
version = "0.2.33"; | ||
sha256 = "1l7synziccnvarsq2kk22vps720ih6chmn016bhr2bq54hblbnl1"; | ||
inherit dependencies buildDependencies features release verbose; | ||
}; | ||
|
||
in | ||
rec { | ||
hello_0_1_0 = hello_0_1_0_ { | ||
dependencies = [ libc_0_2_33 ]; | ||
}; | ||
libc_0_2_33 = libc_0_2_33_ { | ||
features = [ "use_std" ]; | ||
}; | ||
} | ||
``` | ||
|
||
Here, the `libc` crate has no `src` attribute, so `buildRustCrate` | ||
will fetch it from [crates.io](https://crates.io). A `sha256` | ||
attribute is still needed for Nix purity. | ||
|
||
Some crates require external libraries. For crates from | ||
[crates.io](https://crates.io), such libraries can be specified in | ||
`<nixpkgs/pkgs/build-support/rust/defaultCrateOverrides.nix>`. | ||
|
||
Starting from that file, one can add more overrides, to add features | ||
or build inputs, as follows: | ||
|
||
``` | ||
with import <nixpkgs> {}; | ||
let kernel = buildPlatform.parsed.kernel.name; | ||
abi = buildPlatform.parsed.abi.name; | ||
helo_0_1_0_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate { | ||
crateName = "helo"; | ||
version = "0.1.0"; | ||
authors = [ "pe@pijul.org <pe@pijul.org>" ]; | ||
src = ./.; | ||
inherit dependencies buildDependencies features; | ||
}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This example might also help people:
|
||
in | ||
rec { | ||
helo_0_1_0 = (helo_0_1_0_ {}).override { | ||
crateOverrides = defaultCrateOverrides // { | ||
helo = attrs: { buildInputs = [ openssl ]; }; | ||
}; | ||
}; | ||
} | ||
``` | ||
|
||
Here, `crateOverrides` is expected to be a attribute set, where the | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: "an attribute set" |
||
key is the crate name without version number and the value a function. | ||
The function gets all attributes passed to `buildRustCrate` as first | ||
argument and returns a set that contains all attribute that should be | ||
overwritten. | ||
|
||
For more complicated cases, such as when parts of the crate's | ||
derivation depend on the the crate's version, the `attrs` argument of | ||
the override above can be read, as in the following example, which | ||
patches the derivation: | ||
|
||
``` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would some more information about `crateOverrides` is expected to be a attribute set,
where the key is the crate name without version number and the value a function.
The function gets all attributes passed to `buildRustCrate` as first argument
and returns a set that contains all attribute that should be overwritten. |
||
with import <nixpkgs> {}; | ||
let kernel = buildPlatform.parsed.kernel.name; | ||
abi = buildPlatform.parsed.abi.name; | ||
helo_0_1_0_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate { | ||
crateName = "helo"; | ||
version = "0.1.0"; | ||
authors = [ "pe@pijul.org <pe@pijul.org>" ]; | ||
src = ./.; | ||
inherit dependencies buildDependencies features; | ||
}; | ||
in | ||
rec { | ||
helo_0_1_0 = (helo_0_1_0_ {}).override { | ||
crateOverrides = defaultCrateOverrides // { | ||
helo = attrs: lib.optionalAttrs (lib.versionAtLeast attrs.version "1.0") { | ||
postPatch = '' | ||
substituteInPlace lib/zoneinfo.rs \ | ||
--replace "/usr/share/zoneinfo" "${tzdata}/share/zoneinfo" | ||
''; | ||
}; | ||
}; | ||
}; | ||
} | ||
``` | ||
|
||
|
||
Three more parameters can be overridden: | ||
|
||
- The version of rustc used to compile the crate: | ||
|
||
``` | ||
hello_0_1_0.override { rust = pkgs.rust; }; | ||
``` | ||
|
||
- Whether to build in release mode or debug mode (release mode by | ||
default): | ||
|
||
``` | ||
hello_0_1_0.override { release = false; }; | ||
``` | ||
|
||
- Whether to print the commands sent to rustc when building | ||
(equivalent to `--verbose` in cargo: | ||
|
||
``` | ||
hello_0_1_0.override { verbose = false; }; | ||
``` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where should users go to find the full collection of attrs that can be passed? |
||
|
||
|
||
## Using the Rust nightlies overlay | ||
|
||
Mozilla provides an overlay for nixpkgs to bring a nightly version of Rust into scope. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nix-build hello.nix
no longer works, since carnix replaced thewith import <nixpkgs>{};
preamble.Also, this command would build all crates in
hello.nix
which might lead to errors if, for example, a crate like redox_syscall is pulled in as a conditional dependency of the time crate for the Redox-OS platform when building on Linux or any platform that is not Redox-OS.i.e.
I would recommend an example that kicks off the build by specifying the "root" Rust project only.
e.g.
I think that example expression will work. Corrections and improvements welcome. :/
Anyway, it'll be subject to change if @Mic92's recommendation to replace
{pkgs}
to improve composability is applied.