]> git.lizzy.rs Git - rust.git/blob - src/bootstrap/check.rs
Don't check bootstrap artifacts by default
[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::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         let target = self.target;
76         let compiler = builder.compiler(builder.top_stage, builder.config.build);
77
78         let mut cargo = builder.cargo(
79             compiler,
80             Mode::Std,
81             SourceType::InTree,
82             target,
83             cargo_subcommand(builder.kind),
84         );
85         std_cargo(builder, target, compiler.stage, &mut cargo);
86
87         builder.info(&format!(
88             "Checking stage{} std artifacts ({} -> {})",
89             builder.top_stage, &compiler.host, target
90         ));
91         run_cargo(
92             builder,
93             cargo,
94             args(builder),
95             &libstd_stamp(builder, compiler, target),
96             vec![],
97             true,
98         );
99
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         }
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
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             }
132
133             builder.info(&format!(
134                 "Checking stage{} std test/bench/example targets ({} -> {})",
135                 builder.top_stage, &compiler.host, target
136             ));
137             run_cargo(
138                 builder,
139                 cargo,
140                 args(builder),
141                 &libstd_test_stamp(builder, compiler, target),
142                 vec![],
143                 true,
144             );
145         }
146     }
147 }
148
149 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
150 pub struct Rustc {
151     pub target: TargetSelection,
152 }
153
154 impl Step for Rustc {
155     type Output = ();
156     const ONLY_HOSTS: bool = true;
157     const DEFAULT: bool = true;
158
159     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
160         run.all_krates("rustc-main")
161     }
162
163     fn make_run(run: RunConfig<'_>) {
164         run.builder.ensure(Rustc { target: run.target });
165     }
166
167     /// Builds the compiler.
168     ///
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.
172     fn run(self, builder: &Builder<'_>) {
173         let compiler = builder.compiler(builder.top_stage, builder.config.build);
174         let target = self.target;
175
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         }
187
188         let mut cargo = builder.cargo(
189             compiler,
190             Mode::Rustc,
191             SourceType::InTree,
192             target,
193             cargo_subcommand(builder.kind),
194         );
195         rustc_cargo(builder, &mut cargo, target);
196         if let Subcommand::Check { all_targets: true, .. } = builder.config.cmd {
197             cargo.arg("--all-targets");
198         }
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.
203         for krate in builder.in_tree_crates("rustc-main", Some(target)) {
204             cargo.arg("-p").arg(krate.name);
205         }
206
207         builder.info(&format!(
208             "Checking stage{} compiler artifacts ({} -> {})",
209             builder.top_stage, &compiler.host, target
210         ));
211         run_cargo(
212             builder,
213             cargo,
214             args(builder),
215             &librustc_stamp(builder, compiler, target),
216             vec![],
217             true,
218         );
219
220         let libdir = builder.sysroot_libdir(compiler, target);
221         let hostdir = builder.sysroot_libdir(compiler, compiler.host);
222         add_to_sysroot(&builder, &libdir, &hostdir, &librustc_stamp(builder, compiler, target));
223     }
224 }
225
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<'_>) {
248         let compiler = builder.compiler(builder.top_stage, builder.config.build);
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
266         builder.info(&format!(
267             "Checking stage{} {} artifacts ({} -> {})",
268             builder.top_stage, backend, &compiler.host.triple, target.triple
269         ));
270
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
282 macro_rules! tool_check_step {
283     ($name:ident, $path:literal, $($alias:literal, )* $source_type:path $(, $default:literal )?) => {
284         #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
285         pub struct $name {
286             pub target: TargetSelection,
287         }
288
289         impl Step for $name {
290             type Output = ();
291             const ONLY_HOSTS: bool = true;
292             const DEFAULT: bool = true $( && $default )?;
293
294             fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
295                 run.paths(&[ $path, $($alias),* ])
296             }
297
298             fn make_run(run: RunConfig<'_>) {
299                 run.builder.ensure($name { target: run.target });
300             }
301
302             fn run(self, builder: &Builder<'_>) {
303                 let compiler = builder.compiler(builder.top_stage, builder.config.build);
304                 let target = self.target;
305
306                 builder.ensure(Rustc { target });
307
308                 let mut cargo = prepare_tool_cargo(
309                     builder,
310                     compiler,
311                     Mode::ToolRustc,
312                     target,
313                     cargo_subcommand(builder.kind),
314                     $path,
315                     $source_type,
316                     &[],
317                 );
318
319                 if let Subcommand::Check { all_targets: true, .. } = builder.config.cmd {
320                     cargo.arg("--all-targets");
321                 }
322
323                 // Enable internal lints for clippy and rustdoc
324                 // NOTE: this doesn't enable lints for any other tools unless they explicitly add `#![warn(rustc::internal)]`
325                 // See https://github.com/rust-lang/rust/pull/80573#issuecomment-754010776
326                 cargo.rustflag("-Zunstable-options");
327
328                 builder.info(&format!(
329                     "Checking stage{} {} artifacts ({} -> {})",
330                     builder.top_stage,
331                     stringify!($name).to_lowercase(),
332                     &compiler.host.triple,
333                     target.triple
334                 ));
335                 run_cargo(
336                     builder,
337                     cargo,
338                     args(builder),
339                     &stamp(builder, compiler, target),
340                     vec![],
341                     true,
342                 );
343
344                 let libdir = builder.sysroot_libdir(compiler, target);
345                 let hostdir = builder.sysroot_libdir(compiler, compiler.host);
346                 add_to_sysroot(&builder, &libdir, &hostdir, &stamp(builder, compiler, target));
347
348                 /// Cargo's output path in a given stage, compiled by a particular
349                 /// compiler for the specified target.
350                 fn stamp(
351                     builder: &Builder<'_>,
352                     compiler: Compiler,
353                     target: TargetSelection,
354                 ) -> PathBuf {
355                     builder
356                         .cargo_out(compiler, Mode::ToolRustc, target)
357                         .join(format!(".{}-check.stamp", stringify!($name).to_lowercase()))
358                 }
359             }
360         }
361     };
362 }
363
364 tool_check_step!(Rustdoc, "src/tools/rustdoc", "src/librustdoc", SourceType::InTree);
365 // Clippy is a hybrid. It is an external tool, but uses a git subtree instead
366 // of a submodule. Since the SourceType only drives the deny-warnings
367 // behavior, treat it as in-tree so that any new warnings in clippy will be
368 // rejected.
369 tool_check_step!(Clippy, "src/tools/clippy", SourceType::InTree);
370
371 tool_check_step!(Bootstrap, "src/bootstrap", SourceType::InTree, false);
372
373 /// Cargo's output path for the standard library in a given stage, compiled
374 /// by a particular compiler for the specified target.
375 fn libstd_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
376     builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check.stamp")
377 }
378
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
389 /// Cargo's output path for librustc in a given stage, compiled by a particular
390 /// compiler for the specified target.
391 fn librustc_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
392     builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc-check.stamp")
393 }
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 }