-
Notifications
You must be signed in to change notification settings - Fork 314
/
rust.nix
171 lines (150 loc) · 5.91 KB
/
rust.nix
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
{ pkgs, config, lib, ... }:
let
cfg = config.languages.rust;
fenix = config.lib.getInput {
name = "fenix";
url = "github:nix-community/fenix";
attribute = "languages.rust.version";
follows = [ "nixpkgs" ];
};
in
{
imports = [
(lib.mkRenamedOptionModule [ "languages" "rust" "version" ] [ "languages" "rust" "channel" ])
(lib.mkRenamedOptionModule [ "languages" "rust" "packages" ] [ "languages" "rust" "toolchain" ])
];
options.languages.rust = {
enable = lib.mkEnableOption "tools for Rust development";
components = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ "rustc" "cargo" "clippy" "rustfmt" "rust-analyzer" ];
defaultText = lib.literalExpression ''[ "rustc" "cargo" "clippy" "rustfmt" "rust-analyzer" ]'';
description = ''
List of [Rustup components](https://rust-lang.github.io/rustup/concepts/components.html)
to install. Defaults to those available in `nixpkgs`.
'';
};
targets = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
defaultText = lib.literalExpression ''[ ]'';
description = ''
List of extra [targets](https://github.com/nix-community/fenix#supported-platforms-and-targets)
to install. Defaults to only the native target.
'';
};
channel = lib.mkOption {
type = lib.types.enum [ "nixpkgs" "stable" "beta" "nightly" ];
default = "nixpkgs";
defaultText = lib.literalExpression ''"nixpkgs"'';
description = "The rustup toolchain to install.";
};
rustflags = lib.mkOption {
type = lib.types.str;
default = "";
description = "Extra flags to pass to the Rust compiler.";
};
mold.enable = lib.mkOption {
type = lib.types.bool;
default = pkgs.stdenv.isLinux && pkgs.stdenv.isx86_64 && cfg.targets == [ ];
description = "Enable mold as the linker.";
};
toolchain = lib.mkOption {
type = lib.types.submodule ({
freeformType = lib.types.attrsOf lib.types.package;
options =
let
documented-components = [ "rustc" "cargo" "clippy" "rustfmt" "rust-analyzer" ];
mkComponentOption = component: lib.mkOption {
type = lib.types.nullOr lib.types.package;
default = pkgs.${component};
defaultText = lib.literalExpression "pkgs.${component}";
description = "${component} package";
};
in
lib.genAttrs documented-components mkComponentOption;
});
default = { };
defaultText = lib.literalExpression "nixpkgs";
description = "Rust component packages. May optionally define additional components, for example `miri`.";
};
};
config = lib.mkIf cfg.enable (lib.mkMerge [
(
let
mkOverrideTools = lib.mkOverride (lib.modules.defaultOverridePriority - 1);
in
{
assertions = [
{
assertion = cfg.channel == "nixpkgs" -> (cfg.targets == [ ]);
message = ''
Cannot use `languages.rust.channel = "nixpkgs"` with `languages.rust.targets`.
The nixpkgs channel does not support cross-compiling with targets.
Use the stable, beta, or nightly channels instead. For example:
languages.rust.channel = "stable";
'';
}
];
# Set $CARGO_INSTALL_ROOT so that executables installed by `cargo install` can be found from $PATH
enterShell = ''
export CARGO_INSTALL_ROOT=$(${
lib.strings.escapeShellArgs [
"${pkgs.coreutils}/bin/realpath"
"--no-symlinks"
"${config.devenv.state}/cargo-install"
]
})
export PATH="$PATH:$CARGO_INSTALL_ROOT/bin"
'';
packages =
lib.optional cfg.mold.enable pkgs.mold-wrapped
++ lib.optional pkgs.stdenv.isDarwin pkgs.libiconv;
# enable compiler tooling by default to expose things like cc
languages.c.enable = lib.mkDefault true;
env =
let
darwinFlags = lib.optionalString pkgs.stdenv.isDarwin "-L framework=${config.devenv.profile}/Library/Frameworks";
moldFlags = lib.optionalString cfg.mold.enable "-C link-arg=-fuse-ld=mold";
in
{
# RUST_SRC_PATH is necessary when rust-src is not at the same location as
# as rustc. This is the case with the rust toolchain from nixpkgs.
RUST_SRC_PATH =
if cfg.toolchain ? rust-src
then "${cfg.toolchain.rust-src}/lib/rustlib/src/rust/library"
else pkgs.rustPlatform.rustLibSrc;
RUSTFLAGS = "${darwinFlags} ${moldFlags} ${cfg.rustflags}";
RUSTDOCFLAGS = "${darwinFlags} ${moldFlags}";
CFLAGS = lib.optionalString pkgs.stdenv.isDarwin "-iframework ${config.devenv.profile}/Library/Frameworks";
};
pre-commit.tools.cargo = mkOverrideTools cfg.toolchain.cargo or null;
pre-commit.tools.rustfmt = mkOverrideTools cfg.toolchain.rustfmt or null;
pre-commit.tools.clippy = mkOverrideTools cfg.toolchain.clippy or null;
}
)
(lib.mkIf (cfg.channel == "nixpkgs") {
packages = builtins.map (c: cfg.toolchain.${c} or (throw "toolchain.${c}")) cfg.components;
})
(lib.mkIf (cfg.channel != "nixpkgs") (
let
rustPackages = fenix.packages.${pkgs.stdenv.system};
fenixChannel =
if cfg.channel == "nightly"
then "latest"
else cfg.channel;
toolchain = rustPackages.${fenixChannel};
in
{
languages.rust.toolchain =
(builtins.mapAttrs (_: pkgs.lib.mkDefault) toolchain);
packages = [
(rustPackages.combine (
(map (c: toolchain.${c}) cfg.components) ++
(map (t: rustPackages.targets.${t}.${fenixChannel}.rust-std) cfg.targets)
))
];
}
))
]);
}