]> git.lizzy.rs Git - rust.git/blob - src/bootstrap/check.rs
Rollup merge of #88706 - ThePuzzlemaker:issue-88609, r=jackh726
[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 { fix, .. } = builder.config.cmd {
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         ];
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"]));
46         args.extend(ignored_lints.iter().map(|lint| format!("-Aclippy::{}", lint)));
47         args
48     } else {
49         vec![]
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",
58         _ => unreachable!(),
59     }
60 }
61
62 impl Step for Std {
63     type Output = ();
64     const DEFAULT: bool = true;
65
66     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
67         run.all_krates("test")
68     }
69
70     fn make_run(run: RunConfig<'_>) {
71         run.builder.ensure(Std { target: run.target });
72     }
73
74     fn run(self, builder: &Builder<'_>) {
75         builder.update_submodule(&Path::new("library").join("stdarch"));
76
77         let target = self.target;
78         let compiler = builder.compiler(builder.top_stage, builder.config.build);
79
80         let mut cargo = builder.cargo(
81             compiler,
82             Mode::Std,
83             SourceType::InTree,
84             target,
85             cargo_subcommand(builder.kind),
86         );
87         std_cargo(builder, target, compiler.stage, &mut cargo);
88
89         builder.info(&format!(
90             "Checking stage{} std artifacts ({} -> {})",
91             builder.top_stage, &compiler.host, target
92         ));
93         run_cargo(
94             builder,
95             cargo,
96             args(builder),
97             &libstd_stamp(builder, compiler, target),
98             vec![],
99             true,
100         );
101
102         // We skip populating the sysroot in non-zero stage because that'll lead
103         // to rlib/rmeta conflicts if std gets built during this session.
104         if compiler.stage == 0 {
105             let libdir = builder.sysroot_libdir(compiler, target);
106             let hostdir = builder.sysroot_libdir(compiler, compiler.host);
107             add_to_sysroot(&builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target));
108         }
109
110         // don't run on std twice with x.py clippy
111         if builder.kind == Kind::Clippy {
112             return;
113         }
114
115         // Then run cargo again, once we've put the rmeta files for the library
116         // crates into the sysroot. This is needed because e.g., core's tests
117         // depend on `libtest` -- Cargo presumes it will exist, but it doesn't
118         // since we initialize with an empty sysroot.
119         //
120         // Currently only the "libtest" tree of crates does this.
121         let mut cargo = builder.cargo(
122             compiler,
123             Mode::Std,
124             SourceType::InTree,
125             target,
126             cargo_subcommand(builder.kind),
127         );
128
129         cargo.arg("--all-targets");
130         std_cargo(builder, target, compiler.stage, &mut cargo);
131
132         // Explicitly pass -p for all dependencies krates -- this will force cargo
133         // to also check the tests/benches/examples for these crates, rather
134         // than just the leaf crate.
135         for krate in builder.in_tree_crates("test", Some(target)) {
136             cargo.arg("-p").arg(krate.name);
137         }
138
139         builder.info(&format!(
140             "Checking stage{} std test/bench/example targets ({} -> {})",
141             builder.top_stage, &compiler.host, target
142         ));
143         run_cargo(
144             builder,
145             cargo,
146             args(builder),
147             &libstd_test_stamp(builder, compiler, target),
148             vec![],
149             true,
150         );
151     }
152 }
153
154 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
155 pub struct Rustc {
156     pub target: TargetSelection,
157 }
158
159 impl Step for Rustc {
160     type Output = ();
161     const ONLY_HOSTS: bool = true;
162     const DEFAULT: bool = true;
163
164     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
165         run.all_krates("rustc-main")
166     }
167
168     fn make_run(run: RunConfig<'_>) {
169         run.builder.ensure(Rustc { target: run.target });
170     }
171
172     /// Builds the compiler.
173     ///
174     /// This will build the compiler for a particular stage of the build using
175     /// the `compiler` targeting the `target` architecture. The artifacts
176     /// created will also be linked into the sysroot directory.
177     fn run(self, builder: &Builder<'_>) {
178         let compiler = builder.compiler(builder.top_stage, builder.config.build);
179         let target = self.target;
180
181         if compiler.stage != 0 {
182             // If we're not in stage 0, then we won't have a std from the beta
183             // compiler around. That means we need to make sure there's one in
184             // the sysroot for the compiler to find. Otherwise, we're going to
185             // fail when building crates that need to generate code (e.g., build
186             // scripts and their dependencies).
187             builder.ensure(crate::compile::Std { target: compiler.host, compiler });
188             builder.ensure(crate::compile::Std { target, compiler });
189         } else {
190             builder.ensure(Std { target });
191         }
192
193         let mut cargo = builder.cargo(
194             compiler,
195             Mode::Rustc,
196             SourceType::InTree,
197             target,
198             cargo_subcommand(builder.kind),
199         );
200         rustc_cargo(builder, &mut cargo, target);
201
202         // For ./x.py clippy, don't run with --all-targets because
203         // linting tests and benchmarks can produce very noisy results
204         if builder.kind != Kind::Clippy {
205             cargo.arg("--all-targets");
206         }
207
208         // Explicitly pass -p for all compiler krates -- this will force cargo
209         // to also check the tests/benches/examples for these crates, rather
210         // than just the leaf crate.
211         for krate in builder.in_tree_crates("rustc-main", Some(target)) {
212             cargo.arg("-p").arg(krate.name);
213         }
214
215         builder.info(&format!(
216             "Checking stage{} compiler artifacts ({} -> {})",
217             builder.top_stage, &compiler.host, target
218         ));
219         run_cargo(
220             builder,
221             cargo,
222             args(builder),
223             &librustc_stamp(builder, compiler, target),
224             vec![],
225             true,
226         );
227
228         let libdir = builder.sysroot_libdir(compiler, target);
229         let hostdir = builder.sysroot_libdir(compiler, compiler.host);
230         add_to_sysroot(&builder, &libdir, &hostdir, &librustc_stamp(builder, compiler, target));
231     }
232 }
233
234 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
235 pub struct CodegenBackend {
236     pub target: TargetSelection,
237     pub backend: Interned<String>,
238 }
239
240 impl Step for CodegenBackend {
241     type Output = ();
242     const ONLY_HOSTS: bool = true;
243     const DEFAULT: bool = true;
244
245     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
246         run.paths(&[
247             "compiler/rustc_codegen_cranelift",
248             "rustc_codegen_cranelift",
249             "compiler/rustc_codegen_gcc",
250             "rustc_codegen_gcc",
251         ])
252     }
253
254     fn make_run(run: RunConfig<'_>) {
255         for &backend in &[INTERNER.intern_str("cranelift"), INTERNER.intern_str("gcc")] {
256             run.builder.ensure(CodegenBackend { target: run.target, backend });
257         }
258     }
259
260     fn run(self, builder: &Builder<'_>) {
261         let compiler = builder.compiler(builder.top_stage, builder.config.build);
262         let target = self.target;
263         let backend = self.backend;
264
265         builder.ensure(Rustc { target });
266
267         let mut cargo = builder.cargo(
268             compiler,
269             Mode::Codegen,
270             SourceType::InTree,
271             target,
272             cargo_subcommand(builder.kind),
273         );
274         cargo
275             .arg("--manifest-path")
276             .arg(builder.src.join(format!("compiler/rustc_codegen_{}/Cargo.toml", backend)));
277         rustc_cargo_env(builder, &mut cargo, target);
278
279         builder.info(&format!(
280             "Checking stage{} {} artifacts ({} -> {})",
281             builder.top_stage, backend, &compiler.host.triple, target.triple
282         ));
283
284         run_cargo(
285             builder,
286             cargo,
287             args(builder),
288             &codegen_backend_stamp(builder, compiler, target, backend),
289             vec![],
290             true,
291         );
292     }
293 }
294
295 macro_rules! tool_check_step {
296     ($name:ident, $path:literal, $($alias:literal, )* $source_type:path $(, $default:literal )?) => {
297         #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
298         pub struct $name {
299             pub target: TargetSelection,
300         }
301
302         impl Step for $name {
303             type Output = ();
304             const ONLY_HOSTS: bool = true;
305             // don't ever check out-of-tree tools by default, they'll fail when toolstate is broken
306             const DEFAULT: bool = matches!($source_type, SourceType::InTree) $( && $default )?;
307
308             fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
309                 run.paths(&[ $path, $($alias),* ])
310             }
311
312             fn make_run(run: RunConfig<'_>) {
313                 run.builder.ensure($name { target: run.target });
314             }
315
316             fn run(self, builder: &Builder<'_>) {
317                 let compiler = builder.compiler(builder.top_stage, builder.config.build);
318                 let target = self.target;
319
320                 builder.ensure(Rustc { target });
321
322                 let mut cargo = prepare_tool_cargo(
323                     builder,
324                     compiler,
325                     Mode::ToolRustc,
326                     target,
327                     cargo_subcommand(builder.kind),
328                     $path,
329                     $source_type,
330                     &[],
331                 );
332
333                 // For ./x.py clippy, don't run with --all-targets because
334                 // linting tests and benchmarks can produce very noisy results
335                 if builder.kind != Kind::Clippy {
336                     cargo.arg("--all-targets");
337                 }
338
339                 // Enable internal lints for clippy and rustdoc
340                 // NOTE: this doesn't enable lints for any other tools unless they explicitly add `#![warn(rustc::internal)]`
341                 // See https://github.com/rust-lang/rust/pull/80573#issuecomment-754010776
342                 cargo.rustflag("-Zunstable-options");
343
344                 builder.info(&format!(
345                     "Checking stage{} {} artifacts ({} -> {})",
346                     builder.top_stage,
347                     stringify!($name).to_lowercase(),
348                     &compiler.host.triple,
349                     target.triple
350                 ));
351                 run_cargo(
352                     builder,
353                     cargo,
354                     args(builder),
355                     &stamp(builder, compiler, target),
356                     vec![],
357                     true,
358                 );
359
360                 /// Cargo's output path in a given stage, compiled by a particular
361                 /// compiler for the specified target.
362                 fn stamp(
363                     builder: &Builder<'_>,
364                     compiler: Compiler,
365                     target: TargetSelection,
366                 ) -> PathBuf {
367                     builder
368                         .cargo_out(compiler, Mode::ToolRustc, target)
369                         .join(format!(".{}-check.stamp", stringify!($name).to_lowercase()))
370                 }
371             }
372         }
373     };
374 }
375
376 tool_check_step!(Rustdoc, "src/tools/rustdoc", "src/librustdoc", SourceType::InTree);
377 // Clippy and Rustfmt are hybrids. They are external tools, but use a git subtree instead
378 // of a submodule. Since the SourceType only drives the deny-warnings
379 // behavior, treat it as in-tree so that any new warnings in clippy will be
380 // rejected.
381 tool_check_step!(Clippy, "src/tools/clippy", SourceType::InTree);
382 tool_check_step!(Miri, "src/tools/miri", SourceType::Submodule);
383 tool_check_step!(Rls, "src/tools/rls", SourceType::Submodule);
384 tool_check_step!(Rustfmt, "src/tools/rustfmt", SourceType::InTree);
385
386 tool_check_step!(Bootstrap, "src/bootstrap", SourceType::InTree, false);
387
388 /// Cargo's output path for the standard library in a given stage, compiled
389 /// by a particular compiler for the specified target.
390 fn libstd_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
391     builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check.stamp")
392 }
393
394 /// Cargo's output path for the standard library in a given stage, compiled
395 /// by a particular compiler for the specified target.
396 fn libstd_test_stamp(
397     builder: &Builder<'_>,
398     compiler: Compiler,
399     target: TargetSelection,
400 ) -> PathBuf {
401     builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check-test.stamp")
402 }
403
404 /// Cargo's output path for librustc in a given stage, compiled by a particular
405 /// compiler for the specified target.
406 fn librustc_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
407     builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc-check.stamp")
408 }
409
410 /// Cargo's output path for librustc_codegen_llvm in a given stage, compiled by a particular
411 /// compiler for the specified target and backend.
412 fn codegen_backend_stamp(
413     builder: &Builder<'_>,
414     compiler: Compiler,
415     target: TargetSelection,
416     backend: Interned<String>,
417 ) -> PathBuf {
418     builder
419         .cargo_out(compiler, Mode::Codegen, target)
420         .join(format!(".librustc_codegen_{}-check.stamp", backend))
421 }