diff options
| author | Jakub Beránek <berykubik@gmail.com> | 2025-07-08 16:18:56 +0200 |
|---|---|---|
| committer | Jakub Beránek <berykubik@gmail.com> | 2025-07-08 16:18:56 +0200 |
| commit | bdead41b65ed10d6c947b20ddb724f1ae59e2b48 (patch) | |
| tree | 05a5849ce18ed88207f14d23da57a06dfc1e8126 /src/bootstrap | |
| parent | 3c9297c845c513a2609dd915ca9346664fe82663 (diff) | |
| parent | 040e2f8b9ff2d76fbe2146d6003e297ed4532088 (diff) | |
Merge ref '040e2f8b9ff2' from rust-lang/rust
Pull recent changes from https://github.com/rust-lang/rust via Josh. Upstream ref: 040e2f8b9ff2d76fbe2146d6003e297ed4532088 Filtered ref: cf4d00a666607e356e410a820ae07eeba28a9b53 This merge was created using https://github.com/rust-lang/josh-sync.
Diffstat (limited to 'src/bootstrap')
28 files changed, 854 insertions, 439 deletions
diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index a6ca699e282..2434a278d55 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -12,6 +12,15 @@ dependencies = [ ] [[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] name = "anstyle" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -62,8 +71,8 @@ dependencies = [ "toml", "tracing", "tracing-chrome", + "tracing-forest", "tracing-subscriber", - "tracing-tree", "walkdir", "windows", "xz2", @@ -450,15 +459,6 @@ dependencies = [ ] [[package]] -name = "nu-ansi-term" -version = "0.50.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] name = "objc2-core-foundation" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -776,6 +776,26 @@ dependencies = [ ] [[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] name = "thread_local" version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -838,6 +858,19 @@ dependencies = [ ] [[package]] +name = "tracing-forest" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee40835db14ddd1e3ba414292272eddde9dad04d3d4b65509656414d1c42592f" +dependencies = [ + "ansi_term", + "smallvec", + "thiserror", + "tracing", + "tracing-subscriber", +] + +[[package]] name = "tracing-log" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -855,7 +888,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ "matchers", - "nu-ansi-term 0.46.0", + "nu-ansi-term", "once_cell", "regex", "sharded-slab", @@ -867,18 +900,6 @@ dependencies = [ ] [[package]] -name = "tracing-tree" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f459ca79f1b0d5f71c54ddfde6debfc59c8b6eeb46808ae492077f739dc7b49c" -dependencies = [ - "nu-ansi-term 0.50.1", - "tracing-core", - "tracing-log", - "tracing-subscriber", -] - -[[package]] name = "typenum" version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 9785a306c9b..073cebdcae2 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -7,7 +7,7 @@ default-run = "bootstrap" [features] build-metrics = ["sysinfo"] -tracing = ["dep:tracing", "dep:tracing-chrome", "dep:tracing-subscriber", "dep:tracing-tree"] +tracing = ["dep:tracing", "dep:tracing-chrome", "dep:tracing-subscriber", "dep:tracing-forest"] [lib] path = "src/lib.rs" @@ -64,7 +64,7 @@ sysinfo = { version = "0.35.0", default-features = false, optional = true, featu tracing = { version = "0.1", optional = true, features = ["attributes"] } tracing-chrome = { version = "0.7", optional = true } tracing-subscriber = { version = "0.3", optional = true, features = ["env-filter", "fmt", "registry", "std"] } -tracing-tree = { version = "0.4.0", optional = true } +tracing-forest = { version = "0.1.6", optional = true, default-features = false, features = ["smallvec", "ansi", "env-filter"] } [target.'cfg(windows)'.dependencies.junction] version = "1.0.0" diff --git a/src/bootstrap/defaults/bootstrap.dist.toml b/src/bootstrap/defaults/bootstrap.dist.toml index f0cb34eb458..9daf9faac14 100644 --- a/src/bootstrap/defaults/bootstrap.dist.toml +++ b/src/bootstrap/defaults/bootstrap.dist.toml @@ -20,7 +20,6 @@ download-ci-llvm = false channel = "auto-detect" # Never download a rustc, distributions must build a fresh compiler. download-rustc = false -lld = true # Build the llvm-bitcode-linker llvm-bitcode-linker = true diff --git a/src/bootstrap/defaults/bootstrap.library.toml b/src/bootstrap/defaults/bootstrap.library.toml index 6a867093b78..3f811402b26 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] @@ -13,7 +12,8 @@ lto = "off" # # If compiler-affecting directories are not modified, use precompiled rustc to speed up # library development by skipping compiler builds. -download-rustc = "if-unchanged" +# FIXME: download-rustc is currently broken: https://github.com/rust-lang/rust/issues/142505 +download-rustc = false [llvm] # Will download LLVM from CI if available on your platform. diff --git a/src/bootstrap/src/bin/main.rs b/src/bootstrap/src/bin/main.rs index 833f8027951..e1862a451f2 100644 --- a/src/bootstrap/src/bin/main.rs +++ b/src/bootstrap/src/bin/main.rs @@ -217,12 +217,11 @@ fn check_version(config: &Config) -> Option<String> { // "tracing", instrument(..))]`. #[cfg(feature = "tracing")] fn setup_tracing() -> impl Drop { + use tracing_forest::ForestLayer; use tracing_subscriber::EnvFilter; use tracing_subscriber::layer::SubscriberExt; let filter = EnvFilter::from_env("BOOTSTRAP_TRACING"); - // cf. <https://docs.rs/tracing-tree/latest/tracing_tree/struct.HierarchicalLayer.html>. - let layer = tracing_tree::HierarchicalLayer::default().with_targets(true).with_indent_amount(2); let mut chrome_layer = tracing_chrome::ChromeLayerBuilder::new().include_args(true); @@ -233,7 +232,8 @@ fn setup_tracing() -> impl Drop { let (chrome_layer, _guard) = chrome_layer.build(); - let registry = tracing_subscriber::registry().with(filter).with(layer).with(chrome_layer); + let registry = + tracing_subscriber::registry().with(filter).with(ForestLayer::default()).with(chrome_layer); tracing::subscriber::set_global_default(registry).unwrap(); _guard diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 567416d079b..0497bae86a1 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -3,16 +3,19 @@ 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; 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 +23,13 @@ pub struct Std { /// /// [`compile::Rustc`]: crate::core::build_steps::compile::Rustc crates: Vec<String>, - /// 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<u32>, } 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 +48,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 +63,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 +92,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 +110,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 +126,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<StepMetadata> { + 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 +153,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 +174,43 @@ 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. + /// + /// If we check a stage 2 compiler, we will have to first build a stage 1 compiler to check it. 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 +225,75 @@ 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<StepMetadata> { + 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 => { + // These tools require the local standard library to be checked + let build_compiler = builder.compiler(builder.top_stage, host); + + // We need to build the host stdlib to check the tool itself. + // We need to build the target stdlib so that the tool can link to it. + builder.std(build_compiler, host); + // We could only check this library in theory, but `check::Std` doesn't copy rmetas + // into `build_compiler`'s sysroot to avoid clashes with `.rlibs`, so we build it + // instead. + builder.std(build_compiler, target); + build_compiler + } + Mode::ToolRustc | Mode::Codegen => { + // FIXME: this is a hack, see description of Mode::Rustc below + let stage = if host == target { builder.top_stage - 1 } else { builder.top_stage }; + // When checking tool stage N, we check it with compiler stage N-1 + let build_compiler = builder.compiler(stage, host); + builder.ensure(Rustc::new(builder, build_compiler, target)); + build_compiler + } + Mode::Rustc => { + // This is a horrible hack, because we actually change the compiler stage numbering + // here. If you do `x check --stage 1 --host FOO`, we build stage 1 host rustc, + // and use that to check stage 1 FOO rustc (which actually makes that stage 2 FOO + // rustc). + // + // FIXME: remove this and either fix cross-compilation check on stage 2 (which has a + // myriad of other problems) or disable cross-checking on stage 1. + let stage = if host == target { builder.top_stage - 1 } else { builder.top_stage }; + builder.compiler(stage, 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 +308,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 +322,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 +338,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<StepMetadata> { + 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 +377,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 +404,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<StepMetadata> { + 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 +442,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 +459,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<StepMetadata> { + Some(StepMetadata::check("compiletest", self.target)) + } } macro_rules! tool_check_step { @@ -440,12 +477,15 @@ 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 + $(, allow_features: $allow_features:expr )? $(, default: $default:literal )? $( , )? } ) => { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct $name { + pub build_compiler: Compiler, pub target: TargetSelection, } @@ -460,12 +500,30 @@ 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); + + // It doesn't make sense to cross-check bootstrap tools + if $mode == Mode::ToolBootstrap && target != run.builder.host_target { + println!("WARNING: not checking bootstrap tool {} for target {target} as it is a bootstrap (host-only) tool", stringify!($path)); + return; + }; + + 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; + let allow_features = { + let mut _value = ""; + $( _value = $allow_features; )? + _value + }; + run_tool_check_step(builder, build_compiler, target, $path, $mode, allow_features); + } + + fn metadata(&self) -> Option<StepMetadata> { + Some(StepMetadata::check(stringify!($name), self.target).built_by(self.build_compiler)) } } } @@ -474,19 +532,18 @@ 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, + allow_features: &str, ) { 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, @@ -497,98 +554,65 @@ fn run_tool_check_step( SourceType::InTree, &[], ); + cargo.allow_features(allow_features); + // 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, + allow_features: tool::TestFloatParse::ALLOW_FEATURES +}); +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/clean.rs b/src/bootstrap/src/core/build_steps/clean.rs index 882fcd08780..f67569d1486 100644 --- a/src/bootstrap/src/core/build_steps/clean.rs +++ b/src/bootstrap/src/core/build_steps/clean.rs @@ -181,7 +181,7 @@ fn rm_rf(path: &Path) { panic!("failed to get metadata for file {}: {}", path.display(), e); } Ok(metadata) => { - if metadata.file_type().is_file() || metadata.file_type().is_symlink() { + if !metadata.file_type().is_dir() { do_op(path, "remove file", |p| match fs::remove_file(p) { #[cfg(windows)] Err(e) diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index 1e44b5b67a4..a0371eb7155 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 8200e154169..3e2bdc2d6b5 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -12,7 +12,6 @@ use std::ffi::OsStr; use std::io::BufReader; use std::io::prelude::*; use std::path::{Path, PathBuf}; -use std::process::Stdio; use std::{env, fs, str}; use serde_derive::Deserialize; @@ -306,11 +305,7 @@ impl Step for Std { } fn metadata(&self) -> Option<StepMetadata> { - 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 +1181,7 @@ impl Step for Rustc { } fn metadata(&self) -> Option<StepMetadata> { - 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)) } } @@ -1750,17 +1741,19 @@ fn copy_codegen_backends_to_sysroot( } let stamp = build_stamp::codegen_backend_stamp(builder, compiler, target, backend); - let dylib = t!(fs::read_to_string(stamp.path())); - let file = Path::new(&dylib); - let filename = file.file_name().unwrap().to_str().unwrap(); - // change `librustc_codegen_cranelift-xxxxxx.so` to - // `librustc_codegen_cranelift-release.so` - let target_filename = { - let dash = filename.find('-').unwrap(); - let dot = filename.find('.').unwrap(); - format!("{}-{}{}", &filename[..dash], builder.rust_release(), &filename[dot..]) - }; - builder.copy_link(file, &dst.join(target_filename), FileType::NativeLibrary); + if stamp.path().exists() { + let dylib = t!(fs::read_to_string(stamp.path())); + let file = Path::new(&dylib); + let filename = file.file_name().unwrap().to_str().unwrap(); + // change `librustc_codegen_cranelift-xxxxxx.so` to + // `librustc_codegen_cranelift-release.so` + let target_filename = { + let dash = filename.find('-').unwrap(); + let dot = filename.find('.').unwrap(); + format!("{}-{}{}", &filename[..dash], builder.rust_release(), &filename[dot..]) + }; + builder.copy_link(file, &dst.join(target_filename), FileType::NativeLibrary); + } } } @@ -2171,6 +2164,25 @@ impl Step for Assemble { continue; // Already built as part of rustc } + // FIXME: this is a horrible hack used to make `x check` work when other codegen + // backends are enabled. + // `x check` will check stage 1 rustc, which copies its rmetas to the stage0 sysroot. + // Then it checks codegen backends, which correctly use these rmetas. + // Then it needs to check std, but for that it needs to build stage 1 rustc. + // This copies the build rmetas into the stage0 sysroot, effectively poisoning it, + // because we then have both check and build rmetas in the same sysroot. + // That would be fine on its own. However, when another codegen backend is enabled, + // then building stage 1 rustc implies also building stage 1 codegen backend (even if + // it isn't used for anything). And since that tries to use the poisoned + // rmetas, it fails to build. + // We don't actually need to build rustc-private codegen backends for checking std, + // so instead we skip that. + // Note: this would be also an issue for other rustc-private tools, but that is "solved" + // by check::Std being last in the list of checked things (see + // `Builder::get_step_descriptions`). + if builder.kind == Kind::Check && builder.top_stage == 1 { + continue; + } builder.ensure(CodegenBackend { compiler: build_compiler, target: target_compiler.host, @@ -2241,7 +2253,7 @@ impl Step for Assemble { debug!("copying codegen backends to sysroot"); copy_codegen_backends_to_sysroot(builder, build_compiler, target_compiler); - if builder.config.lld_enabled && !builder.config.is_system_llvm(target_compiler.host) { + if builder.config.lld_enabled { builder.ensure(crate::core::build_steps::tool::LldWrapper { build_compiler, target_compiler, @@ -2515,7 +2527,6 @@ pub fn stream_cargo( #[cfg(feature = "tracing")] let _run_span = crate::trace_cmd!(cmd); - let cargo = cmd.as_command_mut(); // Instruct Cargo to give us json messages on stdout, critically leaving // stderr as piped so we can get those pretty colors. let mut message_format = if builder.config.json_output { @@ -2527,27 +2538,24 @@ pub fn stream_cargo( message_format.push_str(",json-diagnostic-"); message_format.push_str(s); } - cargo.arg("--message-format").arg(message_format).stdout(Stdio::piped()); + cmd.arg("--message-format").arg(message_format); for arg in tail_args { - cargo.arg(arg); + cmd.arg(arg); } - builder.verbose(|| println!("running: {cargo:?}")); + builder.verbose(|| println!("running: {cmd:?}")); - if builder.config.dry_run() { - return true; - } + let streaming_command = cmd.stream_capture_stdout(&builder.config.exec_ctx); - let mut child = match cargo.spawn() { - Ok(child) => child, - Err(e) => panic!("failed to execute command: {cargo:?}\nERROR: {e}"), + let Some(mut streaming_command) = streaming_command else { + return true; }; // Spawn Cargo slurping up its JSON output. We'll start building up the // `deps` array of all files it generated along with a `toplevel` array of // files we need to probe for later. - let stdout = BufReader::new(child.stdout.take().unwrap()); + let stdout = BufReader::new(streaming_command.stdout.take().unwrap()); for line in stdout.lines() { let line = t!(line); match serde_json::from_str::<CargoMessage<'_>>(&line) { @@ -2564,13 +2572,14 @@ pub fn stream_cargo( } // Make sure Cargo actually succeeded after we read all of its stdout. - let status = t!(child.wait()); + let status = t!(streaming_command.wait()); if builder.is_verbose() && !status.success() { eprintln!( - "command did not execute successfully: {cargo:?}\n\ + "command did not execute successfully: {cmd:?}\n\ expected success, got: {status}" ); } + status.success() } diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index 61268df7336..d487995e98a 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -346,6 +346,6 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) { // since last merge. // // NOTE: Because of the exit above, this is only reachable if formatting / format checking - // succeeded. So we are not commiting the version if formatting was not good. + // succeeded. So we are not committing the version if formatting was not good. update_rustfmt_version(build); } diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index de67a5f77e6..b2056f5cf37 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -263,6 +263,15 @@ impl Step for Llvm { } /// Compile LLVM for `target`. + #[cfg_attr( + feature = "tracing", + instrument( + level = "debug", + name = "Llvm::run", + skip_all, + fields(target = ?self.target), + ), + )] fn run(self, builder: &Builder<'_>) -> LlvmResult { let target = self.target; let target_native = if self.target.starts_with("riscv") { diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index b3104ae05e8..b2293fdd9b5 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -5,6 +5,8 @@ use std::path::PathBuf; +use clap_complete::{Generator, shells}; + use crate::core::build_steps::dist::distdir; use crate::core::build_steps::test; use crate::core::build_steps::tool::{self, SourceType, Tool}; @@ -285,36 +287,35 @@ impl Step for GenerateWindowsSys { } } +/// Return tuples of (shell, file containing completions). +pub fn get_completion_paths(builder: &Builder<'_>) -> Vec<(&'static dyn Generator, PathBuf)> { + vec![ + (&shells::Bash as &'static dyn Generator, builder.src.join("src/etc/completions/x.py.sh")), + (&shells::Zsh, builder.src.join("src/etc/completions/x.py.zsh")), + (&shells::Fish, builder.src.join("src/etc/completions/x.py.fish")), + (&shells::PowerShell, builder.src.join("src/etc/completions/x.py.ps1")), + (&shells::Bash, builder.src.join("src/etc/completions/x.sh")), + (&shells::Zsh, builder.src.join("src/etc/completions/x.zsh")), + (&shells::Fish, builder.src.join("src/etc/completions/x.fish")), + (&shells::PowerShell, builder.src.join("src/etc/completions/x.ps1")), + ] +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct GenerateCompletions; -macro_rules! generate_completions { - ( $( ( $shell:ident, $filename:expr ) ),* ) => { - $( - if let Some(comp) = get_completion($shell, &$filename) { - std::fs::write(&$filename, comp).expect(&format!("writing {} completion", stringify!($shell))); - } - )* - }; -} - impl Step for GenerateCompletions { type Output = (); /// Uses `clap_complete` to generate shell completions. fn run(self, builder: &Builder<'_>) { - use clap_complete::shells::{Bash, Fish, PowerShell, Zsh}; - - generate_completions!( - (Bash, builder.src.join("src/etc/completions/x.py.sh")), - (Zsh, builder.src.join("src/etc/completions/x.py.zsh")), - (Fish, builder.src.join("src/etc/completions/x.py.fish")), - (PowerShell, builder.src.join("src/etc/completions/x.py.ps1")), - (Bash, builder.src.join("src/etc/completions/x.sh")), - (Zsh, builder.src.join("src/etc/completions/x.zsh")), - (Fish, builder.src.join("src/etc/completions/x.fish")), - (PowerShell, builder.src.join("src/etc/completions/x.ps1")) - ); + for (shell, path) in get_completion_paths(builder) { + if let Some(comp) = get_completion(shell, &path) { + std::fs::write(&path, comp).unwrap_or_else(|e| { + panic!("writing completion into {} failed: {e:?}", path.display()) + }); + } + } } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 01b181f55de..a5b7b22aba8 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -8,12 +8,11 @@ use std::ffi::{OsStr, OsString}; use std::path::{Path, PathBuf}; use std::{env, fs, iter}; -use clap_complete::shells; - use crate::core::build_steps::compile::{Std, run_cargo}; use crate::core::build_steps::doc::DocumentationFormat; use crate::core::build_steps::gcc::{Gcc, add_cg_gcc_cargo_flags}; use crate::core::build_steps::llvm::get_llvm_version; +use crate::core::build_steps::run::get_completion_paths; use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget; use crate::core::build_steps::tool::{self, COMPILETEST_ALLOW_FEATURES, SourceType, Tool}; use crate::core::build_steps::toolstate::ToolState; @@ -1108,7 +1107,9 @@ impl Step for Tidy { if builder.config.cmd.bless() { cmd.arg("--bless"); } - if let Some(s) = builder.config.cmd.extra_checks() { + if let Some(s) = + builder.config.cmd.extra_checks().or(builder.config.tidy_extra_checks.as_deref()) + { cmd.arg(format!("--extra-checks={s}")); } let mut args = std::env::args_os(); @@ -1151,14 +1152,12 @@ HELP: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to cmd.delay_failure().run(builder); builder.info("x.py completions check"); - let [bash, zsh, fish, powershell] = ["x.py.sh", "x.py.zsh", "x.py.fish", "x.py.ps1"] - .map(|filename| builder.src.join("src/etc/completions").join(filename)); + let completion_paths = get_completion_paths(builder); if builder.config.cmd.bless() { builder.ensure(crate::core::build_steps::run::GenerateCompletions); - } else if get_completion(shells::Bash, &bash).is_some() - || get_completion(shells::Fish, &fish).is_some() - || get_completion(shells::PowerShell, &powershell).is_some() - || crate::flags::get_completion(shells::Zsh, &zsh).is_some() + } else if completion_paths + .into_iter() + .any(|(shell, path)| get_completion(shell, &path).is_some()) { eprintln!( "x.py completions were changed; run `x.py run generate-completions` to update them" diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 83c0525d7c4..b05b34b9b22 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), } } } @@ -120,14 +120,14 @@ impl Step for ToolBuild { match self.mode { Mode::ToolRustc => { - // If compiler was forced, its artifacts should be prepared earlier. + // If compiler was forced, its artifacts should have been prepared earlier. if !self.compiler.is_forced_compiler() { builder.std(self.compiler, self.compiler.host); builder.ensure(compile::Rustc::new(self.compiler, target)); } } Mode::ToolStd => { - // If compiler was forced, its artifacts should be prepared earlier. + // If compiler was forced, its artifacts should have been prepared earlier. if !self.compiler.is_forced_compiler() { builder.std(self.compiler, 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 8e9e8b496de..b96a988cde3 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -153,6 +153,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) } @@ -178,6 +182,14 @@ impl StepMetadata { self.stage = Some(stage); self } + + pub fn get_stage(&self) -> Option<u32> { + self.stage.or(self + .built_by + // For std, its stage corresponds to the stage of the compiler that builds it. + // For everything else, a stage N things gets built by a stage N-1 compiler. + .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 8adf93ea528..1d5690a8197 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 <host> -> OptimizedDist <host>"); + .render_steps(), @"[build] rustc 0 <host> -> OptimizedDist 1 <host>"); } #[test] @@ -880,7 +880,7 @@ mod snapshot { ctx.config("build") .path("opt-dist") .stage(1) - .render_steps(), @"[build] rustc 0 <host> -> OptimizedDist <host>"); + .render_steps(), @"[build] rustc 0 <host> -> OptimizedDist 1 <host>"); } #[test] @@ -890,7 +890,7 @@ mod snapshot { ctx.config("build") .path("opt-dist") .stage(2) - .render_steps(), @"[build] rustc 0 <host> -> OptimizedDist <host>"); + .render_steps(), @"[build] rustc 0 <host> -> OptimizedDist 1 <host>"); } #[test] @@ -984,8 +984,8 @@ mod snapshot { ctx .config("dist") .render_steps(), @r" - [build] rustc 0 <host> -> UnstableBookGen <host> - [build] rustc 0 <host> -> Rustbook <host> + [build] rustc 0 <host> -> UnstableBookGen 1 <host> + [build] rustc 0 <host> -> Rustbook 1 <host> [build] llvm <host> [build] rustc 0 <host> -> rustc 1 <host> [build] rustc 1 <host> -> std 1 <host> @@ -993,14 +993,14 @@ mod snapshot { [build] rustdoc 1 <host> [doc] std 2 <host> [build] rustc 2 <host> -> std 2 <host> - [build] rustc 0 <host> -> LintDocs <host> - [build] rustc 0 <host> -> RustInstaller <host> + [build] rustc 0 <host> -> LintDocs 1 <host> + [build] rustc 0 <host> -> RustInstaller 1 <host> [dist] docs <host> [doc] std 2 <host> [dist] mingw <host> - [build] rustc 0 <host> -> GenerateCopyright <host> + [build] rustc 0 <host> -> GenerateCopyright 1 <host> [dist] rustc <host> - [dist] rustc 1 <host> -> std <host> + [dist] rustc 1 <host> -> std 1 <host> [dist] src <> " ); @@ -1014,25 +1014,25 @@ mod snapshot { .config("dist") .args(&["--set", "build.extended=true"]) .render_steps(), @r" - [build] rustc 0 <host> -> UnstableBookGen <host> - [build] rustc 0 <host> -> Rustbook <host> + [build] rustc 0 <host> -> UnstableBookGen 1 <host> + [build] rustc 0 <host> -> Rustbook 1 <host> [build] llvm <host> [build] rustc 0 <host> -> rustc 1 <host> - [build] rustc 0 <host> -> WasmComponentLd <host> + [build] rustc 0 <host> -> WasmComponentLd 1 <host> [build] rustc 1 <host> -> std 1 <host> [build] rustc 1 <host> -> rustc 2 <host> - [build] rustc 1 <host> -> WasmComponentLd <host> + [build] rustc 1 <host> -> WasmComponentLd 2 <host> [build] rustdoc 1 <host> [doc] std 2 <host> [build] rustc 2 <host> -> std 2 <host> - [build] rustc 0 <host> -> LintDocs <host> - [build] rustc 0 <host> -> RustInstaller <host> + [build] rustc 0 <host> -> LintDocs 1 <host> + [build] rustc 0 <host> -> RustInstaller 1 <host> [dist] docs <host> [doc] std 2 <host> [dist] mingw <host> - [build] rustc 0 <host> -> GenerateCopyright <host> + [build] rustc 0 <host> -> GenerateCopyright 1 <host> [dist] rustc <host> - [dist] rustc 1 <host> -> std <host> + [dist] rustc 1 <host> -> std 1 <host> [dist] src <> [build] rustc 0 <host> -> rustfmt 1 <host> [build] rustc 0 <host> -> cargo-fmt 1 <host> @@ -1052,8 +1052,8 @@ mod snapshot { .hosts(&[&host_target()]) .targets(&[&host_target(), TEST_TRIPLE_1]) .render_steps(), @r" - [build] rustc 0 <host> -> UnstableBookGen <host> - [build] rustc 0 <host> -> Rustbook <host> + [build] rustc 0 <host> -> UnstableBookGen 1 <host> + [build] rustc 0 <host> -> Rustbook 1 <host> [build] llvm <host> [build] rustc 0 <host> -> rustc 1 <host> [build] rustc 1 <host> -> std 1 <host> @@ -1062,19 +1062,19 @@ mod snapshot { [doc] std 2 <host> [doc] std 2 <target1> [build] rustc 2 <host> -> std 2 <host> - [build] rustc 0 <host> -> LintDocs <host> - [build] rustc 0 <host> -> RustInstaller <host> + [build] rustc 0 <host> -> LintDocs 1 <host> + [build] rustc 0 <host> -> RustInstaller 1 <host> [dist] docs <host> [dist] docs <target1> [doc] std 2 <host> [doc] std 2 <target1> [dist] mingw <host> [dist] mingw <target1> - [build] rustc 0 <host> -> GenerateCopyright <host> + [build] rustc 0 <host> -> GenerateCopyright 1 <host> [dist] rustc <host> - [dist] rustc 1 <host> -> std <host> + [dist] rustc 1 <host> -> std 1 <host> [build] rustc 2 <host> -> std 2 <target1> - [dist] rustc 2 <host> -> std <target1> + [dist] rustc 2 <host> -> std 2 <target1> [dist] src <> " ); @@ -1089,8 +1089,8 @@ mod snapshot { .hosts(&[&host_target(), TEST_TRIPLE_1]) .targets(&[&host_target()]) .render_steps(), @r" - [build] rustc 0 <host> -> UnstableBookGen <host> - [build] rustc 0 <host> -> Rustbook <host> + [build] rustc 0 <host> -> UnstableBookGen 1 <host> + [build] rustc 0 <host> -> Rustbook 1 <host> [build] llvm <host> [build] rustc 0 <host> -> rustc 1 <host> [build] rustc 1 <host> -> std 1 <host> @@ -1098,20 +1098,20 @@ mod snapshot { [build] rustdoc 1 <host> [doc] std 2 <host> [build] rustc 2 <host> -> std 2 <host> - [build] rustc 0 <host> -> LintDocs <host> + [build] rustc 0 <host> -> LintDocs 1 <host> [build] rustc 1 <host> -> std 1 <target1> [build] rustc 2 <host> -> std 2 <target1> - [build] rustc 0 <host> -> RustInstaller <host> + [build] rustc 0 <host> -> RustInstaller 1 <host> [dist] docs <host> [doc] std 2 <host> [dist] mingw <host> - [build] rustc 0 <host> -> GenerateCopyright <host> + [build] rustc 0 <host> -> GenerateCopyright 1 <host> [dist] rustc <host> [build] llvm <target1> [build] rustc 1 <host> -> rustc 2 <target1> [build] rustdoc 1 <target1> [dist] rustc <target1> - [dist] rustc 1 <host> -> std <host> + [dist] rustc 1 <host> -> std 1 <host> [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 <host> -> UnstableBookGen <host> - [build] rustc 0 <host> -> Rustbook <host> + [build] rustc 0 <host> -> UnstableBookGen 1 <host> + [build] rustc 0 <host> -> Rustbook 1 <host> [build] llvm <host> [build] rustc 0 <host> -> rustc 1 <host> [build] rustc 1 <host> -> std 1 <host> @@ -1136,24 +1136,24 @@ mod snapshot { [doc] std 2 <host> [doc] std 2 <target1> [build] rustc 2 <host> -> std 2 <host> - [build] rustc 0 <host> -> LintDocs <host> + [build] rustc 0 <host> -> LintDocs 1 <host> [build] rustc 1 <host> -> std 1 <target1> [build] rustc 2 <host> -> std 2 <target1> - [build] rustc 0 <host> -> RustInstaller <host> + [build] rustc 0 <host> -> RustInstaller 1 <host> [dist] docs <host> [dist] docs <target1> [doc] std 2 <host> [doc] std 2 <target1> [dist] mingw <host> [dist] mingw <target1> - [build] rustc 0 <host> -> GenerateCopyright <host> + [build] rustc 0 <host> -> GenerateCopyright 1 <host> [dist] rustc <host> [build] llvm <target1> [build] rustc 1 <host> -> rustc 2 <target1> [build] rustdoc 1 <target1> [dist] rustc <target1> - [dist] rustc 1 <host> -> std <host> - [dist] rustc 1 <host> -> std <target1> + [dist] rustc 1 <host> -> std 1 <host> + [dist] rustc 1 <host> -> std 1 <target1> [dist] src <> " ); @@ -1168,8 +1168,8 @@ mod snapshot { .hosts(&[]) .targets(&[TEST_TRIPLE_1]) .render_steps(), @r" - [build] rustc 0 <host> -> UnstableBookGen <host> - [build] rustc 0 <host> -> Rustbook <host> + [build] rustc 0 <host> -> UnstableBookGen 1 <host> + [build] rustc 0 <host> -> Rustbook 1 <host> [build] llvm <host> [build] rustc 0 <host> -> rustc 1 <host> [build] rustc 1 <host> -> std 1 <host> @@ -1177,12 +1177,12 @@ mod snapshot { [build] rustdoc 1 <host> [doc] std 2 <target1> [build] rustc 2 <host> -> std 2 <host> - [build] rustc 0 <host> -> RustInstaller <host> + [build] rustc 0 <host> -> RustInstaller 1 <host> [dist] docs <target1> [doc] std 2 <target1> [dist] mingw <target1> [build] rustc 2 <host> -> std 2 <target1> - [dist] rustc 2 <host> -> std <target1> + [dist] rustc 2 <host> -> std 2 <target1> "); } @@ -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 <host> -> UnstableBookGen <host> - [build] rustc 0 <host> -> Rustbook <host> + [build] rustc 0 <host> -> UnstableBookGen 1 <host> + [build] rustc 0 <host> -> Rustbook 1 <host> [build] llvm <host> [build] rustc 0 <host> -> rustc 1 <host> - [build] rustc 0 <host> -> WasmComponentLd <host> + [build] rustc 0 <host> -> WasmComponentLd 1 <host> [build] rustc 1 <host> -> std 1 <host> [build] rustc 1 <host> -> rustc 2 <host> - [build] rustc 1 <host> -> WasmComponentLd <host> + [build] rustc 1 <host> -> WasmComponentLd 2 <host> [build] rustdoc 1 <host> [doc] std 2 <target1> [build] rustc 2 <host> -> std 2 <host> [build] rustc 1 <host> -> std 1 <target1> [build] rustc 2 <host> -> std 2 <target1> - [build] rustc 0 <host> -> LintDocs <host> - [build] rustc 0 <host> -> RustInstaller <host> + [build] rustc 0 <host> -> LintDocs 1 <host> + [build] rustc 0 <host> -> RustInstaller 1 <host> [dist] docs <target1> [doc] std 2 <target1> [dist] mingw <target1> [build] llvm <target1> [build] rustc 1 <host> -> rustc 2 <target1> - [build] rustc 1 <host> -> WasmComponentLd <target1> + [build] rustc 1 <host> -> WasmComponentLd 2 <target1> [build] rustdoc 1 <target1> - [build] rustc 0 <host> -> GenerateCopyright <host> + [build] rustc 0 <host> -> GenerateCopyright 1 <host> [dist] rustc <target1> - [dist] rustc 1 <host> -> std <target1> + [dist] rustc 1 <host> -> std 1 <target1> [dist] src <> [build] rustc 0 <host> -> rustfmt 1 <target1> [build] rustc 0 <host> -> cargo-fmt 1 <target1> @@ -1234,6 +1234,268 @@ 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 <host> + [check] rustc 0 <host> -> rustc 1 <host> + [check] rustc 0 <host> -> cranelift 1 <host> + [check] rustc 0 <host> -> gcc 1 <host> + "); + + insta::assert_snapshot!( + ctx.config("check") + .path("rustc") + .render_steps(), @r" + [build] llvm <host> + [check] rustc 0 <host> -> rustc 1 <host> + "); + } + + #[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 <host> + [check] rustc 0 <host> -> rustc 1 <host> + [check] rustc 0 <host> -> cranelift 1 <host> + [check] rustc 0 <host> -> gcc 1 <host> + "); + } + + #[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 <host> + [build] rustc 0 <host> -> rustc 1 <host> + [build] rustc 1 <host> -> std 1 <host> + [check] rustc 1 <host> -> rustc 2 <host> + [check] rustc 1 <host> -> cranelift 2 <host> + [check] rustc 1 <host> -> gcc 2 <host> + "); + } + + #[test] + fn check_cross_compile() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .targets(&[TEST_TRIPLE_1]) + .hosts(&[TEST_TRIPLE_1]) + .render_steps(), @r" + [build] llvm <host> + [build] rustc 0 <host> -> rustc 1 <host> + [build] rustc 1 <host> -> std 1 <host> + [build] rustc 1 <host> -> std 1 <target1> + [check] rustc 1 <host> -> rustc 2 <target1> + [check] rustc 1 <host> -> Rustdoc 2 <target1> + [check] rustc 1 <host> -> cranelift 2 <target1> + [check] rustc 1 <host> -> gcc 2 <target1> + [check] rustc 1 <host> -> Clippy 2 <target1> + [check] rustc 1 <host> -> Miri 2 <target1> + [check] rustc 1 <host> -> CargoMiri 2 <target1> + [check] rustc 1 <host> -> Rustfmt 2 <target1> + [check] rustc 1 <host> -> rust-analyzer 2 <target1> + [check] rustc 1 <host> -> TestFloatParse 2 <target1> + [check] rustc 1 <host> -> std 1 <target1> + "); + } + + #[test] + fn check_library_no_explicit_stage() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("library") + .render_steps(), @r" + [build] llvm <host> + [build] rustc 0 <host> -> rustc 1 <host> + [check] rustc 1 <host> -> std 1 <host> + "); + } + + #[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 <host> + [build] rustc 0 <host> -> rustc 1 <host> + [check] rustc 1 <host> -> std 1 <host> + "); + } + + #[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 <host> + [build] rustc 0 <host> -> rustc 1 <host> + [build] rustc 1 <host> -> std 1 <host> + [build] rustc 1 <host> -> rustc 2 <host> + [check] rustc 2 <host> -> std 2 <host> + "); + } + + #[test] + fn check_library_cross_compile() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .paths(&["core", "alloc", "std"]) + .targets(&[TEST_TRIPLE_1, TEST_TRIPLE_2]) + .render_steps(), @r" + [build] llvm <host> + [build] rustc 0 <host> -> rustc 1 <host> + [check] rustc 1 <host> -> std 1 <target1> + [check] rustc 1 <host> -> std 1 <target2> + "); + } + + #[test] + fn check_miri_no_explicit_stage() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("miri") + .render_steps(), @r" + [build] llvm <host> + [check] rustc 0 <host> -> rustc 1 <host> + [check] rustc 0 <host> -> Miri 1 <host> + "); + } + + #[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 <host> + [check] rustc 0 <host> -> rustc 1 <host> + [check] rustc 0 <host> -> Miri 1 <host> + "); + } + + #[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 <host> + [build] rustc 0 <host> -> rustc 1 <host> + [build] rustc 1 <host> -> std 1 <host> + [check] rustc 1 <host> -> rustc 2 <host> + [check] rustc 1 <host> -> Miri 2 <host> + "); + } + + #[test] + fn check_compiletest() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("compiletest") + .render_steps(), @"[check] compiletest <host>"); + } + + #[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 <host> + [build] rustc 0 <host> -> rustc 1 <host> + [build] rustc 1 <host> -> std 1 <host> + [check] compiletest <host> + "); + } + + #[test] + fn check_codegen() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("rustc_codegen_cranelift") + .render_steps(), @r" + [build] llvm <host> + [check] rustc 0 <host> -> rustc 1 <host> + [check] rustc 0 <host> -> cranelift 1 <host> + [check] rustc 0 <host> -> gcc 1 <host> + "); + } + + #[test] + fn check_rust_analyzer() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("rust-analyzer") + .render_steps(), @r" + [build] llvm <host> + [check] rustc 0 <host> -> rustc 1 <host> + [check] rustc 0 <host> -> rust-analyzer 1 <host> + "); + } + + #[test] + fn check_bootstrap_tool() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("check") + .path("run-make-support") + .render_steps(), @"[check] rustc 0 <host> -> RunMakeSupport 1 <host>"); + } + + #[test] fn test_exclude() { let ctx = TestCtx::new(); let steps = ctx.config("test").args(&["--skip", "src/tools/tidy"]).get_steps(); @@ -1384,7 +1646,7 @@ 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 = metadata.get_stage().map(|stage| format!("{stage} ")).unwrap_or_default(); 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 d1ffdf24acd..59693dc3e4c 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -297,7 +297,8 @@ pub struct Config { /// Whether to use the precompiled stage0 libtest with compiletest. pub compiletest_use_stage0_libtest: bool, - + /// Default value for `--extra-checks` + pub tidy_extra_checks: Option<String>, pub is_running_on_ci: bool, /// Cache for determining path modifications @@ -744,6 +745,7 @@ impl Config { jobs, compiletest_diff_tool, compiletest_use_stage0_libtest, + tidy_extra_checks, mut ccache, exclude, } = toml.build.unwrap_or_default(); @@ -1003,15 +1005,14 @@ impl Config { } if config.lld_enabled && config.is_system_llvm(config.host_target) { - eprintln!( - "Warning: LLD is enabled when using external llvm-config. LLD will not be built and copied to the sysroot." - ); + panic!("Cannot enable LLD with `rust.lld = true` when using external llvm-config."); } config.optimized_compiler_builtins = optimized_compiler_builtins.unwrap_or(config.channel != "dev"); config.compiletest_diff_tool = compiletest_diff_tool; config.compiletest_use_stage0_libtest = compiletest_use_stage0_libtest.unwrap_or(true); + config.tidy_extra_checks = tidy_extra_checks; let download_rustc = config.download_rustc_commit.is_some(); config.explicit_stage_from_cli = flags_stage.is_some(); @@ -1024,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 { .. } => { @@ -1051,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/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index bb21d033458..bfc06f90d4f 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -6,6 +6,7 @@ use std::path::{Path, PathBuf}; use clap::{CommandFactory, Parser, ValueEnum}; +use clap_complete::Generator; #[cfg(feature = "tracing")] use tracing::instrument; @@ -382,7 +383,7 @@ pub enum Subcommand { bless: bool, #[arg(long)] /// comma-separated list of other files types to check (accepts py, py:lint, - /// py:fmt, shell) + /// py:fmt, shell, shell:lint, cpp, cpp:fmt, spellcheck, spellcheck:fix) extra_checks: Option<String>, #[arg(long)] /// rerun tests even if the inputs are unchanged @@ -644,7 +645,7 @@ impl Subcommand { /// Returns the shell completion for a given shell, if the result differs from the current /// content of `path`. If `path` does not exist, always returns `Some`. -pub fn get_completion<G: clap_complete::Generator>(shell: G, path: &Path) -> Option<String> { +pub fn get_completion(shell: &dyn Generator, path: &Path) -> Option<String> { let mut cmd = Flags::command(); let current = if !path.exists() { String::new() @@ -662,7 +663,12 @@ pub fn get_completion<G: clap_complete::Generator>(shell: G, path: &Path) -> Opt .expect("file name should be UTF-8") .rsplit_once('.') .expect("file name should have an extension"); - clap_complete::generate(shell, &mut cmd, bin_name, &mut buf); + + // We sort of replicate `clap_complete::generate` here, because we want to call it with + // `&dyn Generator`, but that function requires `G: Generator` instead. + cmd.set_bin_name(bin_name); + cmd.build(); + shell.generate(&cmd, &mut buf); if buf == current.as_bytes() { return None; } diff --git a/src/bootstrap/src/core/config/toml/build.rs b/src/bootstrap/src/core/config/toml/build.rs index 98e1194de72..4d29691f38b 100644 --- a/src/bootstrap/src/core/config/toml/build.rs +++ b/src/bootstrap/src/core/config/toml/build.rs @@ -69,6 +69,7 @@ define_config! { jobs: Option<u32> = "jobs", compiletest_diff_tool: Option<String> = "compiletest-diff-tool", compiletest_use_stage0_libtest: Option<bool> = "compiletest-use-stage0-libtest", + tidy_extra_checks: Option<String> = "tidy-extra-checks", ccache: Option<StringOrBool> = "ccache", exclude: Option<Vec<PathBuf>> = "exclude", } diff --git a/src/bootstrap/src/core/config/toml/rust.rs b/src/bootstrap/src/core/config/toml/rust.rs index 642f2f2271d..ac5eaea3bcb 100644 --- a/src/bootstrap/src/core/config/toml/rust.rs +++ b/src/bootstrap/src/core/config/toml/rust.rs @@ -393,6 +393,27 @@ pub fn check_incompatible_options_for_ci_rustc( Ok(()) } +pub(crate) const VALID_CODEGEN_BACKENDS: &[&str] = &["llvm", "cranelift", "gcc"]; + +pub(crate) fn validate_codegen_backends(backends: Vec<String>, section: &str) -> Vec<String> { + for backend in &backends { + if let Some(stripped) = backend.strip_prefix(CODEGEN_BACKEND_PREFIX) { + panic!( + "Invalid value '{backend}' for '{section}.codegen-backends'. \ + Codegen backends are defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \ + Please, use '{stripped}' instead." + ) + } + if !VALID_CODEGEN_BACKENDS.contains(&backend.as_str()) { + println!( + "HELP: '{backend}' for '{section}.codegen-backends' might fail. \ + List of known good values: {VALID_CODEGEN_BACKENDS:?}" + ); + } + } + backends +} + impl Config { pub fn apply_rust_config( &mut self, @@ -571,24 +592,10 @@ impl Config { set(&mut self.ehcont_guard, ehcont_guard); self.llvm_libunwind_default = llvm_libunwind.map(|v| v.parse().expect("failed to parse rust.llvm-libunwind")); - - if let Some(ref backends) = codegen_backends { - let available_backends = ["llvm", "cranelift", "gcc"]; - - self.rust_codegen_backends = backends.iter().map(|s| { - if let Some(backend) = s.strip_prefix(CODEGEN_BACKEND_PREFIX) { - if available_backends.contains(&backend) { - panic!("Invalid value '{s}' for 'rust.codegen-backends'. Instead, please use '{backend}'."); - } else { - println!("HELP: '{s}' for 'rust.codegen-backends' might fail. \ - Codegen backends are mostly defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \ - In this case, it would be referred to as '{backend}'."); - } - } - - s.clone() - }).collect(); - } + set( + &mut self.rust_codegen_backends, + codegen_backends.map(|backends| validate_codegen_backends(backends, "rust")), + ); self.rust_codegen_units = codegen_units.map(threads_from_config); self.rust_codegen_units_std = codegen_units_std.map(threads_from_config); diff --git a/src/bootstrap/src/core/config/toml/target.rs b/src/bootstrap/src/core/config/toml/target.rs index b9f6780ca3f..337276948b3 100644 --- a/src/bootstrap/src/core/config/toml/target.rs +++ b/src/bootstrap/src/core/config/toml/target.rs @@ -16,7 +16,7 @@ use std::collections::HashMap; use serde::{Deserialize, Deserializer}; -use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX; +use crate::core::config::toml::rust::validate_codegen_backends; use crate::core::config::{LlvmLibunwind, Merge, ReplaceOpt, SplitDebuginfo, StringOrBool}; use crate::{Config, HashSet, PathBuf, TargetSelection, define_config, exit}; @@ -142,23 +142,9 @@ impl Config { target.rpath = cfg.rpath; target.optimized_compiler_builtins = cfg.optimized_compiler_builtins; target.jemalloc = cfg.jemalloc; - - if let Some(ref backends) = cfg.codegen_backends { - let available_backends = ["llvm", "cranelift", "gcc"]; - - target.codegen_backends = Some(backends.iter().map(|s| { - if let Some(backend) = s.strip_prefix(CODEGEN_BACKEND_PREFIX) { - if available_backends.contains(&backend) { - panic!("Invalid value '{s}' for 'target.{triple}.codegen-backends'. Instead, please use '{backend}'."); - } else { - println!("HELP: '{s}' for 'target.{triple}.codegen-backends' might fail. \ - Codegen backends are mostly defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \ - In this case, it would be referred to as '{backend}'."); - } - } - - s.clone() - }).collect()); + if let Some(backends) = cfg.codegen_backends { + target.codegen_backends = + Some(validate_codegen_backends(backends, &format!("target.{triple}"))) } target.split_debuginfo = cfg.split_debuginfo.as_ref().map(|v| { diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 958058d982b..f2119e84cce 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -34,8 +34,6 @@ pub struct Finder { // Targets can be removed from this list once they are present in the stage0 compiler (usually by updating the beta compiler of the bootstrap). const STAGE0_MISSING_TARGETS: &[&str] = &[ // just a dummy comment so the list doesn't get onelined - "loongarch32-unknown-none", - "loongarch32-unknown-none-softfloat", ]; /// Minimum version threshold for libstdc++ required when using prebuilt LLVM diff --git a/src/bootstrap/src/utils/cache/tests.rs b/src/bootstrap/src/utils/cache/tests.rs index 8562a35b3e0..fd0a7cccd60 100644 --- a/src/bootstrap/src/utils/cache/tests.rs +++ b/src/bootstrap/src/utils/cache/tests.rs @@ -1,12 +1,13 @@ use std::path::PathBuf; -use crate::utils::cache::{INTERNER, Internable, TyIntern}; +use crate::utils::cache::{INTERNER, Internable, Interner, TyIntern}; #[test] fn test_string_interning() { - let s1 = INTERNER.intern_str("Hello"); - let s2 = INTERNER.intern_str("Hello"); - let s3 = INTERNER.intern_str("world"); + let interner = Interner::default(); + let s1 = interner.intern_str("Hello"); + let s2 = interner.intern_str("Hello"); + let s3 = interner.intern_str("world"); assert_eq!(s1, s2, "Same strings should be interned to the same instance"); assert_ne!(s1, s3, "Different strings should have different interned values"); @@ -14,6 +15,8 @@ fn test_string_interning() { #[test] fn test_interned_equality() { + // Because we compare with &str, and the Deref impl accesses the global + // INTERNER variable, we cannot use a local Interner variable here. let s1 = INTERNER.intern_str("test"); let s2 = INTERNER.intern_str("test"); diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 7c588cfea8c..424f211c7d4 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -149,7 +149,7 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ ChangeInfo { change_id: 121976, severity: ChangeSeverity::Info, - summary: "A new `boostrap-cache-path` option has been introduced which can be utilized to modify the cache path for bootstrap.", + summary: "A new `bootstrap-cache-path` option has been introduced which can be utilized to modify the cache path for bootstrap.", }, ChangeInfo { change_id: 122108, @@ -404,7 +404,7 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ ChangeInfo { change_id: 140438, severity: ChangeSeverity::Info, - summary: "Added a new option `rust.debug-assertions-tools` to control debug asssertions for tools.", + summary: "Added a new option `rust.debug-assertions-tools` to control debug assertions for tools.", }, ChangeInfo { change_id: 140732, @@ -431,4 +431,34 @@ 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: 143175, + severity: ChangeSeverity::Info, + summary: "It is no longer possible to combine `rust.lld = true` with configuring external LLVM using `llvm.llvm-config`.", + }, + ChangeInfo { + change_id: 143255, + severity: ChangeSeverity::Warning, + summary: "`llvm.lld` is no longer enabled by default for the dist profile.", + }, + ChangeInfo { + change_id: 143251, + severity: ChangeSeverity::Info, + summary: "Added new option `build.tidy-extra-checks` to specify a default value for the --extra-checks cli flag.", + }, + ChangeInfo { + change_id: 143493, + severity: ChangeSeverity::Warning, + summary: "The `spellcheck:fix` tidy extra check argument has been removed, use `--bless` instead", + }, + 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+. Bootstrap tools can now also only be checked for the host target.", + }, + ChangeInfo { + change_id: 143577, + severity: ChangeSeverity::Warning, + summary: "`download-rustc` has been temporarily disabled for the library profile due to implementation bugs (see #142505).", + }, ]; diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index d092765ef76..487077835ac 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -13,7 +13,9 @@ use std::fmt::{Debug, Formatter}; use std::hash::Hash; use std::panic::Location; use std::path::Path; -use std::process::{Child, Command, CommandArgs, CommandEnvs, ExitStatus, Output, Stdio}; +use std::process::{ + Child, ChildStderr, ChildStdout, Command, CommandArgs, CommandEnvs, ExitStatus, Output, Stdio, +}; use std::sync::{Arc, Mutex}; use build_helper::ci::CiEnv; @@ -209,15 +211,14 @@ impl<'a> BootstrapCommand { exec_ctx.as_ref().start(self, OutputMode::Capture, OutputMode::Print) } - /// Provides access to the stdlib Command inside. - /// FIXME: This function should be eventually removed from bootstrap. - pub fn as_command_mut(&mut self) -> &mut Command { - // We proactively mark this command as executed since we can't be certain how the returned - // command will be handled. Caching must also be avoided here, as the inner command could be - // modified externally without us being aware. - self.mark_as_executed(); - self.do_not_cache(); - &mut self.command + /// Spawn the command in background, while capturing and returning stdout, and printing stderr. + /// Returns None in dry-mode + #[track_caller] + pub fn stream_capture_stdout( + &'a mut self, + exec_ctx: impl AsRef<ExecutionContext>, + ) -> Option<StreamingCommand> { + exec_ctx.as_ref().stream(self, OutputMode::Capture, OutputMode::Print) } /// Mark the command as being executed, disarming the drop bomb. @@ -449,6 +450,12 @@ enum CommandState<'a> { }, } +pub struct StreamingCommand { + child: Child, + pub stdout: Option<ChildStdout>, + pub stderr: Option<ChildStderr>, +} + #[must_use] pub struct DeferredCommand<'a> { state: CommandState<'a>, @@ -617,6 +624,33 @@ impl ExecutionContext { } exit!(1); } + + /// Spawns the command with configured stdout and stderr handling. + /// + /// Returns None if in dry-run mode or Panics if the command fails to spawn. + pub fn stream( + &self, + command: &mut BootstrapCommand, + stdout: OutputMode, + stderr: OutputMode, + ) -> Option<StreamingCommand> { + command.mark_as_executed(); + if !command.run_in_dry_run && self.dry_run() { + return None; + } + let cmd = &mut command.command; + cmd.stdout(stdout.stdio()); + cmd.stderr(stderr.stdio()); + let child = cmd.spawn(); + let mut child = match child { + Ok(child) => child, + Err(e) => panic!("failed to execute command: {cmd:?}\nERROR: {e}"), + }; + + let stdout = child.stdout.take(); + let stderr = child.stderr.take(); + Some(StreamingCommand { child, stdout, stderr }) + } } impl AsRef<ExecutionContext> for ExecutionContext { @@ -625,6 +659,12 @@ impl AsRef<ExecutionContext> for ExecutionContext { } } +impl StreamingCommand { + pub fn wait(mut self) -> Result<ExitStatus, std::io::Error> { + self.child.wait() + } +} + impl<'a> DeferredCommand<'a> { pub fn wait_for_output(self, exec_ctx: impl AsRef<ExecutionContext>) -> CommandOutput { match self.state { diff --git a/src/bootstrap/src/utils/proc_macro_deps.rs b/src/bootstrap/src/utils/proc_macro_deps.rs index b61fa3bb8d6..21c7fc89d7d 100644 --- a/src/bootstrap/src/utils/proc_macro_deps.rs +++ b/src/bootstrap/src/utils/proc_macro_deps.rs @@ -30,7 +30,6 @@ pub static CRATES: &[&str] = &[ "memchr", "minimal-lexical", "nom", - "once_cell", "pest", "pest_generator", "pest_meta", diff --git a/src/bootstrap/src/utils/render_tests.rs b/src/bootstrap/src/utils/render_tests.rs index 051d7dd9fd4..934699d736b 100644 --- a/src/bootstrap/src/utils/render_tests.rs +++ b/src/bootstrap/src/utils/render_tests.rs @@ -7,7 +7,7 @@ //! to reimplement all the rendering logic in this module because of that. use std::io::{BufRead, BufReader, Read, Write}; -use std::process::{ChildStdout, Stdio}; +use std::process::ChildStdout; use std::time::Duration; use termcolor::{Color, ColorSpec, WriteColor}; @@ -34,50 +34,44 @@ pub(crate) fn try_run_tests( cmd: &mut BootstrapCommand, stream: bool, ) -> bool { - if builder.config.dry_run() { - cmd.mark_as_executed(); + if run_tests(builder, cmd, stream) { return true; } - if !run_tests(builder, cmd, stream) { - if builder.fail_fast { - crate::exit!(1); - } else { - builder.config.exec_ctx().add_to_delay_failure(format!("{cmd:?}")); - false - } - } else { - true + if builder.fail_fast { + crate::exit!(1); } + + builder.config.exec_ctx().add_to_delay_failure(format!("{cmd:?}")); + + false } fn run_tests(builder: &Builder<'_>, cmd: &mut BootstrapCommand, stream: bool) -> bool { - let cmd = cmd.as_command_mut(); - cmd.stdout(Stdio::piped()); - builder.verbose(|| println!("running: {cmd:?}")); - let mut process = cmd.spawn().unwrap(); + let Some(mut streaming_command) = cmd.stream_capture_stdout(&builder.config.exec_ctx) else { + return true; + }; // This runs until the stdout of the child is closed, which means the child exited. We don't // run this on another thread since the builder is not Sync. - let renderer = Renderer::new(process.stdout.take().unwrap(), builder); + let renderer = Renderer::new(streaming_command.stdout.take().unwrap(), builder); if stream { renderer.stream_all(); } else { renderer.render_all(); } - let result = process.wait_with_output().unwrap(); - if !result.status.success() && builder.is_verbose() { + let status = streaming_command.wait().unwrap(); + if !status.success() && builder.is_verbose() { println!( "\n\ncommand did not execute successfully: {cmd:?}\n\ - expected success, got: {}", - result.status + expected success, got: {status}", ); } - result.status.success() + status.success() } struct Renderer<'a> { diff --git a/src/bootstrap/src/utils/tests/mod.rs b/src/bootstrap/src/utils/tests/mod.rs index b8984d1f3aa..59c169b0f2b 100644 --- a/src/bootstrap/src/utils/tests/mod.rs +++ b/src/bootstrap/src/utils/tests/mod.rs @@ -7,6 +7,7 @@ use tempfile::TempDir; use crate::core::builder::Builder; use crate::core::config::DryRun; +use crate::utils::helpers::get_host_target; use crate::{Build, Config, Flags, t}; pub mod git; @@ -91,6 +92,13 @@ impl ConfigBuilder { self.args.push("--set".to_string()); self.args.push("build.submodules=false".to_string()); + // Override any external LLVM set and inhibit CI LLVM; pretend that we're always building + // in-tree LLVM from sources. + self.args.push("--set".to_string()); + self.args.push("llvm.download-ci-llvm=false".to_string()); + self.args.push("--set".to_string()); + self.args.push(format!("target.'{}'.llvm-config=false", get_host_target())); + // Do not mess with the local rustc checkout build directory self.args.push("--build-dir".to_string()); self.args.push(self.directory.join("build").display().to_string()); |
