]>
Commit | Line | Data |
---|---|---|
dc9dc135 | 1 | //! Implementation of compiling the compiler and standard library, in "check"-based modes. |
54a0048b | 2 | |
dfeec247 | 3 | use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step}; |
29967ef6 XL |
4 | use crate::cache::Interned; |
5 | use crate::compile::{add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo}; | |
3dfed10e | 6 | use crate::config::TargetSelection; |
0731742a | 7 | use crate::tool::{prepare_tool_cargo, SourceType}; |
29967ef6 XL |
8 | use crate::INTERNER; |
9 | use crate::{Compiler, Mode, Subcommand}; | |
2c00a5a8 | 10 | use std::path::PathBuf; |
7cac9316 | 11 | |
3b2f2976 | 12 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
2c00a5a8 | 13 | pub struct Std { |
3dfed10e | 14 | pub target: TargetSelection, |
3b2f2976 XL |
15 | } |
16 | ||
29967ef6 XL |
17 | /// Returns args for the subcommand itself (not for cargo) |
18 | fn args(builder: &Builder<'_>) -> Vec<String> { | |
19 | fn strings<'a>(arr: &'a [&str]) -> impl Iterator<Item = String> + 'a { | |
20 | arr.iter().copied().map(String::from) | |
21 | } | |
22 | ||
23 | if let Subcommand::Clippy { fix, .. } = builder.config.cmd { | |
5869c6ff XL |
24 | // disable the most spammy clippy lints |
25 | let ignored_lints = vec![ | |
26 | "many_single_char_names", // there are a lot in stdarch | |
27 | "collapsible_if", | |
28 | "type_complexity", | |
29 | "missing_safety_doc", // almost 3K warnings | |
30 | "too_many_arguments", | |
31 | "needless_lifetimes", // people want to keep the lifetimes | |
32 | "wrong_self_convention", | |
33 | ]; | |
29967ef6 XL |
34 | let mut args = vec![]; |
35 | if fix { | |
36 | #[rustfmt::skip] | |
37 | args.extend(strings(&[ | |
38 | "--fix", "-Zunstable-options", | |
39 | // FIXME: currently, `--fix` gives an error while checking tests for libtest, | |
40 | // possibly because libtest is not yet built in the sysroot. | |
41 | // As a workaround, avoid checking tests and benches when passed --fix. | |
42 | "--lib", "--bins", "--examples", | |
43 | ])); | |
44 | } | |
45 | args.extend(strings(&["--", "--cap-lints", "warn"])); | |
5869c6ff | 46 | args.extend(ignored_lints.iter().map(|lint| format!("-Aclippy::{}", lint))); |
29967ef6 XL |
47 | args |
48 | } else { | |
49 | vec![] | |
dc9dc135 XL |
50 | } |
51 | } | |
52 | ||
53 | fn cargo_subcommand(kind: Kind) -> &'static str { | |
54 | match kind { | |
55 | Kind::Check => "check", | |
56 | Kind::Clippy => "clippy", | |
57 | Kind::Fix => "fix", | |
dfeec247 | 58 | _ => unreachable!(), |
dc9dc135 XL |
59 | } |
60 | } | |
61 | ||
2c00a5a8 | 62 | impl Step for Std { |
3b2f2976 | 63 | type Output = (); |
3b2f2976 XL |
64 | const DEFAULT: bool = true; |
65 | ||
9fa01778 | 66 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
e1599b0c | 67 | run.all_krates("test") |
a7813a04 XL |
68 | } |
69 | ||
9fa01778 | 70 | fn make_run(run: RunConfig<'_>) { |
dfeec247 | 71 | run.builder.ensure(Std { target: run.target }); |
a7813a04 | 72 | } |
a7813a04 | 73 | |
9fa01778 | 74 | fn run(self, builder: &Builder<'_>) { |
3b2f2976 | 75 | let target = self.target; |
5869c6ff | 76 | let compiler = builder.compiler(builder.top_stage, builder.config.build); |
83c7162d | 77 | |
f035d41b XL |
78 | let mut cargo = builder.cargo( |
79 | compiler, | |
80 | Mode::Std, | |
81 | SourceType::InTree, | |
82 | target, | |
83 | cargo_subcommand(builder.kind), | |
84 | ); | |
f9f354fc | 85 | std_cargo(builder, target, compiler.stage, &mut cargo); |
0531ce1d | 86 | |
5869c6ff XL |
87 | builder.info(&format!( |
88 | "Checking stage{} std artifacts ({} -> {})", | |
89 | builder.top_stage, &compiler.host, target | |
90 | )); | |
dfeec247 XL |
91 | run_cargo( |
92 | builder, | |
93 | cargo, | |
29967ef6 | 94 | args(builder), |
dfeec247 XL |
95 | &libstd_stamp(builder, compiler, target), |
96 | vec![], | |
97 | true, | |
98 | ); | |
0531ce1d | 99 | |
5869c6ff XL |
100 | // We skip populating the sysroot in non-zero stage because that'll lead |
101 | // to rlib/rmeta conflicts if std gets built during this session. | |
102 | if compiler.stage == 0 { | |
103 | let libdir = builder.sysroot_libdir(compiler, target); | |
104 | let hostdir = builder.sysroot_libdir(compiler, compiler.host); | |
105 | add_to_sysroot(&builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target)); | |
106 | } | |
1b1a35ee XL |
107 | |
108 | // Then run cargo again, once we've put the rmeta files for the library | |
109 | // crates into the sysroot. This is needed because e.g., core's tests | |
110 | // depend on `libtest` -- Cargo presumes it will exist, but it doesn't | |
111 | // since we initialize with an empty sysroot. | |
112 | // | |
113 | // Currently only the "libtest" tree of crates does this. | |
114 | ||
29967ef6 XL |
115 | if let Subcommand::Check { all_targets: true, .. } = builder.config.cmd { |
116 | let mut cargo = builder.cargo( | |
117 | compiler, | |
118 | Mode::Std, | |
119 | SourceType::InTree, | |
120 | target, | |
121 | cargo_subcommand(builder.kind), | |
122 | ); | |
123 | std_cargo(builder, target, compiler.stage, &mut cargo); | |
124 | cargo.arg("--all-targets"); | |
125 | ||
126 | // Explicitly pass -p for all dependencies krates -- this will force cargo | |
127 | // to also check the tests/benches/examples for these crates, rather | |
128 | // than just the leaf crate. | |
129 | for krate in builder.in_tree_crates("test", Some(target)) { | |
130 | cargo.arg("-p").arg(krate.name); | |
131 | } | |
1b1a35ee | 132 | |
29967ef6 | 133 | builder.info(&format!( |
5869c6ff XL |
134 | "Checking stage{} std test/bench/example targets ({} -> {})", |
135 | builder.top_stage, &compiler.host, target | |
29967ef6 XL |
136 | )); |
137 | run_cargo( | |
138 | builder, | |
139 | cargo, | |
140 | args(builder), | |
141 | &libstd_test_stamp(builder, compiler, target), | |
142 | vec![], | |
143 | true, | |
144 | ); | |
1b1a35ee | 145 | } |
a7813a04 XL |
146 | } |
147 | } | |
148 | ||
3b2f2976 | 149 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
2c00a5a8 | 150 | pub struct Rustc { |
3dfed10e | 151 | pub target: TargetSelection, |
3b2f2976 XL |
152 | } |
153 | ||
2c00a5a8 | 154 | impl Step for Rustc { |
3b2f2976 | 155 | type Output = (); |
3b2f2976 | 156 | const ONLY_HOSTS: bool = true; |
3b2f2976 | 157 | const DEFAULT: bool = true; |
3b2f2976 | 158 | |
9fa01778 | 159 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
2c00a5a8 | 160 | run.all_krates("rustc-main") |
3b2f2976 XL |
161 | } |
162 | ||
9fa01778 | 163 | fn make_run(run: RunConfig<'_>) { |
dfeec247 | 164 | run.builder.ensure(Rustc { target: run.target }); |
3b2f2976 XL |
165 | } |
166 | ||
9fa01778 | 167 | /// Builds the compiler. |
3b2f2976 | 168 | /// |
2c00a5a8 XL |
169 | /// This will build the compiler for a particular stage of the build using |
170 | /// the `compiler` targeting the `target` architecture. The artifacts | |
171 | /// created will also be linked into the sysroot directory. | |
9fa01778 | 172 | fn run(self, builder: &Builder<'_>) { |
5869c6ff | 173 | let compiler = builder.compiler(builder.top_stage, builder.config.build); |
3b2f2976 | 174 | let target = self.target; |
3b2f2976 | 175 | |
5869c6ff XL |
176 | if compiler.stage != 0 { |
177 | // If we're not in stage 0, then we won't have a std from the beta | |
178 | // compiler around. That means we need to make sure there's one in | |
179 | // the sysroot for the compiler to find. Otherwise, we're going to | |
180 | // fail when building crates that need to generate code (e.g., build | |
181 | // scripts and their dependencies). | |
182 | builder.ensure(crate::compile::Std { target: compiler.host, compiler }); | |
183 | builder.ensure(crate::compile::Std { target, compiler }); | |
184 | } else { | |
185 | builder.ensure(Std { target }); | |
186 | } | |
ff7c6d11 | 187 | |
f035d41b XL |
188 | let mut cargo = builder.cargo( |
189 | compiler, | |
190 | Mode::Rustc, | |
191 | SourceType::InTree, | |
192 | target, | |
193 | cargo_subcommand(builder.kind), | |
194 | ); | |
60c5eb7d | 195 | rustc_cargo(builder, &mut cargo, target); |
29967ef6 XL |
196 | if let Subcommand::Check { all_targets: true, .. } = builder.config.cmd { |
197 | cargo.arg("--all-targets"); | |
198 | } | |
1b1a35ee XL |
199 | |
200 | // Explicitly pass -p for all compiler krates -- this will force cargo | |
201 | // to also check the tests/benches/examples for these crates, rather | |
202 | // than just the leaf crate. | |
29967ef6 | 203 | for krate in builder.in_tree_crates("rustc-main", Some(target)) { |
1b1a35ee XL |
204 | cargo.arg("-p").arg(krate.name); |
205 | } | |
0531ce1d | 206 | |
5869c6ff XL |
207 | builder.info(&format!( |
208 | "Checking stage{} compiler artifacts ({} -> {})", | |
209 | builder.top_stage, &compiler.host, target | |
210 | )); | |
dfeec247 XL |
211 | run_cargo( |
212 | builder, | |
213 | cargo, | |
29967ef6 | 214 | args(builder), |
dfeec247 XL |
215 | &librustc_stamp(builder, compiler, target), |
216 | vec![], | |
217 | true, | |
218 | ); | |
0531ce1d | 219 | |
2c00a5a8 | 220 | let libdir = builder.sysroot_libdir(compiler, target); |
532ac7d7 XL |
221 | let hostdir = builder.sysroot_libdir(compiler, compiler.host); |
222 | add_to_sysroot(&builder, &libdir, &hostdir, &librustc_stamp(builder, compiler, target)); | |
83c7162d XL |
223 | } |
224 | } | |
225 | ||
29967ef6 XL |
226 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
227 | pub struct CodegenBackend { | |
228 | pub target: TargetSelection, | |
229 | pub backend: Interned<String>, | |
230 | } | |
231 | ||
232 | impl Step for CodegenBackend { | |
233 | type Output = (); | |
234 | const ONLY_HOSTS: bool = true; | |
235 | const DEFAULT: bool = true; | |
236 | ||
237 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { | |
238 | run.paths(&["compiler/rustc_codegen_cranelift", "rustc_codegen_cranelift"]) | |
239 | } | |
240 | ||
241 | fn make_run(run: RunConfig<'_>) { | |
242 | for &backend in &[INTERNER.intern_str("cranelift")] { | |
243 | run.builder.ensure(CodegenBackend { target: run.target, backend }); | |
244 | } | |
245 | } | |
246 | ||
247 | fn run(self, builder: &Builder<'_>) { | |
5869c6ff | 248 | let compiler = builder.compiler(builder.top_stage, builder.config.build); |
29967ef6 XL |
249 | let target = self.target; |
250 | let backend = self.backend; | |
251 | ||
252 | builder.ensure(Rustc { target }); | |
253 | ||
254 | let mut cargo = builder.cargo( | |
255 | compiler, | |
256 | Mode::Codegen, | |
257 | SourceType::Submodule, | |
258 | target, | |
259 | cargo_subcommand(builder.kind), | |
260 | ); | |
261 | cargo | |
262 | .arg("--manifest-path") | |
263 | .arg(builder.src.join(format!("compiler/rustc_codegen_{}/Cargo.toml", backend))); | |
264 | rustc_cargo_env(builder, &mut cargo, target); | |
265 | ||
fc512014 | 266 | builder.info(&format!( |
5869c6ff XL |
267 | "Checking stage{} {} artifacts ({} -> {})", |
268 | builder.top_stage, backend, &compiler.host.triple, target.triple | |
fc512014 XL |
269 | )); |
270 | ||
29967ef6 XL |
271 | run_cargo( |
272 | builder, | |
273 | cargo, | |
274 | args(builder), | |
275 | &codegen_backend_stamp(builder, compiler, target, backend), | |
276 | vec![], | |
277 | true, | |
278 | ); | |
279 | } | |
280 | } | |
281 | ||
f9f354fc | 282 | macro_rules! tool_check_step { |
17df50a5 | 283 | ($name:ident, $path:literal, $($alias:literal, )* $source_type:path $(, $default:literal )?) => { |
f9f354fc XL |
284 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
285 | pub struct $name { | |
3dfed10e | 286 | pub target: TargetSelection, |
f9f354fc XL |
287 | } |
288 | ||
289 | impl Step for $name { | |
290 | type Output = (); | |
291 | const ONLY_HOSTS: bool = true; | |
17df50a5 XL |
292 | // don't ever check out-of-tree tools by default, they'll fail when toolstate is broken |
293 | const DEFAULT: bool = matches!($source_type, SourceType::InTree) $( && $default )?; | |
f9f354fc XL |
294 | |
295 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { | |
cdc7bbd5 | 296 | run.paths(&[ $path, $($alias),* ]) |
f9f354fc XL |
297 | } |
298 | ||
299 | fn make_run(run: RunConfig<'_>) { | |
300 | run.builder.ensure($name { target: run.target }); | |
301 | } | |
302 | ||
303 | fn run(self, builder: &Builder<'_>) { | |
5869c6ff | 304 | let compiler = builder.compiler(builder.top_stage, builder.config.build); |
f9f354fc XL |
305 | let target = self.target; |
306 | ||
307 | builder.ensure(Rustc { target }); | |
308 | ||
1b1a35ee | 309 | let mut cargo = prepare_tool_cargo( |
f9f354fc XL |
310 | builder, |
311 | compiler, | |
312 | Mode::ToolRustc, | |
313 | target, | |
314 | cargo_subcommand(builder.kind), | |
315 | $path, | |
f035d41b | 316 | $source_type, |
f9f354fc XL |
317 | &[], |
318 | ); | |
319 | ||
29967ef6 XL |
320 | if let Subcommand::Check { all_targets: true, .. } = builder.config.cmd { |
321 | cargo.arg("--all-targets"); | |
322 | } | |
1b1a35ee | 323 | |
5869c6ff | 324 | // Enable internal lints for clippy and rustdoc |
cdc7bbd5 XL |
325 | // NOTE: this doesn't enable lints for any other tools unless they explicitly add `#![warn(rustc::internal)]` |
326 | // See https://github.com/rust-lang/rust/pull/80573#issuecomment-754010776 | |
327 | cargo.rustflag("-Zunstable-options"); | |
5869c6ff | 328 | |
1b1a35ee | 329 | builder.info(&format!( |
5869c6ff XL |
330 | "Checking stage{} {} artifacts ({} -> {})", |
331 | builder.top_stage, | |
f9f354fc | 332 | stringify!($name).to_lowercase(), |
3dfed10e XL |
333 | &compiler.host.triple, |
334 | target.triple | |
1b1a35ee | 335 | )); |
f9f354fc XL |
336 | run_cargo( |
337 | builder, | |
338 | cargo, | |
29967ef6 | 339 | args(builder), |
f9f354fc XL |
340 | &stamp(builder, compiler, target), |
341 | vec![], | |
342 | true, | |
343 | ); | |
344 | ||
f9f354fc XL |
345 | /// Cargo's output path in a given stage, compiled by a particular |
346 | /// compiler for the specified target. | |
347 | fn stamp( | |
348 | builder: &Builder<'_>, | |
349 | compiler: Compiler, | |
3dfed10e | 350 | target: TargetSelection, |
f9f354fc XL |
351 | ) -> PathBuf { |
352 | builder | |
353 | .cargo_out(compiler, Mode::ToolRustc, target) | |
354 | .join(format!(".{}-check.stamp", stringify!($name).to_lowercase())) | |
355 | } | |
356 | } | |
357 | } | |
358 | }; | |
83c7162d XL |
359 | } |
360 | ||
cdc7bbd5 | 361 | tool_check_step!(Rustdoc, "src/tools/rustdoc", "src/librustdoc", SourceType::InTree); |
17df50a5 | 362 | // Clippy and Rustfmt are hybrids. They are external tools, but use a git subtree instead |
f035d41b XL |
363 | // of a submodule. Since the SourceType only drives the deny-warnings |
364 | // behavior, treat it as in-tree so that any new warnings in clippy will be | |
365 | // rejected. | |
366 | tool_check_step!(Clippy, "src/tools/clippy", SourceType::InTree); | |
17df50a5 XL |
367 | tool_check_step!(Miri, "src/tools/miri", SourceType::Submodule); |
368 | tool_check_step!(Rls, "src/tools/rls", SourceType::Submodule); | |
369 | tool_check_step!(Rustfmt, "src/tools/rustfmt", SourceType::InTree); | |
c30ab7b3 | 370 | |
17df50a5 | 371 | tool_check_step!(Bootstrap, "src/bootstrap", SourceType::InTree, false); |
1b1a35ee | 372 | |
2c00a5a8 XL |
373 | /// Cargo's output path for the standard library in a given stage, compiled |
374 | /// by a particular compiler for the specified target. | |
3dfed10e | 375 | fn libstd_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf { |
94b46f34 | 376 | builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check.stamp") |
3b2f2976 XL |
377 | } |
378 | ||
1b1a35ee XL |
379 | /// Cargo's output path for the standard library in a given stage, compiled |
380 | /// by a particular compiler for the specified target. | |
381 | fn libstd_test_stamp( | |
382 | builder: &Builder<'_>, | |
383 | compiler: Compiler, | |
384 | target: TargetSelection, | |
385 | ) -> PathBuf { | |
386 | builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check-test.stamp") | |
387 | } | |
388 | ||
2c00a5a8 XL |
389 | /// Cargo's output path for librustc in a given stage, compiled by a particular |
390 | /// compiler for the specified target. | |
3dfed10e | 391 | fn librustc_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf { |
94b46f34 | 392 | builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc-check.stamp") |
83c7162d | 393 | } |
29967ef6 XL |
394 | |
395 | /// Cargo's output path for librustc_codegen_llvm in a given stage, compiled by a particular | |
396 | /// compiler for the specified target and backend. | |
397 | fn codegen_backend_stamp( | |
398 | builder: &Builder<'_>, | |
399 | compiler: Compiler, | |
400 | target: TargetSelection, | |
401 | backend: Interned<String>, | |
402 | ) -> PathBuf { | |
403 | builder | |
404 | .cargo_out(compiler, Mode::Codegen, target) | |
405 | .join(format!(".librustc_codegen_{}-check.stamp", backend)) | |
406 | } |