Skip to content

Commit db3fd47

Browse files
committed
Auto merge of #145902 - Kobzol:dist-docs-build-compiler, r=jieyouxu
Avoid more rustc rebuilds in cross-compilation scenarios This is a continuation of #145874. It adds a `compiler_for_std` function, which is a slimmed down version of `compiler_for`, which is much simpler, and designed to be used only for the standard library. The build, dist and doc steps somtimes work with a stage2 std for a given target. That currently requires building a stage2 host compiler. However, if we uplift the stage1 libstd anyway, that is wasteful, in particular when we are cross-compiling. The last two commits progressively make the stage 2 host rustc build avoidance more and more aggressive. I think that if we decide that it is fine to ship stage1 libstd everywhere, then it makes sense to go all the way. When we ship stuff, we always build it with the stage 1 compiler (e.g. we ship stage 2 rustc which is built with stage 1 rustc). Libstd is the only component where stage N is built with the stage N compiler. So I think that shipping stage 1 libstd is "enough", and we could thus optimize what gets built on CI. r? `@jieyouxu`
2 parents 41f2b6b + 6864a5b commit db3fd47

File tree

5 files changed

+127
-80
lines changed

5 files changed

+127
-80
lines changed

src/bootstrap/src/core/build_steps/compile.rs

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -99,28 +99,12 @@ impl Std {
9999
deps
100100
}
101101

102-
/// Returns true if the standard library will be uplifted from stage 1 for the given
103-
/// `build_compiler` (which determines the stdlib stage) and `target`.
102+
/// Returns true if the standard library should be uplifted from stage 1.
104103
///
105-
/// Uplifting is enabled if we're building a stage2+ libstd, full bootstrap is
106-
/// disabled and we have a stage1 libstd already compiled for the given target.
107-
pub fn should_be_uplifted_from_stage_1(
108-
builder: &Builder<'_>,
109-
stage: u32,
110-
target: TargetSelection,
111-
) -> bool {
112-
stage > 1
113-
&& !builder.config.full_bootstrap
114-
// This estimates if a stage1 libstd exists for the given target. If we're not
115-
// cross-compiling, it should definitely exist by the time we're building a stage2
116-
// libstd.
117-
// Or if we are cross-compiling, and we are building a cross-compiled rustc, then that
118-
// rustc needs to link to a cross-compiled libstd, so again we should have a stage1
119-
// libstd for the given target prepared.
120-
// Even if we guess wrong in the cross-compiled case, the worst that should happen is
121-
// that we build a fresh stage1 libstd below, and then we immediately uplift it, so we
122-
// don't pay the libstd build cost twice.
123-
&& (target == builder.host_target || builder.config.hosts.contains(&target))
104+
/// Uplifting is enabled if we're building a stage2+ libstd and full bootstrap is
105+
/// disabled.
106+
pub fn should_be_uplifted_from_stage_1(builder: &Builder<'_>, stage: u32) -> bool {
107+
stage > 1 && !builder.config.full_bootstrap
124108
}
125109
}
126110

@@ -150,7 +134,9 @@ impl Step for Std {
150134
trace!(force_recompile);
151135

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

229-
if Self::should_be_uplifted_from_stage_1(builder, build_compiler.stage, target) {
215+
if Self::should_be_uplifted_from_stage_1(builder, build_compiler.stage) {
230216
let build_compiler_for_std_to_uplift = builder.compiler(1, builder.host_target);
231217
let stage_1_stamp = builder.std(build_compiler_for_std_to_uplift, target);
232218

src/bootstrap/src/core/build_steps/dist.rs

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ impl Step for Docs {
9696
}
9797
}
9898

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

114116
fn make_run(run: RunConfig<'_>) {
115117
run.builder.ensure(JsonDocs {
116-
build_compiler: run.builder.compiler(run.builder.top_stage, run.builder.host_target),
118+
build_compiler: run.builder.compiler_for_std(run.builder.top_stage),
117119
target: run.target,
118120
});
119121
}
120122

121-
/// Builds the `rust-docs-json` installer component.
122123
fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
123124
let target = self.target;
124125
let directory = builder.ensure(crate::core::build_steps::doc::Std::from_build_compiler(
@@ -135,6 +136,10 @@ impl Step for JsonDocs {
135136
tarball.add_bulk_dir(directory, dest);
136137
Some(tarball.generate())
137138
}
139+
140+
fn metadata(&self) -> Option<StepMetadata> {
141+
Some(StepMetadata::dist("json-docs", self.target).built_by(self.build_compiler))
142+
}
138143
}
139144

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

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

src/bootstrap/src/core/build_steps/doc.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,7 @@ impl Step for Std {
616616
return;
617617
}
618618
run.builder.ensure(Std {
619-
build_compiler: run.builder.compiler(run.builder.top_stage, run.builder.host_target),
619+
build_compiler: run.builder.compiler_for_std(run.builder.top_stage),
620620
target: run.target,
621621
format: if run.builder.config.cmd.json() {
622622
DocumentationFormat::Json

src/bootstrap/src/core/builder/mod.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1360,6 +1360,30 @@ impl<'a> Builder<'a> {
13601360
self.ensure(compile::Assemble { target_compiler: Compiler::new(stage, host) })
13611361
}
13621362

1363+
/// This function can be used to provide a build compiler for building
1364+
/// the standard library, in order to avoid unnecessary rustc builds in case where std uplifting
1365+
/// would happen anyway.
1366+
///
1367+
/// This is an important optimization mainly for CI.
1368+
///
1369+
/// Normally, to build stage N libstd, we need stage N rustc.
1370+
/// However, if we know that we will uplift libstd from stage 1 anyway, building the stage N
1371+
/// rustc can be wasteful.
1372+
/// In particular, if we do a cross-compiling dist stage 2 build from target1 to target2,
1373+
/// we need:
1374+
/// - stage 2 libstd for target2 (uplifted from stage 1, where it was built by target1 rustc)
1375+
/// - stage 2 rustc for target2
1376+
///
1377+
/// However, without this optimization, we would also build stage 2 rustc for **target1**,
1378+
/// which is completely wasteful.
1379+
pub fn compiler_for_std(&self, stage: u32) -> Compiler {
1380+
if compile::Std::should_be_uplifted_from_stage_1(self, stage) {
1381+
self.compiler(1, self.host_target)
1382+
} else {
1383+
self.compiler(stage, self.host_target)
1384+
}
1385+
}
1386+
13631387
/// Similar to `compiler`, except handles the full-bootstrap option to
13641388
/// silently use the stage1 compiler instead of a stage2 compiler if one is
13651389
/// requested.

0 commit comments

Comments
 (0)