From 502dc8df56e37477da5249245cb8074b40a4c2ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 12 Aug 2025 12:29:14 +0200 Subject: [PATCH] Refactor `Std` dist step --- src/bootstrap/src/core/build_steps/compile.rs | 41 ++++++++++------- src/bootstrap/src/core/build_steps/dist.rs | 46 +++++++++++++------ src/bootstrap/src/core/build_steps/install.rs | 2 +- src/bootstrap/src/utils/build_stamp.rs | 6 +-- 4 files changed, 62 insertions(+), 33 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 6ca32aca345e..7b3e5db58f80 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -96,6 +96,30 @@ impl Std { } deps } + + /// Returns true if the standard library will be uplifted from stage 1 for the given + /// `build_compiler` (which determines the stdlib stage) and `target`. + /// + /// Uplifting is enabled if we're building a stage2+ libstd, full bootstrap is + /// disabled and we have a stage1 libstd already compiled for the given target. + pub fn should_be_uplifted_from_stage_1( + builder: &Builder<'_>, + stage: u32, + target: TargetSelection, + ) -> bool { + stage > 1 + && !builder.config.full_bootstrap + // This estimates if a stage1 libstd exists for the given target. If we're not + // cross-compiling, it should definitely exist by the time we're building a stage2 + // libstd. + // Or if we are cross-compiling, and we are building a cross-compiled rustc, then that + // rustc needs to link to a cross-compiled libstd, so again we should have a stage1 + // libstd for the given target prepared. + // Even if we guess wrong in the cross-compiled case, the worst that should happen is + // that we build a fresh stage1 libstd below, and then we immediately uplift it, so we + // don't pay the libstd build cost twice. + && (target == builder.host_target || builder.config.hosts.contains(&target)) + } } impl Step for Std { @@ -193,22 +217,7 @@ impl Step for Std { // Stage of the stdlib that we're building let stage = build_compiler.stage; - // If we're building a stage2+ libstd, full bootstrap is - // disabled and we have a stage1 libstd already compiled for the given target, - // then simply uplift a previously built stage1 library. - if build_compiler.stage > 1 - && !builder.config.full_bootstrap - // This estimates if a stage1 libstd exists for the given target. If we're not - // cross-compiling, it should definitely exist by the time we're building a stage2 - // libstd. - // Or if we are cross-compiling, and we are building a cross-compiled rustc, then that - // rustc needs to link to a cross-compiled libstd, so again we should have a stage1 - // libstd for the given target prepared. - // Even if we guess wrong in the cross-compiled case, the worst that should happen is - // that we build a fresh stage1 libstd below, and then we immediately uplift it, so we - // don't pay the libstd build cost twice. - && (target == builder.host_target || builder.config.hosts.contains(&target)) - { + if Self::should_be_uplifted_from_stage_1(builder, build_compiler.stage, target) { let build_compiler_for_std_to_uplift = builder.compiler(1, builder.host_target); builder.std(build_compiler_for_std_to_uplift, target); diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 29e4a608c3ae..5694688780bf 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -747,9 +747,16 @@ fn copy_target_libs( } } +/// Builds the standard library (`rust-std`) dist component for a given `target`. +/// This includes the standard library dynamic library file (e.g. .so/.dll), along with stdlib +/// .rlibs. +/// +/// Note that due to uplifting, we actually ship the stage 1 library +/// (built using the stage1 compiler) even with a stage 2 dist, unless `full-bootstrap` is enabled. #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct Std { - pub compiler: Compiler, + /// Compiler that will build the standard library. + pub build_compiler: Compiler, pub target: TargetSelection, } @@ -762,31 +769,43 @@ impl Step for Std { } fn make_run(run: RunConfig<'_>) { + // This is a build time optimization for running just `x dist rust-std` (without + // `x dist rustc`). + // If we know that we will be uplifting a stage2+ library from stage 1 anyway, + // there is no point in building a stage2 rustc, which will then not do anything (because + // the stdlib will be uplifted). + let top_stage = run.builder.top_stage; + let stage = if top_stage > 1 + && compile::Std::should_be_uplifted_from_stage_1(run.builder, top_stage, run.target) + { + run.builder.info(&format!( + "Note: stage {top_stage} library for `{}` would be uplifted from stage 1, so stage was downgraded from {top_stage} to 1 to avoid needless compiler build(s)", + run.target + )); + 1 + } else { + top_stage + }; run.builder.ensure(Std { - compiler: run.builder.compiler_for( - run.builder.top_stage, - run.builder.config.host_target, - run.target, - ), + build_compiler: run.builder.compiler(stage, run.builder.config.host_target), target: run.target, }); } fn run(self, builder: &Builder<'_>) -> Option { - let compiler = self.compiler; + let build_compiler = self.build_compiler; let target = self.target; - if skip_host_target_lib(builder, compiler) { + if skip_host_target_lib(builder, build_compiler) { return None; } - builder.std(compiler, target); + builder.std(build_compiler, target); let mut tarball = Tarball::new(builder, "rust-std", &target.triple); tarball.include_target_in_component_name(true); - let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); - let stamp = build_stamp::libstd_stamp(builder, compiler_to_use, target); + let stamp = build_stamp::libstd_stamp(builder, build_compiler, target); verify_uefi_rlib_format(builder, target, &stamp); copy_target_libs(builder, target, tarball.image_dir(), &stamp); @@ -794,7 +813,7 @@ impl Step for Std { } fn metadata(&self) -> Option { - Some(StepMetadata::dist("std", self.target).built_by(self.compiler)) + Some(StepMetadata::dist("std", self.target).built_by(self.build_compiler)) } } @@ -1630,7 +1649,8 @@ impl Step for Extended { // the std files during uninstall. To do this ensure that rustc comes // before rust-std in the list below. tarballs.push(builder.ensure(Rustc { target_compiler })); - tarballs.push(builder.ensure(Std { compiler, target }).expect("missing std")); + tarballs + .push(builder.ensure(Std { build_compiler: compiler, target }).expect("missing std")); if target.is_windows_gnu() { tarballs.push(builder.ensure(Mingw { target }).expect("missing mingw")); diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs index 92e5084d4908..d1c93acd7892 100644 --- a/src/bootstrap/src/core/build_steps/install.rs +++ b/src/bootstrap/src/core/build_steps/install.rs @@ -214,7 +214,7 @@ install!((self, builder, _config), // `expect` should be safe, only None when host != build, but this // only runs when host == build let tarball = builder.ensure(dist::Std { - compiler: self.compiler, + build_compiler: self.compiler, target: self.target }).expect("missing std"); install_sh(builder, "std", self.compiler.stage, Some(self.target), &tarball); diff --git a/src/bootstrap/src/utils/build_stamp.rs b/src/bootstrap/src/utils/build_stamp.rs index 6c79385190e8..4c35388a181a 100644 --- a/src/bootstrap/src/utils/build_stamp.rs +++ b/src/bootstrap/src/utils/build_stamp.rs @@ -136,13 +136,13 @@ pub fn codegen_backend_stamp( } /// Cargo's output path for the standard library in a given stage, compiled -/// by a particular compiler for the specified target. +/// by a particular `build_compiler` for the specified `target`. pub fn libstd_stamp( builder: &Builder<'_>, - compiler: Compiler, + build_compiler: Compiler, target: TargetSelection, ) -> BuildStamp { - BuildStamp::new(&builder.cargo_out(compiler, Mode::Std, target)).with_prefix("libstd") + BuildStamp::new(&builder.cargo_out(build_compiler, Mode::Std, target)).with_prefix("libstd") } /// Cargo's output path for librustc in a given stage, compiled by a particular