Rollup merge of #145557 - Kobzol:rustc-link-fix, r=jieyouxu

Fix uplifting in `Assemble` step

In https://github.com/rust-lang/rust/pull/145310, I removed [this line](https://github.com/rust-lang/rust/pull/145310/files#diff-5a1e05f2688d271039171a547d407d0c8a96715ee64d35562fc76b4c9a874303L2109), which adjusted the stage of the build compiler if an uplift has happened. This broke stage3+ uplifted rustc builds (https://github.com/rust-lang/rust/issues/145534). I could swear I tested this in the PR, but somehow I missed it.

Instead of keeping the original returned stage, I made it more explicit by returning the actually used `build_compiler` from the `Rustc` step, and then use that in the `Assemble` step.

The changes to `RustcLink` were needed to fix `ui-fulldeps`, which apparently build a stage3 rustc, because I haven't fixed the test steps yet 😅

Hopefully we might be able to remove `RustcLink` if the approach from https://github.com/rust-lang/rust/pull/144252 will work.

Should fix https://github.com/rust-lang/rust/issues/145534.

r? ``@jieyouxu``
This commit is contained in:
Stuart Cook 2025-08-19 14:18:26 +10:00 committed by GitHub
commit cf2f50e332
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -933,6 +933,15 @@ fn cp_rustc_component_to_ci_sysroot(builder: &Builder<'_>, sysroot: &Path, conte
}
}
/// Represents information about a built rustc.
#[derive(Clone, Debug)]
pub struct BuiltRustc {
/// The compiler that actually built this *rustc*.
/// This can be different from the *build_compiler* passed to the `Rustc` step because of
/// uplifting.
pub build_compiler: Compiler,
}
/// Build rustc using the passed `build_compiler`.
///
/// - Makes sure that `build_compiler` has a standard library prepared for its host target,
@ -960,7 +969,7 @@ impl Rustc {
}
impl Step for Rustc {
type Output = ();
type Output = BuiltRustc;
const IS_HOST: bool = true;
const DEFAULT: bool = false;
@ -1000,7 +1009,7 @@ impl Step for Rustc {
/// This will build the compiler for a particular stage of the build using
/// the `build_compiler` targeting the `target` architecture. The artifacts
/// created will also be linked into the sysroot directory.
fn run(self, builder: &Builder<'_>) {
fn run(self, builder: &Builder<'_>) -> Self::Output {
let build_compiler = self.build_compiler;
let target = self.target;
@ -1016,7 +1025,7 @@ impl Step for Rustc {
&sysroot,
builder.config.ci_rustc_dev_contents(),
);
return;
return BuiltRustc { build_compiler };
}
// Build a standard library for `target` using the `build_compiler`.
@ -1028,9 +1037,9 @@ impl Step for Rustc {
builder.info("WARNING: Using a potentially old librustc. This may not behave well.");
builder.info("WARNING: Use `--keep-stage-std` if you want to rebuild the compiler when it changes");
builder.ensure(RustcLink::from_rustc(self, build_compiler));
builder.ensure(RustcLink::from_rustc(self));
return;
return BuiltRustc { build_compiler };
}
// The stage of the compiler that we're building
@ -1042,21 +1051,35 @@ impl Step for Rustc {
&& !builder.config.full_bootstrap
&& (target == builder.host_target || builder.hosts.contains(&target))
{
// If we're cross-compiling, the earliest rustc that we could have is stage 2.
// If we're not cross-compiling, then we should have rustc stage 1.
let stage_to_uplift = if target == builder.host_target { 1 } else { 2 };
let rustc_to_uplift = builder.compiler(stage_to_uplift, target);
let msg = if rustc_to_uplift.host == target {
format!("Uplifting rustc (stage{} -> stage{stage})", rustc_to_uplift.stage,)
// Here we need to determine the **build compiler** that built the stage that we will
// be uplifting. We cannot uplift stage 1, as it has a different ABI than stage 2+,
// so we always uplift the stage2 compiler (compiled with stage 1).
let uplift_build_compiler = builder.compiler(1, build_compiler.host);
let msg = if uplift_build_compiler.host == target {
format!("Uplifting rustc (stage2 -> stage{stage})")
} else {
format!(
"Uplifting rustc (stage{}:{} -> stage{stage}:{target})",
rustc_to_uplift.stage, rustc_to_uplift.host,
"Uplifting rustc (stage2:{} -> stage{stage}:{target})",
uplift_build_compiler.host
)
};
builder.info(&msg);
builder.ensure(RustcLink::from_rustc(self, rustc_to_uplift));
return;
// Here the compiler that built the rlibs (`uplift_build_compiler`) can be different
// from the compiler whose sysroot should be modified in this step. So we need to copy
// the (previously built) rlibs into the correct sysroot.
builder.ensure(RustcLink::from_build_compiler_and_sysroot(
// This is the compiler that actually built the rustc rlibs
uplift_build_compiler,
// We copy the rlibs into the sysroot of `build_compiler`
build_compiler,
target,
self.crates,
));
// Here we have performed an uplift, so we return the actual build compiler that "built"
// this rustc.
return BuiltRustc { build_compiler: uplift_build_compiler };
}
// Build a standard library for the current host target using the `build_compiler`.
@ -1129,10 +1152,8 @@ impl Step for Rustc {
strip_debug(builder, target, &target_root_dir.join("rustc-main"));
}
builder.ensure(RustcLink::from_rustc(
self,
builder.compiler(build_compiler.stage, builder.config.host_target),
));
builder.ensure(RustcLink::from_rustc(self));
BuiltRustc { build_compiler }
}
fn metadata(&self) -> Option<StepMetadata> {
@ -1441,31 +1462,51 @@ fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelect
}
}
/// `RustcLink` copies all of the rlibs from the rustc build into the previous stage's sysroot.
/// `RustcLink` copies compiler rlibs from a rustc build into a compiler sysroot.
/// It works with (potentially up to) three compilers:
/// - `build_compiler` is a compiler that built rustc rlibs
/// - `sysroot_compiler` is a compiler into whose sysroot we will copy the rlibs
/// - In most situations, `build_compiler` == `sysroot_compiler`
/// - `target_compiler` is the compiler whose rlibs were built. It is not represented explicitly
/// in this step, rather we just read the rlibs from a rustc build stamp of `build_compiler`.
///
/// This is necessary for tools using `rustc_private`, where the previous compiler will build
/// a tool against the next compiler.
/// To build a tool against a compiler, the rlibs of that compiler that it links against
/// must be in the sysroot of the compiler that's doing the compiling.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct RustcLink {
/// The compiler whose rlibs we are copying around.
pub compiler: Compiler,
/// This is the compiler into whose sysroot we want to copy the rlibs into.
pub previous_stage_compiler: Compiler,
pub target: TargetSelection,
/// This compiler **built** some rustc, whose rlibs we will copy into a sysroot.
build_compiler: Compiler,
/// This is the compiler into whose sysroot we want to copy the built rlibs.
/// In most cases, it will correspond to `build_compiler`.
sysroot_compiler: Compiler,
target: TargetSelection,
/// Not actually used; only present to make sure the cache invalidation is correct.
crates: Vec<String>,
}
impl RustcLink {
fn from_rustc(rustc: Rustc, host_compiler: Compiler) -> Self {
/// Copy rlibs from the build compiler that build this `rustc` into the sysroot of that
/// build compiler.
fn from_rustc(rustc: Rustc) -> Self {
Self {
compiler: host_compiler,
previous_stage_compiler: rustc.build_compiler,
build_compiler: rustc.build_compiler,
sysroot_compiler: rustc.build_compiler,
target: rustc.target,
crates: rustc.crates,
}
}
/// Copy rlibs **built** by `build_compiler` into the sysroot of `sysroot_compiler`.
fn from_build_compiler_and_sysroot(
build_compiler: Compiler,
sysroot_compiler: Compiler,
target: TargetSelection,
crates: Vec<String>,
) -> Self {
Self { build_compiler, sysroot_compiler, target, crates }
}
}
impl Step for RustcLink {
@ -1477,14 +1518,14 @@ impl Step for RustcLink {
/// Same as `std_link`, only for librustc
fn run(self, builder: &Builder<'_>) {
let compiler = self.compiler;
let previous_stage_compiler = self.previous_stage_compiler;
let build_compiler = self.build_compiler;
let sysroot_compiler = self.sysroot_compiler;
let target = self.target;
add_to_sysroot(
builder,
&builder.sysroot_target_libdir(previous_stage_compiler, target),
&builder.sysroot_target_libdir(previous_stage_compiler, compiler.host),
&build_stamp::librustc_stamp(builder, compiler, target),
&builder.sysroot_target_libdir(sysroot_compiler, target),
&builder.sysroot_target_libdir(sysroot_compiler, sysroot_compiler.host),
&build_stamp::librustc_stamp(builder, build_compiler, target),
);
}
}
@ -2099,7 +2140,10 @@ impl Step for Assemble {
"target_compiler.host" = ?target_compiler.host,
"building compiler libraries to link to"
);
builder.ensure(Rustc::new(build_compiler, target_compiler.host));
// It is possible that an uplift has happened, so we override build_compiler here.
let BuiltRustc { build_compiler } =
builder.ensure(Rustc::new(build_compiler, target_compiler.host));
let stage = target_compiler.stage;
let host = target_compiler.host;