1 //! Implementation of compiling the compiler and standard library, in "check"-based modes.
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};
9 use crate::{Compiler, Mode, Subcommand};
10 use std::path::PathBuf;
12 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
14 pub target: TargetSelection,
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)
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
29 "missing_safety_doc", // almost 3K warnings
31 "needless_lifetimes", // people want to keep the lifetimes
32 "wrong_self_convention",
34 let mut args = vec![];
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",
45 args.extend(strings(&["--", "--cap-lints", "warn"]));
46 args.extend(ignored_lints.iter().map(|lint| format!("-Aclippy::{}", lint)));
53 fn cargo_subcommand(kind: Kind) -> &'static str {
55 Kind::Check => "check",
56 Kind::Clippy => "clippy",
64 const DEFAULT: bool = true;
66 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
67 run.all_krates("test")
70 fn make_run(run: RunConfig<'_>) {
71 run.builder.ensure(Std { target: run.target });
74 fn run(self, builder: &Builder<'_>) {
75 let target = self.target;
76 let compiler = builder.compiler(builder.top_stage, builder.config.build);
78 let mut cargo = builder.cargo(
83 cargo_subcommand(builder.kind),
85 std_cargo(builder, target, compiler.stage, &mut cargo);
87 builder.info(&format!(
88 "Checking stage{} std artifacts ({} -> {})",
89 builder.top_stage, &compiler.host, target
95 &libstd_stamp(builder, compiler, target),
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));
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.
113 // Currently only the "libtest" tree of crates does this.
115 if let Subcommand::Check { all_targets: true, .. } = builder.config.cmd {
116 let mut cargo = builder.cargo(
121 cargo_subcommand(builder.kind),
123 std_cargo(builder, target, compiler.stage, &mut cargo);
124 cargo.arg("--all-targets");
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);
133 builder.info(&format!(
134 "Checking stage{} std test/bench/example targets ({} -> {})",
135 builder.top_stage, &compiler.host, target
141 &libstd_test_stamp(builder, compiler, target),
149 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
151 pub target: TargetSelection,
154 impl Step for Rustc {
156 const ONLY_HOSTS: bool = true;
157 const DEFAULT: bool = true;
159 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
160 run.all_krates("rustc-main")
163 fn make_run(run: RunConfig<'_>) {
164 run.builder.ensure(Rustc { target: run.target });
167 /// Builds the compiler.
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;
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 });
185 builder.ensure(Std { target });
188 let mut cargo = builder.cargo(
193 cargo_subcommand(builder.kind),
195 rustc_cargo(builder, &mut cargo, target);
196 if let Subcommand::Check { all_targets: true, .. } = builder.config.cmd {
197 cargo.arg("--all-targets");
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);
207 builder.info(&format!(
208 "Checking stage{} compiler artifacts ({} -> {})",
209 builder.top_stage, &compiler.host, target
215 &librustc_stamp(builder, compiler, target),
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));
226 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
227 pub struct CodegenBackend {
228 pub target: TargetSelection,
229 pub backend: Interned<String>,
232 impl Step for CodegenBackend {
234 const ONLY_HOSTS: bool = true;
235 const DEFAULT: bool = true;
237 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
238 run.paths(&["compiler/rustc_codegen_cranelift", "rustc_codegen_cranelift"])
241 fn make_run(run: RunConfig<'_>) {
242 for &backend in &[INTERNER.intern_str("cranelift")] {
243 run.builder.ensure(CodegenBackend { target: run.target, backend });
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;
252 builder.ensure(Rustc { target });
254 let mut cargo = builder.cargo(
257 SourceType::Submodule,
259 cargo_subcommand(builder.kind),
262 .arg("--manifest-path")
263 .arg(builder.src.join(format!("compiler/rustc_codegen_{}/Cargo.toml", backend)));
264 rustc_cargo_env(builder, &mut cargo, target);
266 builder.info(&format!(
267 "Checking stage{} {} artifacts ({} -> {})",
268 builder.top_stage, backend, &compiler.host.triple, target.triple
275 &codegen_backend_stamp(builder, compiler, target, backend),
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)]
286 pub target: TargetSelection,
289 impl Step for $name {
291 const ONLY_HOSTS: bool = true;
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 )?;
295 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
296 run.paths(&[ $path, $($alias),* ])
299 fn make_run(run: RunConfig<'_>) {
300 run.builder.ensure($name { target: run.target });
303 fn run(self, builder: &Builder<'_>) {
304 let compiler = builder.compiler(builder.top_stage, builder.config.build);
305 let target = self.target;
307 builder.ensure(Rustc { target });
309 let mut cargo = prepare_tool_cargo(
314 cargo_subcommand(builder.kind),
320 if let Subcommand::Check { all_targets: true, .. } = builder.config.cmd {
321 cargo.arg("--all-targets");
324 // Enable internal lints for clippy and rustdoc
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");
329 builder.info(&format!(
330 "Checking stage{} {} artifacts ({} -> {})",
332 stringify!($name).to_lowercase(),
333 &compiler.host.triple,
340 &stamp(builder, compiler, target),
345 /// Cargo's output path in a given stage, compiled by a particular
346 /// compiler for the specified target.
348 builder: &Builder<'_>,
350 target: TargetSelection,
353 .cargo_out(compiler, Mode::ToolRustc, target)
354 .join(format!(".{}-check.stamp", stringify!($name).to_lowercase()))
361 tool_check_step!(Rustdoc, "src/tools/rustdoc", "src/librustdoc", SourceType::InTree);
362 // Clippy and Rustfmt are hybrids. They are external tools, but use a git subtree instead
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
366 tool_check_step!(Clippy, "src/tools/clippy", SourceType::InTree);
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);
371 tool_check_step!(Bootstrap, "src/bootstrap", SourceType::InTree, false);
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")
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<'_>,
384 target: TargetSelection,
386 builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check-test.stamp")
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")
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<'_>,
400 target: TargetSelection,
401 backend: Interned<String>,
404 .cargo_out(compiler, Mode::Codegen, target)
405 .join(format!(".librustc_codegen_{}-check.stamp", backend))