Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 9 additions & 23 deletions src/bootstrap/src/core/build_steps/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,28 +99,12 @@ 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`.
/// Returns true if the standard library should be uplifted from stage 1.
///
/// 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))
/// Uplifting is enabled if we're building a stage2+ libstd and full bootstrap is
/// disabled.
pub fn should_be_uplifted_from_stage_1(builder: &Builder<'_>, stage: u32) -> bool {
stage > 1 && !builder.config.full_bootstrap
}
}

Expand Down Expand Up @@ -150,7 +134,9 @@ impl Step for Std {
trace!(force_recompile);

run.builder.ensure(Std {
build_compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()),
// Note: we don't use compiler_for_std here, so that `x build library --stage 2`
// builds a stage2 rustc.
build_compiler: run.builder.compiler(run.builder.top_stage, builder.host_target),
target: run.target,
crates,
force_recompile,
Expand Down Expand Up @@ -226,7 +212,7 @@ impl Step for Std {
// Stage of the stdlib that we're building
let stage = build_compiler.stage;

if Self::should_be_uplifted_from_stage_1(builder, build_compiler.stage, target) {
if Self::should_be_uplifted_from_stage_1(builder, build_compiler.stage) {
let build_compiler_for_std_to_uplift = builder.compiler(1, builder.host_target);
let stage_1_stamp = builder.std(build_compiler_for_std_to_uplift, target);

Expand Down
26 changes: 8 additions & 18 deletions src/bootstrap/src/core/build_steps/dist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ impl Step for Docs {
}
}

/// Builds the `rust-docs-json` installer component.
/// It contains the documentation of the standard library in JSON format.
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct JsonDocs {
build_compiler: Compiler,
Expand All @@ -113,12 +115,11 @@ impl Step for JsonDocs {

fn make_run(run: RunConfig<'_>) {
run.builder.ensure(JsonDocs {
build_compiler: run.builder.compiler(run.builder.top_stage, run.builder.host_target),
build_compiler: run.builder.compiler_for_std(run.builder.top_stage),
target: run.target,
});
}

/// Builds the `rust-docs-json` installer component.
fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
let target = self.target;
let directory = builder.ensure(crate::core::build_steps::doc::Std::from_build_compiler(
Expand All @@ -135,6 +136,10 @@ impl Step for JsonDocs {
tarball.add_bulk_dir(directory, dest);
Some(tarball.generate())
}

fn metadata(&self) -> Option<StepMetadata> {
Some(StepMetadata::dist("json-docs", self.target).built_by(self.build_compiler))
}
}

/// Builds the `rustc-docs` installer component.
Expand Down Expand Up @@ -764,22 +769,7 @@ pub struct Std {

impl Std {
pub fn new(builder: &Builder<'_>, target: TargetSelection) -> Self {
// This is an important optimization mainly for CI.
// Normally, to build stage N libstd, we need stage N rustc.
// However, if we know that we will uplift libstd from stage 1 anyway, building the stage N
// rustc can be wasteful.
// In particular, if we do a cross-compiling dist stage 2 build from T1 to T2, we need:
// - stage 2 libstd for T2 (uplifted from stage 1, where it was built by T1 rustc)
// - stage 2 rustc for T2
// However, without this optimization, we would also build stage 2 rustc for **T1**, which
// is completely wasteful.
let build_compiler =
if compile::Std::should_be_uplifted_from_stage_1(builder, builder.top_stage, target) {
builder.compiler(1, builder.host_target)
} else {
builder.compiler(builder.top_stage, builder.host_target)
};
Std { build_compiler, target }
Std { build_compiler: builder.compiler_for_std(builder.top_stage), target }
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/bootstrap/src/core/build_steps/doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -616,7 +616,7 @@ impl Step for Std {
return;
}
run.builder.ensure(Std {
build_compiler: run.builder.compiler(run.builder.top_stage, run.builder.host_target),
build_compiler: run.builder.compiler_for_std(run.builder.top_stage),
target: run.target,
format: if run.builder.config.cmd.json() {
DocumentationFormat::Json
Expand Down
24 changes: 24 additions & 0 deletions src/bootstrap/src/core/builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1360,6 +1360,30 @@ impl<'a> Builder<'a> {
self.ensure(compile::Assemble { target_compiler: Compiler::new(stage, host) })
}

/// This function can be used to provide a build compiler for building
/// the standard library, in order to avoid unnecessary rustc builds in case where std uplifting
/// would happen anyway.
///
/// This is an important optimization mainly for CI.
///
/// Normally, to build stage N libstd, we need stage N rustc.
/// However, if we know that we will uplift libstd from stage 1 anyway, building the stage N
/// rustc can be wasteful.
/// In particular, if we do a cross-compiling dist stage 2 build from target1 to target2,
/// we need:
/// - stage 2 libstd for target2 (uplifted from stage 1, where it was built by target1 rustc)
/// - stage 2 rustc for target2
///
/// However, without this optimization, we would also build stage 2 rustc for **target1**,
/// which is completely wasteful.
pub fn compiler_for_std(&self, stage: u32) -> Compiler {
if compile::Std::should_be_uplifted_from_stage_1(self, stage) {
self.compiler(1, self.host_target)
} else {
self.compiler(stage, self.host_target)
}
}

/// Similar to `compiler`, except handles the full-bootstrap option to
/// silently use the stage1 compiler instead of a stage2 compiler if one is
/// requested.
Expand Down
Loading
Loading