diff --git a/src/bootstrap/defaults/bootstrap.library.toml b/src/bootstrap/defaults/bootstrap.library.toml index 6a867093b781d..24ff87191d68b 100644 --- a/src/bootstrap/defaults/bootstrap.library.toml +++ b/src/bootstrap/defaults/bootstrap.library.toml @@ -1,7 +1,6 @@ # These defaults are meant for contributors to the standard library and documentation. [build] bench-stage = 1 -check-stage = 1 test-stage = 1 [rust] diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 567416d079b12..9f12059d4eec0 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -1,18 +1,22 @@ //! Implementation of compiling the compiler and standard library, in "check"-based modes. +use build_helper::exit; + use crate::core::build_steps::compile::{ add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, std_crates_for_run_make, }; use crate::core::build_steps::tool::{COMPILETEST_ALLOW_FEATURES, SourceType, prepare_tool_cargo}; use crate::core::builder::{ - self, Alias, Builder, Kind, RunConfig, ShouldRun, Step, crate_description, + self, Alias, Builder, Kind, RunConfig, ShouldRun, Step, StepMetadata, crate_description, }; use crate::core::config::TargetSelection; use crate::utils::build_stamp::{self, BuildStamp}; -use crate::{Mode, Subcommand}; +use crate::{Compiler, Mode, Subcommand}; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Std { + /// Compiler that will check this std. + pub build_compiler: Compiler, pub target: TargetSelection, /// Whether to build only a subset of crates. /// @@ -20,16 +24,13 @@ pub struct Std { /// /// [`compile::Rustc`]: crate::core::build_steps::compile::Rustc crates: Vec, - /// Never use this from outside calls. It is intended for internal use only within `check::Std::make_run` - /// and `check::Std::run`. - custom_stage: Option, } impl Std { const CRATE_OR_DEPS: &[&str] = &["sysroot", "coretests", "alloctests"]; - pub fn new(target: TargetSelection) -> Self { - Self { target, crates: vec![], custom_stage: None } + pub fn new(build_compiler: Compiler, target: TargetSelection) -> Self { + Self { build_compiler, target, crates: vec![] } } } @@ -48,14 +49,11 @@ impl Step for Std { fn make_run(run: RunConfig<'_>) { let crates = std_crates_for_run_make(&run); - - let stage = if run.builder.config.is_explicit_stage() || run.builder.top_stage >= 1 { - run.builder.top_stage - } else { - 1 - }; - - run.builder.ensure(Std { target: run.target, crates, custom_stage: Some(stage) }); + run.builder.ensure(Std { + build_compiler: prepare_compiler_for_check(run.builder, run.target, Mode::Std), + target: run.target, + crates, + }); } fn run(self, builder: &Builder<'_>) { @@ -66,40 +64,20 @@ impl Step for Std { return; } - let stage = self.custom_stage.unwrap_or(builder.top_stage); - + let build_compiler = self.build_compiler; + let stage = build_compiler.stage; let target = self.target; - let compiler = builder.compiler(stage, builder.config.host_target); - - if stage == 0 { - let mut is_explicitly_called = - builder.paths.iter().any(|p| p.starts_with("library") || p.starts_with("std")); - - if !is_explicitly_called { - for c in Std::CRATE_OR_DEPS { - is_explicitly_called = builder.paths.iter().any(|p| p.starts_with(c)); - } - } - - if is_explicitly_called { - eprintln!("WARNING: stage 0 std is precompiled and does nothing during `x check`."); - } - - // Reuse the stage0 libstd - builder.std(compiler, target); - return; - } let mut cargo = builder::Cargo::new( builder, - compiler, + build_compiler, Mode::Std, SourceType::InTree, target, Kind::Check, ); - std_cargo(builder, target, compiler.stage, &mut cargo); + std_cargo(builder, target, stage, &mut cargo); if matches!(builder.config.cmd, Subcommand::Fix) { // By default, cargo tries to fix all targets. Tell it not to fix tests until we've added `test` to the sysroot. cargo.arg("--lib"); @@ -115,16 +93,9 @@ impl Step for Std { Some(stage), ); - let stamp = build_stamp::libstd_stamp(builder, compiler, target).with_prefix("check"); + let stamp = build_stamp::libstd_stamp(builder, build_compiler, target).with_prefix("check"); run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); - // We skip populating the sysroot in non-zero stage because that'll lead - // to rlib/rmeta conflicts if std gets built during this session. - if compiler.stage == 0 { - let libdir = builder.sysroot_target_libdir(compiler, target); - let hostdir = builder.sysroot_target_libdir(compiler, compiler.host); - add_to_sysroot(builder, &libdir, &hostdir, &stamp); - } drop(_guard); // don't check test dependencies if we haven't built libtest @@ -140,21 +111,14 @@ impl Step for Std { // Currently only the "libtest" tree of crates does this. let mut cargo = builder::Cargo::new( builder, - compiler, + build_compiler, Mode::Std, SourceType::InTree, target, Kind::Check, ); - // If we're not in stage 0, tests and examples will fail to compile - // from `core` definitions being loaded from two different `libcore` - // .rmeta and .rlib files. - if compiler.stage == 0 { - cargo.arg("--all-targets"); - } - - std_cargo(builder, target, compiler.stage, &mut cargo); + std_cargo(builder, target, build_compiler.stage, &mut cargo); // Explicitly pass -p for all dependencies krates -- this will force cargo // to also check the tests/benches/examples for these crates, rather @@ -163,14 +127,23 @@ impl Step for Std { cargo.arg("-p").arg(krate); } - let stamp = build_stamp::libstd_stamp(builder, compiler, target).with_prefix("check-test"); + let stamp = + build_stamp::libstd_stamp(builder, build_compiler, target).with_prefix("check-test"); let _guard = builder.msg_check("library test/bench/example targets", target, Some(stage)); run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); } + + fn metadata(&self) -> Option { + Some(StepMetadata::check("std", self.target).built_by(self.build_compiler)) + } } +/// Checks rustc using `build_compiler` and copies the built +/// .rmeta files into the sysroot of `build_compiler`. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Rustc { + /// Compiler that will check this rustc. + pub build_compiler: Compiler, pub target: TargetSelection, /// Whether to build only a subset of crates. /// @@ -181,13 +154,13 @@ pub struct Rustc { } impl Rustc { - pub fn new(target: TargetSelection, builder: &Builder<'_>) -> Self { + pub fn new(builder: &Builder<'_>, build_compiler: Compiler, target: TargetSelection) -> Self { let crates = builder .in_tree_crates("rustc-main", Some(target)) .into_iter() .map(|krate| krate.name.to_string()) .collect(); - Self { target, crates } + Self { build_compiler, target, crates } } } @@ -202,40 +175,41 @@ impl Step for Rustc { fn make_run(run: RunConfig<'_>) { let crates = run.make_run_crates(Alias::Compiler); - run.builder.ensure(Rustc { target: run.target, crates }); + run.builder.ensure(Rustc { + target: run.target, + build_compiler: prepare_compiler_for_check(run.builder, run.target, Mode::Rustc), + crates, + }); } - /// Builds the compiler. + /// Check the compiler. /// - /// This will build the compiler for a particular stage of the build using + /// This will check the compiler for a particular stage of the build using /// the `compiler` targeting the `target` architecture. The artifacts /// created will also be linked into the sysroot directory. fn run(self, builder: &Builder<'_>) { - let compiler = builder.compiler(builder.top_stage, builder.config.host_target); + let build_compiler = self.build_compiler; let target = self.target; - if compiler.stage != 0 { - // If we're not in stage 0, then we won't have a std from the beta - // compiler around. That means we need to make sure there's one in - // the sysroot for the compiler to find. Otherwise, we're going to - // fail when building crates that need to generate code (e.g., build - // scripts and their dependencies). - builder.std(compiler, compiler.host); - builder.std(compiler, target); - } else { - builder.ensure(Std::new(target)); - } + // Build host std for compiling build scripts + builder.std(build_compiler, build_compiler.host); + + // Build target std so that the checked rustc can link to it during the check + // FIXME: maybe we can a way to only do a check of std here? + // But for that we would have to copy the stdlib rmetas to the sysroot of the build + // compiler, which conflicts with std rlibs, if we also build std. + builder.std(build_compiler, target); let mut cargo = builder::Cargo::new( builder, - compiler, + build_compiler, Mode::Rustc, SourceType::InTree, target, Kind::Check, ); - rustc_cargo(builder, &mut cargo, target, &compiler, &self.crates); + rustc_cargo(builder, &mut cargo, target, &build_compiler, &self.crates); // Explicitly pass -p for all compiler crates -- this will force cargo // to also check the tests/benches/examples for these crates, rather @@ -250,18 +224,66 @@ impl Step for Rustc { None, ); - let stamp = build_stamp::librustc_stamp(builder, compiler, target).with_prefix("check"); + let stamp = + build_stamp::librustc_stamp(builder, build_compiler, target).with_prefix("check"); run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); - let libdir = builder.sysroot_target_libdir(compiler, target); - let hostdir = builder.sysroot_target_libdir(compiler, compiler.host); + let libdir = builder.sysroot_target_libdir(build_compiler, target); + let hostdir = builder.sysroot_target_libdir(build_compiler, build_compiler.host); add_to_sysroot(builder, &libdir, &hostdir, &stamp); } + + fn metadata(&self) -> Option { + Some(StepMetadata::check("rustc", self.target).built_by(self.build_compiler)) + } } +/// Prepares a compiler that will check something with the given `mode`. +fn prepare_compiler_for_check( + builder: &Builder<'_>, + target: TargetSelection, + mode: Mode, +) -> Compiler { + let host = builder.host_target; + match mode { + Mode::ToolBootstrap => builder.compiler(0, host), + Mode::ToolStd => { + // A small number of tools rely on in-tree standard + // library crates (e.g. compiletest needs libtest). + let build_compiler = builder.compiler(builder.top_stage, host); + builder.std(build_compiler, host); + builder.std(build_compiler, target); + build_compiler + } + Mode::ToolRustc | Mode::Codegen => { + // When checking tool stage N, we check it with compiler stage N-1 + let build_compiler = builder.compiler(builder.top_stage - 1, host); + builder.ensure(Rustc::new(builder, build_compiler, target)); + build_compiler + } + Mode::Rustc => { + if builder.top_stage < 2 && host != target { + eprintln!("Cannot do a cross-compilation check of rustc on stage 1, use stage 2"); + exit!(1); + } + + // When checking the stage N compiler, we want to do it with the stage N-1 compiler + builder.compiler(builder.top_stage - 1, host) + } + Mode::Std => { + // When checking std stage N, we want to do it with the stage N compiler + // Note: we don't need to build the host stdlib here, because when compiling std, the + // stage 0 stdlib is used to compile build scripts and proc macros. + builder.compiler(builder.top_stage, host) + } + } +} + +/// Checks a single codegen backend. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct CodegenBackend { + pub build_compiler: Compiler, pub target: TargetSelection, pub backend: &'static str, } @@ -276,8 +298,10 @@ impl Step for CodegenBackend { } fn make_run(run: RunConfig<'_>) { + // FIXME: only check the backend(s) that were actually selected in run.paths + let build_compiler = prepare_compiler_for_check(run.builder, run.target, Mode::Codegen); for &backend in &["cranelift", "gcc"] { - run.builder.ensure(CodegenBackend { target: run.target, backend }); + run.builder.ensure(CodegenBackend { build_compiler, target: run.target, backend }); } } @@ -288,15 +312,13 @@ impl Step for CodegenBackend { return; } - let compiler = builder.compiler(builder.top_stage, builder.config.host_target); + let build_compiler = self.build_compiler; let target = self.target; let backend = self.backend; - builder.ensure(Rustc::new(target, builder)); - let mut cargo = builder::Cargo::new( builder, - compiler, + build_compiler, Mode::Codegen, SourceType::InTree, target, @@ -306,19 +328,25 @@ impl Step for CodegenBackend { cargo .arg("--manifest-path") .arg(builder.src.join(format!("compiler/rustc_codegen_{backend}/Cargo.toml"))); - rustc_cargo_env(builder, &mut cargo, target, compiler.stage); + rustc_cargo_env(builder, &mut cargo, target, build_compiler.stage); - let _guard = builder.msg_check(backend, target, None); + let _guard = builder.msg_check(&format!("rustc_codegen_{backend}"), target, None); - let stamp = build_stamp::codegen_backend_stamp(builder, compiler, target, backend) + let stamp = build_stamp::codegen_backend_stamp(builder, build_compiler, target, backend) .with_prefix("check"); run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); } + + fn metadata(&self) -> Option { + Some(StepMetadata::check(self.backend, self.target).built_by(self.build_compiler)) + } } +/// Checks Rust analyzer that links to .rmetas from a checked rustc. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct RustAnalyzer { + pub build_compiler: Compiler, pub target: TargetSelection, } @@ -339,18 +367,17 @@ impl Step for RustAnalyzer { } fn make_run(run: RunConfig<'_>) { - run.builder.ensure(RustAnalyzer { target: run.target }); + let build_compiler = prepare_compiler_for_check(run.builder, run.target, Mode::ToolRustc); + run.builder.ensure(RustAnalyzer { build_compiler, target: run.target }); } fn run(self, builder: &Builder<'_>) { - let compiler = builder.compiler(builder.top_stage, builder.config.host_target); + let build_compiler = self.build_compiler; let target = self.target; - builder.ensure(Rustc::new(target, builder)); - let mut cargo = prepare_tool_cargo( builder, - compiler, + build_compiler, Mode::ToolRustc, target, builder.kind, @@ -367,12 +394,16 @@ impl Step for RustAnalyzer { // Cargo's output path in a given stage, compiled by a particular // compiler for the specified target. - let stamp = BuildStamp::new(&builder.cargo_out(compiler, Mode::ToolRustc, target)) + let stamp = BuildStamp::new(&builder.cargo_out(build_compiler, Mode::ToolRustc, target)) .with_prefix("rust-analyzer-check"); let _guard = builder.msg_check("rust-analyzer artifacts", target, None); run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); } + + fn metadata(&self) -> Option { + Some(StepMetadata::check("rust-analyzer", self.target).built_by(self.build_compiler)) + } } /// Compiletest is implicitly "checked" when it gets built in order to run tests, @@ -401,19 +432,11 @@ impl Step for Compiletest { } else { Mode::ToolStd }; - - let compiler = builder.compiler( - if mode == Mode::ToolBootstrap { 0 } else { builder.top_stage }, - builder.config.host_target, - ); - - if mode != Mode::ToolBootstrap { - builder.ensure(Rustc::new(self.target, builder)); - } + let build_compiler = prepare_compiler_for_check(builder, self.target, mode); let mut cargo = prepare_tool_cargo( builder, - compiler, + build_compiler, mode, self.target, builder.kind, @@ -426,12 +449,16 @@ impl Step for Compiletest { cargo.arg("--all-targets"); - let stamp = BuildStamp::new(&builder.cargo_out(compiler, mode, self.target)) + let stamp = BuildStamp::new(&builder.cargo_out(build_compiler, mode, self.target)) .with_prefix("compiletest-check"); let _guard = builder.msg_check("compiletest artifacts", self.target, None); run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); } + + fn metadata(&self) -> Option { + Some(StepMetadata::check("compiletest", self.target)) + } } macro_rules! tool_check_step { @@ -440,12 +467,14 @@ macro_rules! tool_check_step { // The part of this path after the final '/' is also used as a display name. path: $path:literal $(, alt_path: $alt_path:literal )* + , mode: $mode:path $(, default: $default:literal )? $( , )? } ) => { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct $name { + pub build_compiler: Compiler, pub target: TargetSelection, } @@ -460,12 +489,18 @@ macro_rules! tool_check_step { } fn make_run(run: RunConfig<'_>) { - run.builder.ensure($name { target: run.target }); + let target = run.target; + let build_compiler = prepare_compiler_for_check(run.builder, target, $mode); + run.builder.ensure($name { target, build_compiler }); } fn run(self, builder: &Builder<'_>) { - let Self { target } = self; - run_tool_check_step(builder, target, stringify!($name), $path); + let Self { target, build_compiler } = self; + run_tool_check_step(builder, build_compiler, target, $path, $mode); + } + + fn metadata(&self) -> Option { + Some(StepMetadata::check(stringify!($name), self.target).built_by(self.build_compiler)) } } } @@ -474,19 +509,17 @@ macro_rules! tool_check_step { /// Used by the implementation of `Step::run` in `tool_check_step!`. fn run_tool_check_step( builder: &Builder<'_>, + build_compiler: Compiler, target: TargetSelection, - step_type_name: &str, path: &str, + mode: Mode, ) { let display_name = path.rsplit('/').next().unwrap(); - let compiler = builder.compiler(builder.top_stage, builder.config.host_target); - - builder.ensure(Rustc::new(target, builder)); let mut cargo = prepare_tool_cargo( builder, - compiler, - Mode::ToolRustc, + build_compiler, + mode, target, builder.kind, path, @@ -498,97 +531,59 @@ fn run_tool_check_step( &[], ); + // FIXME: check bootstrap doesn't currently work with --all-targets cargo.arg("--all-targets"); - let stamp = BuildStamp::new(&builder.cargo_out(compiler, Mode::ToolRustc, target)) - .with_prefix(&format!("{}-check", step_type_name.to_lowercase())); + let stamp = BuildStamp::new(&builder.cargo_out(build_compiler, mode, target)) + .with_prefix(&format!("{display_name}-check")); + + let stage = match mode { + // Mode::ToolRustc is included here because of how msg_sysroot_tool prints stages + Mode::Std | Mode::ToolRustc => build_compiler.stage, + _ => build_compiler.stage + 1, + }; - let _guard = builder.msg_check(format!("{display_name} artifacts"), target, None); + let _guard = + builder.msg_tool(builder.kind, mode, display_name, stage, &build_compiler.host, &target); run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); } -tool_check_step!(Rustdoc { path: "src/tools/rustdoc", alt_path: "src/librustdoc" }); +tool_check_step!(Rustdoc { + path: "src/tools/rustdoc", + alt_path: "src/librustdoc", + mode: Mode::ToolRustc +}); // Clippy, miri and Rustfmt are hybrids. They are external tools, but use a git subtree instead // of a submodule. Since the SourceType only drives the deny-warnings // behavior, treat it as in-tree so that any new warnings in clippy will be // rejected. -tool_check_step!(Clippy { path: "src/tools/clippy" }); -tool_check_step!(Miri { path: "src/tools/miri" }); -tool_check_step!(CargoMiri { path: "src/tools/miri/cargo-miri" }); -tool_check_step!(Rustfmt { path: "src/tools/rustfmt" }); -tool_check_step!(MiroptTestTools { path: "src/tools/miropt-test-tools" }); -tool_check_step!(TestFloatParse { path: "src/tools/test-float-parse" }); -tool_check_step!(FeaturesStatusDump { path: "src/tools/features-status-dump" }); - -tool_check_step!(Bootstrap { path: "src/bootstrap", default: false }); +tool_check_step!(Clippy { path: "src/tools/clippy", mode: Mode::ToolRustc }); +tool_check_step!(Miri { path: "src/tools/miri", mode: Mode::ToolRustc }); +tool_check_step!(CargoMiri { path: "src/tools/miri/cargo-miri", mode: Mode::ToolRustc }); +tool_check_step!(Rustfmt { path: "src/tools/rustfmt", mode: Mode::ToolRustc }); +tool_check_step!(MiroptTestTools { + path: "src/tools/miropt-test-tools", + mode: Mode::ToolBootstrap +}); +// We want to test the local std +tool_check_step!(TestFloatParse { path: "src/tools/test-float-parse", mode: Mode::ToolStd }); +tool_check_step!(FeaturesStatusDump { + path: "src/tools/features-status-dump", + mode: Mode::ToolBootstrap +}); + +tool_check_step!(Bootstrap { path: "src/bootstrap", mode: Mode::ToolBootstrap, default: false }); // `run-make-support` will be built as part of suitable run-make compiletest test steps, but support // check to make it easier to work on. -tool_check_step!(RunMakeSupport { path: "src/tools/run-make-support", default: false }); - -/// Check step for the `coverage-dump` bootstrap tool. The coverage-dump tool -/// is used internally by coverage tests. -/// -/// FIXME(Zalathar): This is temporarily separate from the other tool check -/// steps so that it can use the stage 0 compiler instead of `top_stage`, -/// without introducing conflicts with the stage 0 redesign (#119899). -/// -/// After the stage 0 redesign lands, we can look into using the stage 0 -/// compiler to check all bootstrap tools (#139170). -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub(crate) struct CoverageDump; - -impl CoverageDump { - const PATH: &str = "src/tools/coverage-dump"; -} - -impl Step for CoverageDump { - type Output = (); - - /// Most contributors won't care about coverage-dump, so don't make their - /// check builds slower unless they opt in and check it explicitly. - const DEFAULT: bool = false; - const ONLY_HOSTS: bool = true; - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path(Self::PATH) - } - - fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Self {}); - } - - fn run(self, builder: &Builder<'_>) -> Self::Output { - // Make sure we haven't forgotten any fields, if there are any. - let Self {} = self; - let display_name = "coverage-dump"; - let host = builder.config.host_target; - let target = host; - let mode = Mode::ToolBootstrap; - - let compiler = builder.compiler(0, host); - let cargo = prepare_tool_cargo( - builder, - compiler, - mode, - target, - builder.kind, - Self::PATH, - SourceType::InTree, - &[], - ); - - let stamp = BuildStamp::new(&builder.cargo_out(compiler, mode, target)) - .with_prefix(&format!("{display_name}-check")); - - let _guard = builder.msg_tool( - builder.kind, - mode, - display_name, - compiler.stage, - &compiler.host, - &target, - ); - run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); - } -} +tool_check_step!(RunMakeSupport { + path: "src/tools/run-make-support", + mode: Mode::ToolBootstrap, + default: false +}); + +tool_check_step!(CoverageDump { + path: "src/tools/coverage-dump", + mode: Mode::ToolBootstrap, + default: false +}); diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index 1e44b5b67a44c..a0371eb71556b 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -215,7 +215,7 @@ impl Step for Rustc { builder.std(compiler, compiler.host); builder.std(compiler, target); } else { - builder.ensure(check::Std::new(target)); + builder.ensure(check::Std::new(compiler, target)); } } @@ -287,7 +287,7 @@ macro_rules! lint_any { let target = self.target; if !builder.download_rustc() { - builder.ensure(check::Rustc::new(target, builder)); + builder.ensure(check::Rustc::new(builder, compiler, target)); }; let cargo = prepare_tool_cargo( diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 8200e1541692a..5c667e4d62615 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -306,11 +306,7 @@ impl Step for Std { } fn metadata(&self) -> Option { - Some( - StepMetadata::build("std", self.target) - .built_by(self.compiler) - .stage(self.compiler.stage), - ) + Some(StepMetadata::build("std", self.target).built_by(self.compiler)) } } @@ -1186,11 +1182,7 @@ impl Step for Rustc { } fn metadata(&self) -> Option { - Some( - StepMetadata::build("rustc", self.target) - .built_by(self.build_compiler) - .stage(self.build_compiler.stage + 1), - ) + Some(StepMetadata::build("rustc", self.target).built_by(self.build_compiler)) } } diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 83c0525d7c421..78a55439142cb 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -77,7 +77,7 @@ impl Builder<'_> { *target, ), // doesn't depend on compiler, same as host compiler - _ => self.msg(Kind::Build, build_stage, format_args!("tool {tool}"), *host, *target), + _ => self.msg(kind, build_stage, format_args!("tool {tool}"), *host, *target), } } } @@ -1195,7 +1195,6 @@ macro_rules! tool_extended { Some( StepMetadata::build($tool_name, self.target) .built_by(self.compiler.with_stage(self.compiler.stage.saturating_sub(1))) - .stage(self.compiler.stage) ) } } diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 7cb7866953a8e..d0a3e0624189e 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -154,6 +154,10 @@ impl StepMetadata { Self::new(name, target, Kind::Build) } + pub fn check(name: &'static str, target: TargetSelection) -> Self { + Self::new(name, target, Kind::Check) + } + pub fn doc(name: &'static str, target: TargetSelection) -> Self { Self::new(name, target, Kind::Doc) } @@ -179,6 +183,12 @@ impl StepMetadata { self.stage = Some(stage); self } + + pub fn get_stage(&self) -> Option { + self.stage.or(self + .built_by + .map(|compiler| if self.name == "std" { compiler.stage } else { compiler.stage + 1 })) + } } pub struct RunConfig<'a> { diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 8adf93ea52889..4b6fc9620887f 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -863,7 +863,7 @@ mod snapshot { insta::assert_snapshot!( ctx.config("build") .path("opt-dist") - .render_steps(), @"[build] rustc 0 -> OptimizedDist "); + .render_steps(), @"[build] rustc 0 -> OptimizedDist 1 "); } #[test] @@ -880,7 +880,7 @@ mod snapshot { ctx.config("build") .path("opt-dist") .stage(1) - .render_steps(), @"[build] rustc 0 -> OptimizedDist "); + .render_steps(), @"[build] rustc 0 -> OptimizedDist 1 "); } #[test] @@ -890,7 +890,7 @@ mod snapshot { ctx.config("build") .path("opt-dist") .stage(2) - .render_steps(), @"[build] rustc 0 -> OptimizedDist "); + .render_steps(), @"[build] rustc 0 -> OptimizedDist 1 "); } #[test] @@ -984,8 +984,8 @@ mod snapshot { ctx .config("dist") .render_steps(), @r" - [build] rustc 0 -> UnstableBookGen - [build] rustc 0 -> Rustbook + [build] rustc 0 -> UnstableBookGen 1 + [build] rustc 0 -> Rustbook 1 [build] llvm [build] rustc 0 -> rustc 1 [build] rustc 1 -> std 1 @@ -993,14 +993,14 @@ mod snapshot { [build] rustdoc 1 [doc] std 2 [build] rustc 2 -> std 2 - [build] rustc 0 -> LintDocs - [build] rustc 0 -> RustInstaller + [build] rustc 0 -> LintDocs 1 + [build] rustc 0 -> RustInstaller 1 [dist] docs [doc] std 2 [dist] mingw - [build] rustc 0 -> GenerateCopyright + [build] rustc 0 -> GenerateCopyright 1 [dist] rustc - [dist] rustc 1 -> std + [dist] rustc 1 -> std 1 [dist] src <> " ); @@ -1014,25 +1014,25 @@ mod snapshot { .config("dist") .args(&["--set", "build.extended=true"]) .render_steps(), @r" - [build] rustc 0 -> UnstableBookGen - [build] rustc 0 -> Rustbook + [build] rustc 0 -> UnstableBookGen 1 + [build] rustc 0 -> Rustbook 1 [build] llvm [build] rustc 0 -> rustc 1 - [build] rustc 0 -> WasmComponentLd + [build] rustc 0 -> WasmComponentLd 1 [build] rustc 1 -> std 1 [build] rustc 1 -> rustc 2 - [build] rustc 1 -> WasmComponentLd + [build] rustc 1 -> WasmComponentLd 2 [build] rustdoc 1 [doc] std 2 [build] rustc 2 -> std 2 - [build] rustc 0 -> LintDocs - [build] rustc 0 -> RustInstaller + [build] rustc 0 -> LintDocs 1 + [build] rustc 0 -> RustInstaller 1 [dist] docs [doc] std 2 [dist] mingw - [build] rustc 0 -> GenerateCopyright + [build] rustc 0 -> GenerateCopyright 1 [dist] rustc - [dist] rustc 1 -> std + [dist] rustc 1 -> std 1 [dist] src <> [build] rustc 0 -> rustfmt 1 [build] rustc 0 -> cargo-fmt 1 @@ -1052,8 +1052,8 @@ mod snapshot { .hosts(&[&host_target()]) .targets(&[&host_target(), TEST_TRIPLE_1]) .render_steps(), @r" - [build] rustc 0 -> UnstableBookGen - [build] rustc 0 -> Rustbook + [build] rustc 0 -> UnstableBookGen 1 + [build] rustc 0 -> Rustbook 1 [build] llvm [build] rustc 0 -> rustc 1 [build] rustc 1 -> std 1 @@ -1062,19 +1062,19 @@ mod snapshot { [doc] std 2 [doc] std 2 [build] rustc 2 -> std 2 - [build] rustc 0 -> LintDocs - [build] rustc 0 -> RustInstaller + [build] rustc 0 -> LintDocs 1 + [build] rustc 0 -> RustInstaller 1 [dist] docs [dist] docs [doc] std 2 [doc] std 2 [dist] mingw [dist] mingw - [build] rustc 0 -> GenerateCopyright + [build] rustc 0 -> GenerateCopyright 1 [dist] rustc - [dist] rustc 1 -> std + [dist] rustc 1 -> std 1 [build] rustc 2 -> std 2 - [dist] rustc 2 -> std + [dist] rustc 2 -> std 2 [dist] src <> " ); @@ -1089,8 +1089,8 @@ mod snapshot { .hosts(&[&host_target(), TEST_TRIPLE_1]) .targets(&[&host_target()]) .render_steps(), @r" - [build] rustc 0 -> UnstableBookGen - [build] rustc 0 -> Rustbook + [build] rustc 0 -> UnstableBookGen 1 + [build] rustc 0 -> Rustbook 1 [build] llvm [build] rustc 0 -> rustc 1 [build] rustc 1 -> std 1 @@ -1098,20 +1098,20 @@ mod snapshot { [build] rustdoc 1 [doc] std 2 [build] rustc 2 -> std 2 - [build] rustc 0 -> LintDocs + [build] rustc 0 -> LintDocs 1 [build] rustc 1 -> std 1 [build] rustc 2 -> std 2 - [build] rustc 0 -> RustInstaller + [build] rustc 0 -> RustInstaller 1 [dist] docs [doc] std 2 [dist] mingw - [build] rustc 0 -> GenerateCopyright + [build] rustc 0 -> GenerateCopyright 1 [dist] rustc [build] llvm [build] rustc 1 -> rustc 2 [build] rustdoc 1 [dist] rustc - [dist] rustc 1 -> std + [dist] rustc 1 -> std 1 [dist] src <> " ); @@ -1126,8 +1126,8 @@ mod snapshot { .hosts(&[&host_target(), TEST_TRIPLE_1]) .targets(&[&host_target(), TEST_TRIPLE_1]) .render_steps(), @r" - [build] rustc 0 -> UnstableBookGen - [build] rustc 0 -> Rustbook + [build] rustc 0 -> UnstableBookGen 1 + [build] rustc 0 -> Rustbook 1 [build] llvm [build] rustc 0 -> rustc 1 [build] rustc 1 -> std 1 @@ -1136,24 +1136,24 @@ mod snapshot { [doc] std 2 [doc] std 2 [build] rustc 2 -> std 2 - [build] rustc 0 -> LintDocs + [build] rustc 0 -> LintDocs 1 [build] rustc 1 -> std 1 [build] rustc 2 -> std 2 - [build] rustc 0 -> RustInstaller + [build] rustc 0 -> RustInstaller 1 [dist] docs [dist] docs [doc] std 2 [doc] std 2 [dist] mingw [dist] mingw - [build] rustc 0 -> GenerateCopyright + [build] rustc 0 -> GenerateCopyright 1 [dist] rustc [build] llvm [build] rustc 1 -> rustc 2 [build] rustdoc 1 [dist] rustc - [dist] rustc 1 -> std - [dist] rustc 1 -> std + [dist] rustc 1 -> std 1 + [dist] rustc 1 -> std 1 [dist] src <> " ); @@ -1168,8 +1168,8 @@ mod snapshot { .hosts(&[]) .targets(&[TEST_TRIPLE_1]) .render_steps(), @r" - [build] rustc 0 -> UnstableBookGen - [build] rustc 0 -> Rustbook + [build] rustc 0 -> UnstableBookGen 1 + [build] rustc 0 -> Rustbook 1 [build] llvm [build] rustc 0 -> rustc 1 [build] rustc 1 -> std 1 @@ -1177,12 +1177,12 @@ mod snapshot { [build] rustdoc 1 [doc] std 2 [build] rustc 2 -> std 2 - [build] rustc 0 -> RustInstaller + [build] rustc 0 -> RustInstaller 1 [dist] docs [doc] std 2 [dist] mingw [build] rustc 2 -> std 2 - [dist] rustc 2 -> std + [dist] rustc 2 -> std 2 "); } @@ -1198,31 +1198,31 @@ mod snapshot { .targets(&[TEST_TRIPLE_1]) .args(&["--set", "rust.channel=nightly", "--set", "build.extended=true"]) .render_steps(), @r" - [build] rustc 0 -> UnstableBookGen - [build] rustc 0 -> Rustbook + [build] rustc 0 -> UnstableBookGen 1 + [build] rustc 0 -> Rustbook 1 [build] llvm [build] rustc 0 -> rustc 1 - [build] rustc 0 -> WasmComponentLd + [build] rustc 0 -> WasmComponentLd 1 [build] rustc 1 -> std 1 [build] rustc 1 -> rustc 2 - [build] rustc 1 -> WasmComponentLd + [build] rustc 1 -> WasmComponentLd 2 [build] rustdoc 1 [doc] std 2 [build] rustc 2 -> std 2 [build] rustc 1 -> std 1 [build] rustc 2 -> std 2 - [build] rustc 0 -> LintDocs - [build] rustc 0 -> RustInstaller + [build] rustc 0 -> LintDocs 1 + [build] rustc 0 -> RustInstaller 1 [dist] docs [doc] std 2 [dist] mingw [build] llvm [build] rustc 1 -> rustc 2 - [build] rustc 1 -> WasmComponentLd + [build] rustc 1 -> WasmComponentLd 2 [build] rustdoc 1 - [build] rustc 0 -> GenerateCopyright + [build] rustc 0 -> GenerateCopyright 1 [dist] rustc - [dist] rustc 1 -> std + [dist] rustc 1 -> std 1 [dist] src <> [build] rustc 0 -> rustfmt 1 [build] rustc 0 -> cargo-fmt 1 @@ -1233,6 +1233,227 @@ mod snapshot { "); } + #[test] + fn check_compiler_no_explicit_stage() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("compiler") + .render_steps(), @r" + [build] llvm + [check] rustc 0 -> rustc 1 + [check] rustc 0 -> cranelift 1 + [check] rustc 0 -> gcc 1 + "); + + insta::assert_snapshot!( + ctx.config("check") + .path("rustc") + .render_steps(), @r" + [build] llvm + [check] rustc 0 -> rustc 1 + "); + } + + #[test] + #[should_panic] + fn check_compiler_stage_0() { + let ctx = TestCtx::new(); + ctx.config("check").path("compiler").stage(0).run(); + } + + #[test] + fn check_compiler_stage_1() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("compiler") + .stage(1) + .render_steps(), @r" + [build] llvm + [check] rustc 0 -> rustc 1 + [check] rustc 0 -> cranelift 1 + [check] rustc 0 -> gcc 1 + "); + } + + #[test] + fn check_compiler_stage_2() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("compiler") + .stage(2) + .render_steps(), @r" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [check] rustc 1 -> rustc 2 + [check] rustc 1 -> cranelift 2 + [check] rustc 1 -> gcc 2 + "); + } + + #[test] + fn check_library_no_explicit_stage() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("library") + .render_steps(), @r" + [build] llvm + [build] rustc 0 -> rustc 1 + [check] rustc 1 -> std 1 + "); + } + + #[test] + #[should_panic] + fn check_library_stage_0() { + let ctx = TestCtx::new(); + ctx.config("check").path("library").stage(0).run(); + } + + #[test] + fn check_library_stage_1() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("library") + .stage(1) + .render_steps(), @r" + [build] llvm + [build] rustc 0 -> rustc 1 + [check] rustc 1 -> std 1 + "); + } + + #[test] + fn check_library_stage_2() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("library") + .stage(2) + .render_steps(), @r" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustc 1 -> rustc 2 + [check] rustc 2 -> std 2 + "); + } + + #[test] + fn check_miri_no_explicit_stage() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("miri") + .render_steps(), @r" + [build] llvm + [check] rustc 0 -> rustc 1 + [check] rustc 0 -> Miri 1 + "); + } + + #[test] + #[should_panic] + fn check_miri_stage_0() { + let ctx = TestCtx::new(); + ctx.config("check").path("miri").stage(0).run(); + } + + #[test] + fn check_miri_stage_1() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("miri") + .stage(1) + .render_steps(), @r" + [build] llvm + [check] rustc 0 -> rustc 1 + [check] rustc 0 -> Miri 1 + "); + } + + #[test] + fn check_miri_stage_2() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("miri") + .stage(2) + .render_steps(), @r" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [check] rustc 1 -> rustc 2 + [check] rustc 1 -> Miri 2 + "); + } + + #[test] + fn check_compiletest() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("compiletest") + .render_steps(), @"[check] compiletest "); + } + + #[test] + fn check_compiletest_stage1_libtest() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("compiletest") + .args(&["--set", "build.compiletest-use-stage0-libtest=false"]) + .render_steps(), @r" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [check] compiletest + "); + } + + #[test] + fn check_codegen() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("rustc_codegen_cranelift") + .render_steps(), @r" + [build] llvm + [check] rustc 0 -> rustc 1 + [check] rustc 0 -> cranelift 1 + [check] rustc 0 -> gcc 1 + "); + } + + #[test] + fn check_rust_analyzer() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("rust-analyzer") + .render_steps(), @r" + [build] llvm + [check] rustc 0 -> rustc 1 + [check] rustc 0 -> rust-analyzer 1 + "); + } + + #[test] + fn check_bootstrap_tool() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("run-make-support") + .render_steps(), @"[check] rustc 0 -> RunMakeSupport 1 "); + } + #[test] fn test_exclude() { let ctx = TestCtx::new(); @@ -1384,7 +1605,8 @@ fn render_metadata(metadata: &StepMetadata) -> String { if let Some(compiler) = metadata.built_by { write!(record, "{} -> ", render_compiler(compiler)); } - let stage = if let Some(stage) = metadata.stage { format!("{stage} ") } else { "".to_string() }; + let stage = + if let Some(stage) = metadata.get_stage() { format!("{stage} ") } else { "".to_string() }; write!(record, "{} {stage}<{}>", metadata.name, normalize_target(metadata.target)); record } diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index d7decaa8a9804..e72b026ac9e95 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1025,7 +1025,7 @@ impl Config { || bench_stage.is_some(); config.stage = match config.cmd { - Subcommand::Check { .. } => flags_stage.or(check_stage).unwrap_or(0), + Subcommand::Check { .. } => flags_stage.or(check_stage).unwrap_or(1), Subcommand::Clippy { .. } | Subcommand::Fix => flags_stage.or(check_stage).unwrap_or(1), // `download-rustc` only has a speed-up for stage2 builds. Default to stage2 unless explicitly overridden. Subcommand::Doc { .. } => { @@ -1052,9 +1052,16 @@ impl Config { }; // Now check that the selected stage makes sense, and if not, print a warning and end - if let (0, Subcommand::Build) = (config.stage, &config.cmd) { - eprintln!("WARNING: cannot build anything on stage 0. Use at least stage 1."); - exit!(1); + match (config.stage, &config.cmd) { + (0, Subcommand::Build) => { + eprintln!("WARNING: cannot build anything on stage 0. Use at least stage 1."); + exit!(1); + } + (0, Subcommand::Check { .. }) => { + eprintln!("WARNING: cannot check anything on stage 0. Use at least stage 1."); + exit!(1); + } + _ => {} } // CI should always run stage 2 builds, unless it specifically states otherwise diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 7c588cfea8c28..f3e4d137ad1e1 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -431,4 +431,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Warning, summary: "It is no longer possible to `x build` with stage 0. All build commands have to be on stage 1+.", }, + ChangeInfo { + change_id: 143048, + severity: ChangeSeverity::Warning, + summary: "The default check stage has been changed to 1. It is no longer possible to `x check` with stage 0. All check commands have to be on stage 1+.", + }, ]; diff --git a/src/ci/docker/host-x86_64/mingw-check-1/Dockerfile b/src/ci/docker/host-x86_64/mingw-check-1/Dockerfile index c46a2471e75b3..b81db0214a115 100644 --- a/src/ci/docker/host-x86_64/mingw-check-1/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check-1/Dockerfile @@ -45,11 +45,11 @@ COPY host-x86_64/mingw-check-1/validate-toolstate.sh /scripts/ # We also skip the x86_64-unknown-linux-gnu target as it is well-tested by other jobs. ENV SCRIPT \ /scripts/check-default-config-profiles.sh && \ - python3 ../x.py build --stage 1 src/tools/build-manifest && \ + python3 ../x.py build src/tools/build-manifest && \ python3 ../x.py test --stage 0 src/tools/compiletest && \ python3 ../x.py check compiletest --set build.compiletest-use-stage0-libtest=true && \ python3 ../x.py check --stage 1 --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu && \ - python3 ../x.py check --stage 1 --set build.optimized-compiler-builtins=false core alloc std --target=aarch64-unknown-linux-gnu,i686-pc-windows-msvc,i686-unknown-linux-gnu,x86_64-apple-darwin,x86_64-pc-windows-gnu,x86_64-pc-windows-msvc && \ + python3 ../x.py check --set build.optimized-compiler-builtins=false core alloc std --target=aarch64-unknown-linux-gnu,i686-pc-windows-msvc,i686-unknown-linux-gnu,x86_64-apple-darwin,x86_64-pc-windows-gnu,x86_64-pc-windows-msvc && \ /scripts/validate-toolstate.sh && \ reuse --include-submodules lint && \ python3 ../x.py test collect-license-metadata && \