]> git.lizzy.rs Git - rust.git/blob - src/bootstrap/check.rs
Rollup merge of #107740 - oli-obk:lock_tcx, r=petrochenkov
[rust.git] / src / bootstrap / check.rs
1 //! Implementation of compiling the compiler and standard library, in "check"-based modes.
2
3 use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
4 use crate::cache::Interned;
5 use crate::compile::{add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo};
6 use crate::config::TargetSelection;
7 use crate::tool::{prepare_tool_cargo, SourceType};
8 use crate::INTERNER;
9 use crate::{Compiler, Mode, Subcommand};
10 use std::path::{Path, PathBuf};
11
12 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
13 pub struct Std {
14     pub target: TargetSelection,
15 }
16
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 {
24         fix,
25         clippy_lint_allow,
26         clippy_lint_deny,
27         clippy_lint_warn,
28         clippy_lint_forbid,
29         ..
30     } = &builder.config.cmd
31     {
32         // disable the most spammy clippy lints
33         let ignored_lints = vec![
34             "many_single_char_names", // there are a lot in stdarch
35             "collapsible_if",
36             "type_complexity",
37             "missing_safety_doc", // almost 3K warnings
38             "too_many_arguments",
39             "needless_lifetimes", // people want to keep the lifetimes
40             "wrong_self_convention",
41         ];
42         let mut args = vec![];
43         if *fix {
44             #[rustfmt::skip]
45             args.extend(strings(&[
46                 "--fix", "-Zunstable-options",
47                 // FIXME: currently, `--fix` gives an error while checking tests for libtest,
48                 // possibly because libtest is not yet built in the sysroot.
49                 // As a workaround, avoid checking tests and benches when passed --fix.
50                 "--lib", "--bins", "--examples",
51             ]));
52         }
53         args.extend(strings(&["--", "--cap-lints", "warn"]));
54         args.extend(ignored_lints.iter().map(|lint| format!("-Aclippy::{}", lint)));
55         let mut clippy_lint_levels: Vec<String> = Vec::new();
56         clippy_lint_allow.iter().for_each(|v| clippy_lint_levels.push(format!("-A{}", v)));
57         clippy_lint_deny.iter().for_each(|v| clippy_lint_levels.push(format!("-D{}", v)));
58         clippy_lint_warn.iter().for_each(|v| clippy_lint_levels.push(format!("-W{}", v)));
59         clippy_lint_forbid.iter().for_each(|v| clippy_lint_levels.push(format!("-F{}", v)));
60         args.extend(clippy_lint_levels);
61         args
62     } else {
63         vec![]
64     }
65 }
66
67 fn cargo_subcommand(kind: Kind) -> &'static str {
68     match kind {
69         Kind::Check => "check",
70         Kind::Clippy => "clippy",
71         Kind::Fix => "fix",
72         _ => unreachable!(),
73     }
74 }
75
76 impl Step for Std {
77     type Output = ();
78     const DEFAULT: bool = true;
79
80     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
81         run.all_krates("test").path("library")
82     }
83
84     fn make_run(run: RunConfig<'_>) {
85         run.builder.ensure(Std { target: run.target });
86     }
87
88     fn run(self, builder: &Builder<'_>) {
89         builder.update_submodule(&Path::new("library").join("stdarch"));
90
91         let target = self.target;
92         let compiler = builder.compiler(builder.top_stage, builder.config.build);
93
94         let mut cargo = builder.cargo(
95             compiler,
96             Mode::Std,
97             SourceType::InTree,
98             target,
99             cargo_subcommand(builder.kind),
100         );
101         std_cargo(builder, target, compiler.stage, &mut cargo);
102
103         builder.info(&format!(
104             "Checking stage{} library artifacts ({} -> {})",
105             builder.top_stage, &compiler.host, target
106         ));
107         run_cargo(
108             builder,
109             cargo,
110             args(builder),
111             &libstd_stamp(builder, compiler, target),
112             vec![],
113             true,
114             false,
115         );
116
117         // We skip populating the sysroot in non-zero stage because that'll lead
118         // to rlib/rmeta conflicts if std gets built during this session.
119         if compiler.stage == 0 {
120             let libdir = builder.sysroot_libdir(compiler, target);
121             let hostdir = builder.sysroot_libdir(compiler, compiler.host);
122             add_to_sysroot(&builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target));
123         }
124
125         // don't run on std twice with x.py clippy
126         if builder.kind == Kind::Clippy {
127             return;
128         }
129
130         // Then run cargo again, once we've put the rmeta files for the library
131         // crates into the sysroot. This is needed because e.g., core's tests
132         // depend on `libtest` -- Cargo presumes it will exist, but it doesn't
133         // since we initialize with an empty sysroot.
134         //
135         // Currently only the "libtest" tree of crates does this.
136         let mut cargo = builder.cargo(
137             compiler,
138             Mode::Std,
139             SourceType::InTree,
140             target,
141             cargo_subcommand(builder.kind),
142         );
143
144         // If we're not in stage 0, tests and examples will fail to compile
145         // from `core` definitions being loaded from two different `libcore`
146         // .rmeta and .rlib files.
147         if compiler.stage == 0 {
148             cargo.arg("--all-targets");
149         }
150
151         std_cargo(builder, target, compiler.stage, &mut cargo);
152
153         // Explicitly pass -p for all dependencies krates -- this will force cargo
154         // to also check the tests/benches/examples for these crates, rather
155         // than just the leaf crate.
156         for krate in builder.in_tree_crates("test", Some(target)) {
157             cargo.arg("-p").arg(krate.name);
158         }
159
160         builder.info(&format!(
161             "Checking stage{} library test/bench/example targets ({} -> {})",
162             builder.top_stage, &compiler.host, target
163         ));
164         run_cargo(
165             builder,
166             cargo,
167             args(builder),
168             &libstd_test_stamp(builder, compiler, target),
169             vec![],
170             true,
171             false,
172         );
173     }
174 }
175
176 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
177 pub struct Rustc {
178     pub target: TargetSelection,
179 }
180
181 impl Step for Rustc {
182     type Output = ();
183     const ONLY_HOSTS: bool = true;
184     const DEFAULT: bool = true;
185
186     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
187         run.all_krates("rustc-main").path("compiler")
188     }
189
190     fn make_run(run: RunConfig<'_>) {
191         run.builder.ensure(Rustc { target: run.target });
192     }
193
194     /// Builds the compiler.
195     ///
196     /// This will build the compiler for a particular stage of the build using
197     /// the `compiler` targeting the `target` architecture. The artifacts
198     /// created will also be linked into the sysroot directory.
199     fn run(self, builder: &Builder<'_>) {
200         let compiler = builder.compiler(builder.top_stage, builder.config.build);
201         let target = self.target;
202
203         if compiler.stage != 0 {
204             // If we're not in stage 0, then we won't have a std from the beta
205             // compiler around. That means we need to make sure there's one in
206             // the sysroot for the compiler to find. Otherwise, we're going to
207             // fail when building crates that need to generate code (e.g., build
208             // scripts and their dependencies).
209             builder.ensure(crate::compile::Std::new(compiler, compiler.host));
210             builder.ensure(crate::compile::Std::new(compiler, target));
211         } else {
212             builder.ensure(Std { target });
213         }
214
215         let mut cargo = builder.cargo(
216             compiler,
217             Mode::Rustc,
218             SourceType::InTree,
219             target,
220             cargo_subcommand(builder.kind),
221         );
222         rustc_cargo(builder, &mut cargo, target);
223
224         // For ./x.py clippy, don't run with --all-targets because
225         // linting tests and benchmarks can produce very noisy results
226         if builder.kind != Kind::Clippy {
227             cargo.arg("--all-targets");
228         }
229
230         // Explicitly pass -p for all compiler krates -- this will force cargo
231         // to also check the tests/benches/examples for these crates, rather
232         // than just the leaf crate.
233         for krate in builder.in_tree_crates("rustc-main", Some(target)) {
234             cargo.arg("-p").arg(krate.name);
235         }
236
237         builder.info(&format!(
238             "Checking stage{} compiler artifacts ({} -> {})",
239             builder.top_stage, &compiler.host, target
240         ));
241         run_cargo(
242             builder,
243             cargo,
244             args(builder),
245             &librustc_stamp(builder, compiler, target),
246             vec![],
247             true,
248             false,
249         );
250
251         let libdir = builder.sysroot_libdir(compiler, target);
252         let hostdir = builder.sysroot_libdir(compiler, compiler.host);
253         add_to_sysroot(&builder, &libdir, &hostdir, &librustc_stamp(builder, compiler, target));
254     }
255 }
256
257 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
258 pub struct CodegenBackend {
259     pub target: TargetSelection,
260     pub backend: Interned<String>,
261 }
262
263 impl Step for CodegenBackend {
264     type Output = ();
265     const ONLY_HOSTS: bool = true;
266     const DEFAULT: bool = true;
267
268     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
269         run.paths(&["compiler/rustc_codegen_cranelift", "compiler/rustc_codegen_gcc"])
270     }
271
272     fn make_run(run: RunConfig<'_>) {
273         for &backend in &[INTERNER.intern_str("cranelift"), INTERNER.intern_str("gcc")] {
274             run.builder.ensure(CodegenBackend { target: run.target, backend });
275         }
276     }
277
278     fn run(self, builder: &Builder<'_>) {
279         let compiler = builder.compiler(builder.top_stage, builder.config.build);
280         let target = self.target;
281         let backend = self.backend;
282
283         builder.ensure(Rustc { target });
284
285         let mut cargo = builder.cargo(
286             compiler,
287             Mode::Codegen,
288             SourceType::InTree,
289             target,
290             cargo_subcommand(builder.kind),
291         );
292         cargo
293             .arg("--manifest-path")
294             .arg(builder.src.join(format!("compiler/rustc_codegen_{}/Cargo.toml", backend)));
295         rustc_cargo_env(builder, &mut cargo, target);
296
297         builder.info(&format!(
298             "Checking stage{} {} artifacts ({} -> {})",
299             builder.top_stage, backend, &compiler.host.triple, target.triple
300         ));
301
302         run_cargo(
303             builder,
304             cargo,
305             args(builder),
306             &codegen_backend_stamp(builder, compiler, target, backend),
307             vec![],
308             true,
309             false,
310         );
311     }
312 }
313
314 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
315 pub struct RustAnalyzer {
316     pub target: TargetSelection,
317 }
318
319 impl Step for RustAnalyzer {
320     type Output = ();
321     const ONLY_HOSTS: bool = true;
322     const DEFAULT: bool = true;
323
324     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
325         run.path("src/tools/rust-analyzer")
326     }
327
328     fn make_run(run: RunConfig<'_>) {
329         run.builder.ensure(RustAnalyzer { target: run.target });
330     }
331
332     fn run(self, builder: &Builder<'_>) {
333         let compiler = builder.compiler(builder.top_stage, builder.config.build);
334         let target = self.target;
335
336         builder.ensure(Std { target });
337
338         let mut cargo = prepare_tool_cargo(
339             builder,
340             compiler,
341             Mode::ToolStd,
342             target,
343             cargo_subcommand(builder.kind),
344             "src/tools/rust-analyzer",
345             SourceType::InTree,
346             &["rust-analyzer/in-rust-tree".to_owned()],
347         );
348
349         cargo.allow_features(crate::tool::RustAnalyzer::ALLOW_FEATURES);
350
351         // For ./x.py clippy, don't check those targets because
352         // linting tests and benchmarks can produce very noisy results
353         if builder.kind != Kind::Clippy {
354             // can't use `--all-targets` because `--examples` doesn't work well
355             cargo.arg("--bins");
356             cargo.arg("--tests");
357             cargo.arg("--benches");
358         }
359
360         builder.info(&format!(
361             "Checking stage{} {} artifacts ({} -> {})",
362             compiler.stage, "rust-analyzer", &compiler.host.triple, target.triple
363         ));
364         run_cargo(
365             builder,
366             cargo,
367             args(builder),
368             &stamp(builder, compiler, target),
369             vec![],
370             true,
371             false,
372         );
373
374         /// Cargo's output path in a given stage, compiled by a particular
375         /// compiler for the specified target.
376         fn stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
377             builder.cargo_out(compiler, Mode::ToolStd, target).join(".rust-analyzer-check.stamp")
378         }
379     }
380 }
381
382 macro_rules! tool_check_step {
383     ($name:ident, $path:literal, $($alias:literal, )* $source_type:path $(, $default:literal )?) => {
384         #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
385         pub struct $name {
386             pub target: TargetSelection,
387         }
388
389         impl Step for $name {
390             type Output = ();
391             const ONLY_HOSTS: bool = true;
392             // don't ever check out-of-tree tools by default, they'll fail when toolstate is broken
393             const DEFAULT: bool = matches!($source_type, SourceType::InTree) $( && $default )?;
394
395             fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
396                 run.paths(&[ $path, $($alias),* ])
397             }
398
399             fn make_run(run: RunConfig<'_>) {
400                 run.builder.ensure($name { target: run.target });
401             }
402
403             fn run(self, builder: &Builder<'_>) {
404                 let compiler = builder.compiler(builder.top_stage, builder.config.build);
405                 let target = self.target;
406
407                 builder.ensure(Rustc { target });
408
409                 let mut cargo = prepare_tool_cargo(
410                     builder,
411                     compiler,
412                     Mode::ToolRustc,
413                     target,
414                     cargo_subcommand(builder.kind),
415                     $path,
416                     $source_type,
417                     &[],
418                 );
419
420                 // For ./x.py clippy, don't run with --all-targets because
421                 // linting tests and benchmarks can produce very noisy results
422                 if builder.kind != Kind::Clippy {
423                     cargo.arg("--all-targets");
424                 }
425
426                 // Enable internal lints for clippy and rustdoc
427                 // NOTE: this doesn't enable lints for any other tools unless they explicitly add `#![warn(rustc::internal)]`
428                 // See https://github.com/rust-lang/rust/pull/80573#issuecomment-754010776
429                 cargo.rustflag("-Zunstable-options");
430
431                 builder.info(&format!(
432                     "Checking stage{} {} artifacts ({} -> {})",
433                     builder.top_stage,
434                     stringify!($name).to_lowercase(),
435                     &compiler.host.triple,
436                     target.triple
437                 ));
438                 run_cargo(
439                     builder,
440                     cargo,
441                     args(builder),
442                     &stamp(builder, compiler, target),
443                     vec![],
444                     true,
445                     false,
446                 );
447
448                 /// Cargo's output path in a given stage, compiled by a particular
449                 /// compiler for the specified target.
450                 fn stamp(
451                     builder: &Builder<'_>,
452                     compiler: Compiler,
453                     target: TargetSelection,
454                 ) -> PathBuf {
455                     builder
456                         .cargo_out(compiler, Mode::ToolRustc, target)
457                         .join(format!(".{}-check.stamp", stringify!($name).to_lowercase()))
458                 }
459             }
460         }
461     };
462 }
463
464 tool_check_step!(Rustdoc, "src/tools/rustdoc", "src/librustdoc", SourceType::InTree);
465 // Clippy, miri and Rustfmt are hybrids. They are external tools, but use a git subtree instead
466 // of a submodule. Since the SourceType only drives the deny-warnings
467 // behavior, treat it as in-tree so that any new warnings in clippy will be
468 // rejected.
469 tool_check_step!(Clippy, "src/tools/clippy", SourceType::InTree);
470 tool_check_step!(Miri, "src/tools/miri", SourceType::InTree);
471 tool_check_step!(CargoMiri, "src/tools/miri/cargo-miri", SourceType::InTree);
472 tool_check_step!(Rls, "src/tools/rls", SourceType::InTree);
473 tool_check_step!(Rustfmt, "src/tools/rustfmt", SourceType::InTree);
474 tool_check_step!(MiroptTestTools, "src/tools/miropt-test-tools", SourceType::InTree);
475
476 tool_check_step!(Bootstrap, "src/bootstrap", SourceType::InTree, false);
477
478 /// Cargo's output path for the standard library in a given stage, compiled
479 /// by a particular compiler for the specified target.
480 fn libstd_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
481     builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check.stamp")
482 }
483
484 /// Cargo's output path for the standard library in a given stage, compiled
485 /// by a particular compiler for the specified target.
486 fn libstd_test_stamp(
487     builder: &Builder<'_>,
488     compiler: Compiler,
489     target: TargetSelection,
490 ) -> PathBuf {
491     builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check-test.stamp")
492 }
493
494 /// Cargo's output path for librustc in a given stage, compiled by a particular
495 /// compiler for the specified target.
496 fn librustc_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
497     builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc-check.stamp")
498 }
499
500 /// Cargo's output path for librustc_codegen_llvm in a given stage, compiled by a particular
501 /// compiler for the specified target and backend.
502 fn codegen_backend_stamp(
503     builder: &Builder<'_>,
504     compiler: Compiler,
505     target: TargetSelection,
506     backend: Interned<String>,
507 ) -> PathBuf {
508     builder
509         .cargo_out(compiler, Mode::Codegen, target)
510         .join(format!(".librustc_codegen_{}-check.stamp", backend))
511 }