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::{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 builder.update_submodule(&Path::new("library").join("stdarch"));
77 let target = self.target;
78 let compiler = builder.compiler(builder.top_stage, builder.config.build);
80 let mut cargo = builder.cargo(
85 cargo_subcommand(builder.kind),
87 std_cargo(builder, target, compiler.stage, &mut cargo);
89 builder.info(&format!(
90 "Checking stage{} std artifacts ({} -> {})",
91 builder.top_stage, &compiler.host, target
97 &libstd_stamp(builder, compiler, target),
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));
110 // Then run cargo again, once we've put the rmeta files for the library
111 // crates into the sysroot. This is needed because e.g., core's tests
112 // depend on `libtest` -- Cargo presumes it will exist, but it doesn't
113 // since we initialize with an empty sysroot.
115 // Currently only the "libtest" tree of crates does this.
117 if let Subcommand::Check { all_targets: true, .. } = builder.config.cmd {
118 let mut cargo = builder.cargo(
123 cargo_subcommand(builder.kind),
125 std_cargo(builder, target, compiler.stage, &mut cargo);
126 cargo.arg("--all-targets");
128 // Explicitly pass -p for all dependencies krates -- this will force cargo
129 // to also check the tests/benches/examples for these crates, rather
130 // than just the leaf crate.
131 for krate in builder.in_tree_crates("test", Some(target)) {
132 cargo.arg("-p").arg(krate.name);
135 builder.info(&format!(
136 "Checking stage{} std test/bench/example targets ({} -> {})",
137 builder.top_stage, &compiler.host, target
143 &libstd_test_stamp(builder, compiler, target),
151 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
153 pub target: TargetSelection,
156 impl Step for Rustc {
158 const ONLY_HOSTS: bool = true;
159 const DEFAULT: bool = true;
161 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
162 run.all_krates("rustc-main")
165 fn make_run(run: RunConfig<'_>) {
166 run.builder.ensure(Rustc { target: run.target });
169 /// Builds the compiler.
171 /// This will build the compiler for a particular stage of the build using
172 /// the `compiler` targeting the `target` architecture. The artifacts
173 /// created will also be linked into the sysroot directory.
174 fn run(self, builder: &Builder<'_>) {
175 let compiler = builder.compiler(builder.top_stage, builder.config.build);
176 let target = self.target;
178 if compiler.stage != 0 {
179 // If we're not in stage 0, then we won't have a std from the beta
180 // compiler around. That means we need to make sure there's one in
181 // the sysroot for the compiler to find. Otherwise, we're going to
182 // fail when building crates that need to generate code (e.g., build
183 // scripts and their dependencies).
184 builder.ensure(crate::compile::Std { target: compiler.host, compiler });
185 builder.ensure(crate::compile::Std { target, compiler });
187 builder.ensure(Std { target });
190 let mut cargo = builder.cargo(
195 cargo_subcommand(builder.kind),
197 rustc_cargo(builder, &mut cargo, target);
198 if let Subcommand::Check { all_targets: true, .. } = builder.config.cmd {
199 cargo.arg("--all-targets");
202 // Explicitly pass -p for all compiler krates -- this will force cargo
203 // to also check the tests/benches/examples for these crates, rather
204 // than just the leaf crate.
205 for krate in builder.in_tree_crates("rustc-main", Some(target)) {
206 cargo.arg("-p").arg(krate.name);
209 builder.info(&format!(
210 "Checking stage{} compiler artifacts ({} -> {})",
211 builder.top_stage, &compiler.host, target
217 &librustc_stamp(builder, compiler, target),
222 let libdir = builder.sysroot_libdir(compiler, target);
223 let hostdir = builder.sysroot_libdir(compiler, compiler.host);
224 add_to_sysroot(&builder, &libdir, &hostdir, &librustc_stamp(builder, compiler, target));
228 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
229 pub struct CodegenBackend {
230 pub target: TargetSelection,
231 pub backend: Interned<String>,
234 impl Step for CodegenBackend {
236 const ONLY_HOSTS: bool = true;
237 const DEFAULT: bool = true;
239 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
240 run.paths(&["compiler/rustc_codegen_cranelift", "rustc_codegen_cranelift"])
243 fn make_run(run: RunConfig<'_>) {
244 for &backend in &[INTERNER.intern_str("cranelift")] {
245 run.builder.ensure(CodegenBackend { target: run.target, backend });
249 fn run(self, builder: &Builder<'_>) {
250 let compiler = builder.compiler(builder.top_stage, builder.config.build);
251 let target = self.target;
252 let backend = self.backend;
254 builder.ensure(Rustc { target });
256 let mut cargo = builder.cargo(
259 SourceType::Submodule,
261 cargo_subcommand(builder.kind),
264 .arg("--manifest-path")
265 .arg(builder.src.join(format!("compiler/rustc_codegen_{}/Cargo.toml", backend)));
266 rustc_cargo_env(builder, &mut cargo, target);
268 builder.info(&format!(
269 "Checking stage{} {} artifacts ({} -> {})",
270 builder.top_stage, backend, &compiler.host.triple, target.triple
277 &codegen_backend_stamp(builder, compiler, target, backend),
284 macro_rules! tool_check_step {
285 ($name:ident, $path:literal, $($alias:literal, )* $source_type:path $(, $default:literal )?) => {
286 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
288 pub target: TargetSelection,
291 impl Step for $name {
293 const ONLY_HOSTS: bool = true;
294 // don't ever check out-of-tree tools by default, they'll fail when toolstate is broken
295 const DEFAULT: bool = matches!($source_type, SourceType::InTree) $( && $default )?;
297 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
298 run.paths(&[ $path, $($alias),* ])
301 fn make_run(run: RunConfig<'_>) {
302 run.builder.ensure($name { target: run.target });
305 fn run(self, builder: &Builder<'_>) {
306 let compiler = builder.compiler(builder.top_stage, builder.config.build);
307 let target = self.target;
309 builder.ensure(Rustc { target });
311 let mut cargo = prepare_tool_cargo(
316 cargo_subcommand(builder.kind),
322 if let Subcommand::Check { all_targets: true, .. } = builder.config.cmd {
323 cargo.arg("--all-targets");
326 // Enable internal lints for clippy and rustdoc
327 // NOTE: this doesn't enable lints for any other tools unless they explicitly add `#![warn(rustc::internal)]`
328 // See https://github.com/rust-lang/rust/pull/80573#issuecomment-754010776
329 cargo.rustflag("-Zunstable-options");
331 builder.info(&format!(
332 "Checking stage{} {} artifacts ({} -> {})",
334 stringify!($name).to_lowercase(),
335 &compiler.host.triple,
342 &stamp(builder, compiler, target),
347 /// Cargo's output path in a given stage, compiled by a particular
348 /// compiler for the specified target.
350 builder: &Builder<'_>,
352 target: TargetSelection,
355 .cargo_out(compiler, Mode::ToolRustc, target)
356 .join(format!(".{}-check.stamp", stringify!($name).to_lowercase()))
363 tool_check_step!(Rustdoc, "src/tools/rustdoc", "src/librustdoc", SourceType::InTree);
364 // Clippy and Rustfmt are hybrids. They are external tools, but use a git subtree instead
365 // of a submodule. Since the SourceType only drives the deny-warnings
366 // behavior, treat it as in-tree so that any new warnings in clippy will be
368 tool_check_step!(Clippy, "src/tools/clippy", SourceType::InTree);
369 tool_check_step!(Miri, "src/tools/miri", SourceType::Submodule);
370 tool_check_step!(Rls, "src/tools/rls", SourceType::Submodule);
371 tool_check_step!(Rustfmt, "src/tools/rustfmt", SourceType::InTree);
373 tool_check_step!(Bootstrap, "src/bootstrap", SourceType::InTree, false);
375 /// Cargo's output path for the standard library in a given stage, compiled
376 /// by a particular compiler for the specified target.
377 fn libstd_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
378 builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check.stamp")
381 /// Cargo's output path for the standard library in a given stage, compiled
382 /// by a particular compiler for the specified target.
383 fn libstd_test_stamp(
384 builder: &Builder<'_>,
386 target: TargetSelection,
388 builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check-test.stamp")
391 /// Cargo's output path for librustc in a given stage, compiled by a particular
392 /// compiler for the specified target.
393 fn librustc_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf {
394 builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc-check.stamp")
397 /// Cargo's output path for librustc_codegen_llvm in a given stage, compiled by a particular
398 /// compiler for the specified target and backend.
399 fn codegen_backend_stamp(
400 builder: &Builder<'_>,
402 target: TargetSelection,
403 backend: Interned<String>,
406 .cargo_out(compiler, Mode::Codegen, target)
407 .join(format!(".librustc_codegen_{}-check.stamp", backend))