forked from mirrors/nixpkgs
Revert "carnix,cratesIO: remove" in doc/languages-frameworks/rust.section.md
This reverts the part of commit
82fe76d1cd
that affected
doc/languages-frameworks/rust.section.md
This commit is contained in:
parent
3e09d895a9
commit
efbbdc16e6
|
@ -642,6 +642,227 @@ buildPythonPackage rec {
|
|||
}
|
||||
```
|
||||
|
||||
## `buildRustCrate`: Compiling Rust crates using Nix instead of Cargo {#compiling-rust-crates-using-nix-instead-of-cargo}
|
||||
|
||||
### Simple operation {#simple-operation}
|
||||
|
||||
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:
|
||||
|
||||
```ShellSession
|
||||
$ 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 -A hello_0_1_0
|
||||
```
|
||||
|
||||
Now, the file produced by the call to `carnix`, called `hello.nix`, looks like:
|
||||
|
||||
```nix
|
||||
# Generated by carnix 0.6.5: carnix -o hello.nix --src ./. Cargo.lock --standalone
|
||||
{ stdenv, buildRustCrate, fetchgit }:
|
||||
let kernel = stdenv.buildPlatform.parsed.kernel.name;
|
||||
# ... (content skipped)
|
||||
in
|
||||
rec {
|
||||
hello = f: hello_0_1_0 { features = hello_0_1_0_features { hello_0_1_0 = f; }; };
|
||||
hello_0_1_0_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate {
|
||||
crateName = "hello";
|
||||
version = "0.1.0";
|
||||
authors = [ "pe@pijul.org <pe@pijul.org>" ];
|
||||
src = ./.;
|
||||
inherit dependencies buildDependencies features;
|
||||
};
|
||||
hello_0_1_0 = { features?(hello_0_1_0_features {}) }: hello_0_1_0_ {};
|
||||
hello_0_1_0_features = f: updateFeatures f (rec {
|
||||
hello_0_1_0.default = (f.hello_0_1_0.default or true);
|
||||
}) [ ];
|
||||
}
|
||||
```
|
||||
|
||||
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
|
||||
`Cargo.lock`. Then, `carnix` needs to be run again, and produces the
|
||||
following nix file:
|
||||
|
||||
```nix
|
||||
# Generated by carnix 0.6.5: carnix -o hello.nix --src ./. Cargo.lock --standalone
|
||||
{ stdenv, buildRustCrate, fetchgit }:
|
||||
let kernel = stdenv.buildPlatform.parsed.kernel.name;
|
||||
# ... (content skipped)
|
||||
in
|
||||
rec {
|
||||
hello = f: hello_0_1_0 { features = hello_0_1_0_features { hello_0_1_0 = f; }; };
|
||||
hello_0_1_0_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate {
|
||||
crateName = "hello";
|
||||
version = "0.1.0";
|
||||
authors = [ "pe@pijul.org <pe@pijul.org>" ];
|
||||
src = ./.;
|
||||
inherit dependencies buildDependencies features;
|
||||
};
|
||||
libc_0_2_36_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate {
|
||||
crateName = "libc";
|
||||
version = "0.2.36";
|
||||
authors = [ "The Rust Project Developers" ];
|
||||
sha256 = "01633h4yfqm0s302fm0dlba469bx8y6cs4nqc8bqrmjqxfxn515l";
|
||||
inherit dependencies buildDependencies features;
|
||||
};
|
||||
hello_0_1_0 = { features?(hello_0_1_0_features {}) }: hello_0_1_0_ {
|
||||
dependencies = mapFeatures features ([ libc_0_2_36 ]);
|
||||
};
|
||||
hello_0_1_0_features = f: updateFeatures f (rec {
|
||||
hello_0_1_0.default = (f.hello_0_1_0.default or true);
|
||||
libc_0_2_36.default = true;
|
||||
}) [ libc_0_2_36_features ];
|
||||
libc_0_2_36 = { features?(libc_0_2_36_features {}) }: libc_0_2_36_ {
|
||||
features = mkFeatures (features.libc_0_2_36 or {});
|
||||
};
|
||||
libc_0_2_36_features = f: updateFeatures f (rec {
|
||||
libc_0_2_36.default = (f.libc_0_2_36.default or true);
|
||||
libc_0_2_36.use_std =
|
||||
(f.libc_0_2_36.use_std or false) ||
|
||||
(f.libc_0_2_36.default or false) ||
|
||||
(libc_0_2_36.default or false);
|
||||
}) [];
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
### Handling external dependencies {#handling-external-dependencies}
|
||||
|
||||
Some crates require external libraries. For crates from
|
||||
[crates.io](https://crates.io), such libraries can be specified in
|
||||
`defaultCrateOverrides` package in nixpkgs itself.
|
||||
|
||||
Starting from that file, one can add more overrides, to add features
|
||||
or build inputs by overriding the hello crate in a separate file.
|
||||
|
||||
```nix
|
||||
with import <nixpkgs> {};
|
||||
((import ./hello.nix).hello {}).override {
|
||||
crateOverrides = defaultCrateOverrides // {
|
||||
hello = attrs: { buildInputs = [ openssl ]; };
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Here, `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.
|
||||
|
||||
For more complicated cases, such as when parts of the crate's
|
||||
derivation depend on the crate's version, the `attrs` argument of
|
||||
the override above can be read, as in the following example, which
|
||||
patches the derivation:
|
||||
|
||||
```nix
|
||||
with import <nixpkgs> {};
|
||||
((import ./hello.nix).hello {}).override {
|
||||
crateOverrides = defaultCrateOverrides // {
|
||||
hello = attrs: lib.optionalAttrs (lib.versionAtLeast attrs.version "1.0") {
|
||||
postPatch = ''
|
||||
substituteInPlace lib/zoneinfo.rs \
|
||||
--replace "/usr/share/zoneinfo" "${tzdata}/share/zoneinfo"
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Another situation is when we want to override a nested
|
||||
dependency. This actually works in the exact same way, since the
|
||||
`crateOverrides` parameter is forwarded to the crate's
|
||||
dependencies. For instance, to override the build inputs for crate
|
||||
`libc` in the example above, where `libc` is a dependency of the main
|
||||
crate, we could do:
|
||||
|
||||
```nix
|
||||
with import <nixpkgs> {};
|
||||
((import hello.nix).hello {}).override {
|
||||
crateOverrides = defaultCrateOverrides // {
|
||||
libc = attrs: { buildInputs = []; };
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Options and phases configuration {#options-and-phases-configuration}
|
||||
|
||||
Actually, the overrides introduced in the previous section are more
|
||||
general. A number of other parameters can be overridden:
|
||||
|
||||
- The version of `rustc` used to compile the crate:
|
||||
|
||||
```nix
|
||||
(hello {}).override { rust = pkgs.rust; };
|
||||
```
|
||||
|
||||
- Whether to build in release mode or debug mode (release mode by
|
||||
default):
|
||||
|
||||
```nix
|
||||
(hello {}).override { release = false; };
|
||||
```
|
||||
|
||||
- Whether to print the commands sent to `rustc` when building
|
||||
(equivalent to `--verbose` in cargo:
|
||||
|
||||
```nix
|
||||
(hello {}).override { verbose = false; };
|
||||
```
|
||||
|
||||
- Extra arguments to be passed to `rustc`:
|
||||
|
||||
```nix
|
||||
(hello {}).override { extraRustcOpts = "-Z debuginfo=2"; };
|
||||
```
|
||||
|
||||
- Phases, just like in any other derivation, can be specified using
|
||||
the following attributes: `preUnpack`, `postUnpack`, `prePatch`,
|
||||
`patches`, `postPatch`, `preConfigure` (in the case of a Rust crate,
|
||||
this is run before calling the "build" script), `postConfigure`
|
||||
(after the "build" script),`preBuild`, `postBuild`, `preInstall` and
|
||||
`postInstall`. As an example, here is how to create a new module
|
||||
before running the build script:
|
||||
|
||||
```nix
|
||||
(hello {}).override {
|
||||
preConfigure = ''
|
||||
echo "pub const PATH=\"${hi.out}\";" >> src/path.rs"
|
||||
'';
|
||||
};
|
||||
```
|
||||
|
||||
### Features {#features}
|
||||
|
||||
One can also supply features switches. For example, if we want to
|
||||
compile `diesel_cli` only with the `postgres` feature, and no default
|
||||
features, we would write:
|
||||
|
||||
```nix
|
||||
(callPackage ./diesel.nix {}).diesel {
|
||||
default = false;
|
||||
postgres = true;
|
||||
}
|
||||
```
|
||||
|
||||
Where `diesel.nix` is the file generated by Carnix, as explained above.
|
||||
|
||||
## Setting Up `nix-shell` {#setting-up-nix-shell}
|
||||
|
||||
Oftentimes you want to develop code from within `nix-shell`. Unfortunately
|
||||
|
|
Loading…
Reference in a new issue