Refactor Std dist step

This commit is contained in:
Jakub Beránek 2025-08-12 12:29:14 +02:00
parent f8b3c566cc
commit 502dc8df56
No known key found for this signature in database
GPG key ID: 909CD0D26483516B
4 changed files with 62 additions and 33 deletions

View file

@ -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);

View file

@ -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<GeneratedTarball> {
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<StepMetadata> {
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"));

View file

@ -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);

View file

@ -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