Skip to content

Commit 424ee44

Browse files
committed
Auto merge of rust-lang#119899 - onur-ozkan:redesign-stage0-std, r=<try>
redesign stage 0 std ### Summary This PR changes how bootstrap builds the stage 1 compiler by switching to precompiled stage 0 standard library instead of building the in-tree one. The goal was to update bootstrap to use the beta standard library at stage 0 rather than compiling it from source (see the motivation at rust-lang/compiler-team#619). Previously, to build a stage 1 compiler bootstrap followed this path: ``` download stage0 compiler -> build in-tree std -> compile stage1 compiler with in-tree std ``` With this PR, the new path is: ``` download stage0 compiler -> compile stage1 compiler with precompiled stage0 std ``` This also means that `cfg(bootstrap)`/`cfg(not(bootstrap))` is no longer needed for library development. ### Building "library" Since stage0 `std` is no longer in-tree `x build/test/check library --stage 0` is now no-op. The minimum supported stage to build `std` is now 1. For the same reason, default stage values in the library profile is no longer 0. Because building the in-tree library now requires a stage1 compiler, I highly recommend library developers to enable `download-rustc` to speed up compilation time. <hr> If you encounter a bug or unexpected results please open a topic in the [#t-infra/bootstrap](https://rust-lang.zulipchat.com/#narrow/channel/326414-t-infra.2Fbootstrap) Zulip channel or create a [bootstrap issue](https://github.com./rust-lang/rust/issues/new?template=bootstrap.md). (Review thread: https://rust-lang.zulipchat.com/#narrow/channel/326414-t-infra.2Fbootstrap/topic/Review.20thread.3A.20stage.200.20redesign.20PR/with/508271433) ~~Blocked on rust-lang#122709 try-job: dist-x86_64-linux
2 parents 69b3959 + d6f178a commit 424ee44

File tree

30 files changed

+238
-262
lines changed

30 files changed

+238
-262
lines changed

Diff for: compiler/rustc_span/src/analyze_source_file.rs

+2
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ cfg_match! {
8484
// For character in the chunk, see if its byte value is < 0, which
8585
// indicates that it's part of a UTF-8 char.
8686
let multibyte_test = _mm_cmplt_epi8(chunk, _mm_set1_epi8(0));
87+
8788
// Create a bit mask from the comparison results.
8889
let multibyte_mask = _mm_movemask_epi8(multibyte_test);
8990

@@ -93,6 +94,7 @@ cfg_match! {
9394

9495
// Check for newlines in the chunk
9596
let newlines_test = _mm_cmpeq_epi8(chunk, _mm_set1_epi8(b'\n' as i8));
97+
9698
let mut newlines_mask = _mm_movemask_epi8(newlines_test);
9799

98100
let output_offset = RelativeBytePos::from_usize(chunk_index * CHUNK_SIZE + 1);

Diff for: library/core/src/fmt/rt.rs

-8
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,6 @@ pub struct Placeholder {
1616
pub width: Count,
1717
}
1818

19-
#[cfg(bootstrap)]
20-
impl Placeholder {
21-
#[inline]
22-
pub const fn new(position: usize, flags: u32, precision: Count, width: Count) -> Self {
23-
Self { position, flags, precision, width }
24-
}
25-
}
26-
2719
/// Used by [width](https://doc.rust-lang.org/std/fmt/#width)
2820
/// and [precision](https://doc.rust-lang.org/std/fmt/#precision) specifiers.
2921
#[lang = "format_count"]

Diff for: src/bootstrap/defaults/bootstrap.library.toml

+7-6
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
# These defaults are meant for contributors to the standard library and documentation.
22
[build]
3-
# When building the standard library, you almost never want to build the compiler itself.
4-
build-stage = 0
5-
test-stage = 0
6-
bench-stage = 0
3+
build-stage = 1
4+
test-stage = 1
5+
bench-stage = 1
76

87
[rust]
98
# This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower.
109
incremental = true
1110
# Make the compiler and standard library faster to build, at the expense of a ~20% runtime slowdown.
1211
lto = "off"
13-
# Download rustc by default for library profile if compiler-affecting
14-
# directories are not modified. For CI this is disabled.
12+
# When building the standard library, you almost never want to build the compiler itself.
13+
#
14+
# If compiler-affecting directories are not modified, use precompiled rustc to speed up
15+
# library development by skipping compiler builds.
1516
download-rustc = "if-unchanged"
1617

1718
[llvm]

Diff for: src/bootstrap/src/core/build_steps/check.rs

+9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Implementation of compiling the compiler and standard library, in "check"-based modes.
22
3+
use crate::core::build_steps::compile;
34
use crate::core::build_steps::compile::{
45
add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, std_crates_for_run_make,
56
};
@@ -45,10 +46,12 @@ impl Step for Std {
4546
const DEFAULT: bool = true;
4647

4748
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
49+
let stage = run.builder.top_stage;
4850
run.crate_or_deps("sysroot")
4951
.crate_or_deps("coretests")
5052
.crate_or_deps("alloctests")
5153
.path("library")
54+
.default_condition(stage != 0)
5255
}
5356

5457
fn make_run(run: RunConfig<'_>) {
@@ -62,6 +65,12 @@ impl Step for Std {
6265
let target = self.target;
6366
let compiler = builder.compiler(builder.top_stage, builder.config.build);
6467

68+
if builder.top_stage == 0 {
69+
// Reuse the stage0 libstd
70+
builder.ensure(compile::Std::new(compiler, target));
71+
return;
72+
}
73+
6574
let mut cargo = builder::Cargo::new(
6675
builder,
6776
compiler,

Diff for: src/bootstrap/src/core/build_steps/clippy.rs

+15-11
Original file line numberDiff line numberDiff line change
@@ -207,16 +207,18 @@ impl Step for Rustc {
207207
let compiler = builder.compiler(builder.top_stage, builder.config.build);
208208
let target = self.target;
209209

210-
if compiler.stage != 0 {
211-
// If we're not in stage 0, then we won't have a std from the beta
212-
// compiler around. That means we need to make sure there's one in
213-
// the sysroot for the compiler to find. Otherwise, we're going to
214-
// fail when building crates that need to generate code (e.g., build
215-
// scripts and their dependencies).
216-
builder.ensure(compile::Std::new(compiler, compiler.host));
217-
builder.ensure(compile::Std::new(compiler, target));
218-
} else {
219-
builder.ensure(check::Std::new(target).build_kind(Some(Kind::Check)));
210+
if !builder.download_rustc() {
211+
if compiler.stage != 0 {
212+
// If we're not in stage 0, then we won't have a std from the beta
213+
// compiler around. That means we need to make sure there's one in
214+
// the sysroot for the compiler to find. Otherwise, we're going to
215+
// fail when building crates that need to generate code (e.g., build
216+
// scripts and their dependencies).
217+
builder.ensure(compile::Std::new(compiler, compiler.host));
218+
builder.ensure(compile::Std::new(compiler, target));
219+
} else {
220+
builder.ensure(check::Std::new(target).build_kind(Some(Kind::Check)));
221+
}
220222
}
221223

222224
let mut cargo = builder::Cargo::new(
@@ -286,7 +288,9 @@ macro_rules! lint_any {
286288
let compiler = builder.compiler(builder.top_stage, builder.config.build);
287289
let target = self.target;
288290

289-
builder.ensure(check::Rustc::new(target, builder).build_kind(Some(Kind::Check)));
291+
if !builder.download_rustc() {
292+
builder.ensure(check::Rustc::new(target, builder).build_kind(Some(Kind::Check)));
293+
};
290294

291295
let cargo = prepare_tool_cargo(
292296
builder,

Diff for: src/bootstrap/src/core/build_steps/compile.rs

+60-60
Original file line numberDiff line numberDiff line change
@@ -151,16 +151,26 @@ impl Step for Std {
151151
)]
152152
fn run(self, builder: &Builder<'_>) {
153153
let target = self.target;
154-
let compiler = self.compiler;
154+
155+
// We already have std ready to be used for stage 0.
156+
if self.compiler.stage == 0 {
157+
let compiler = self.compiler;
158+
builder.ensure(StdLink::from_std(self, compiler));
159+
160+
return;
161+
}
162+
163+
let compiler = if builder.download_rustc() && self.force_recompile {
164+
// When there are changes in the library tree with CI-rustc, we want to build
165+
// the stageN library and that requires using stageN-1 compiler.
166+
builder.compiler(self.compiler.stage.saturating_sub(1), builder.config.build)
167+
} else {
168+
self.compiler
169+
};
155170

156171
// When using `download-rustc`, we already have artifacts for the host available. Don't
157172
// recompile them.
158-
if builder.download_rustc() && builder.is_builder_target(target)
159-
// NOTE: the beta compiler may generate different artifacts than the downloaded compiler, so
160-
// its artifacts can't be reused.
161-
&& compiler.stage != 0
162-
&& !self.force_recompile
163-
{
173+
if builder.download_rustc() && builder.is_builder_target(target) && !self.force_recompile {
164174
let sysroot = builder.ensure(Sysroot { compiler, force_recompile: false });
165175
cp_rustc_component_to_ci_sysroot(
166176
builder,
@@ -193,7 +203,13 @@ impl Step for Std {
193203
let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
194204
trace!(?compiler_to_use);
195205

196-
if compiler_to_use != compiler {
206+
if compiler_to_use != compiler
207+
// Never uplift std unless we have compiled stage 1; if stage 1 is compiled,
208+
// uplift it from there.
209+
//
210+
// FIXME: improve `fn compiler_for` to avoid adding stage condition here.
211+
&& compiler.stage > 1
212+
{
197213
trace!(?compiler_to_use, ?compiler, "compiler != compiler_to_use, uplifting library");
198214

199215
builder.ensure(Std::new(compiler_to_use, target));
@@ -226,27 +242,6 @@ impl Step for Std {
226242

227243
target_deps.extend(self.copy_extra_objects(builder, &compiler, target));
228244

229-
// The LLD wrappers and `rust-lld` are self-contained linking components that can be
230-
// necessary to link the stdlib on some targets. We'll also need to copy these binaries to
231-
// the `stage0-sysroot` to ensure the linker is found when bootstrapping on such a target.
232-
if compiler.stage == 0 && builder.is_builder_target(compiler.host) {
233-
trace!(
234-
"(build == host) copying linking components to `stage0-sysroot` for bootstrapping"
235-
);
236-
// We want to copy the host `bin` folder within the `rustlib` folder in the sysroot.
237-
let src_sysroot_bin = builder
238-
.rustc_snapshot_sysroot()
239-
.join("lib")
240-
.join("rustlib")
241-
.join(compiler.host)
242-
.join("bin");
243-
if src_sysroot_bin.exists() {
244-
let target_sysroot_bin = builder.sysroot_target_bindir(compiler, target);
245-
t!(fs::create_dir_all(&target_sysroot_bin));
246-
builder.cp_link_r(&src_sysroot_bin, &target_sysroot_bin);
247-
}
248-
}
249-
250245
// We build a sysroot for mir-opt tests using the same trick that Miri does: A check build
251246
// with -Zalways-encode-mir. This frees us from the need to have a target linker, and the
252247
// fact that this is a check build integrates nicely with run_cargo.
@@ -741,7 +736,7 @@ impl Step for StdLink {
741736
let target = self.target;
742737

743738
// NOTE: intentionally does *not* check `target == builder.build` to avoid having to add the same check in `test::Crate`.
744-
let (libdir, hostdir) = if self.force_recompile && builder.download_rustc() {
739+
let (libdir, hostdir) = if !self.force_recompile && builder.download_rustc() {
745740
// NOTE: copies part of `sysroot_libdir` to avoid having to add a new `force_recompile` argument there too
746741
let lib = builder.sysroot_libdir_relative(self.compiler);
747742
let sysroot = builder.ensure(crate::core::build_steps::compile::Sysroot {
@@ -757,23 +752,16 @@ impl Step for StdLink {
757752
(libdir, hostdir)
758753
};
759754

760-
add_to_sysroot(
761-
builder,
762-
&libdir,
763-
&hostdir,
764-
&build_stamp::libstd_stamp(builder, compiler, target),
765-
);
755+
let is_downloaded_beta_stage0 = builder
756+
.build
757+
.config
758+
.initial_rustc
759+
.starts_with(builder.out.join(compiler.host).join("stage0/bin"));
766760

767761
// Special case for stage0, to make `rustup toolchain link` and `x dist --stage 0`
768762
// work for stage0-sysroot. We only do this if the stage0 compiler comes from beta,
769763
// and is not set to a custom path.
770-
if compiler.stage == 0
771-
&& builder
772-
.build
773-
.config
774-
.initial_rustc
775-
.starts_with(builder.out.join(compiler.host).join("stage0/bin"))
776-
{
764+
if compiler.stage == 0 && is_downloaded_beta_stage0 {
777765
// Copy bin files from stage0/bin to stage0-sysroot/bin
778766
let sysroot = builder.out.join(compiler.host).join("stage0-sysroot");
779767

@@ -783,21 +771,9 @@ impl Step for StdLink {
783771
t!(fs::create_dir_all(&sysroot_bin_dir));
784772
builder.cp_link_r(&stage0_bin_dir, &sysroot_bin_dir);
785773

786-
// Copy all files from stage0/lib to stage0-sysroot/lib
787774
let stage0_lib_dir = builder.out.join(host).join("stage0/lib");
788-
if let Ok(files) = fs::read_dir(stage0_lib_dir) {
789-
for file in files {
790-
let file = t!(file);
791-
let path = file.path();
792-
if path.is_file() {
793-
builder.copy_link(
794-
&path,
795-
&sysroot.join("lib").join(path.file_name().unwrap()),
796-
FileType::Regular,
797-
);
798-
}
799-
}
800-
}
775+
t!(fs::create_dir_all(sysroot.join("lib")));
776+
builder.cp_link_r(&stage0_lib_dir, &sysroot.join("lib"));
801777

802778
// Copy codegen-backends from stage0
803779
let sysroot_codegen_backends = builder.sysroot_codegen_backends(compiler);
@@ -811,6 +787,30 @@ impl Step for StdLink {
811787
if stage0_codegen_backends.exists() {
812788
builder.cp_link_r(&stage0_codegen_backends, &sysroot_codegen_backends);
813789
}
790+
} else if compiler.stage == 0 {
791+
let sysroot = builder.out.join(compiler.host.triple).join("stage0-sysroot");
792+
793+
if builder.local_rebuild {
794+
// On local rebuilds this path might be a symlink to the project root,
795+
// which can be read-only (e.g., on CI). So remove it before copying
796+
// the stage0 lib.
797+
let _ = fs::remove_dir_all(sysroot.join("lib/rustlib/src/rust"));
798+
}
799+
800+
builder.cp_link_r(&builder.initial_sysroot.join("lib"), &sysroot.join("lib"));
801+
} else {
802+
if builder.download_rustc() {
803+
// Ensure there are no CI-rustc std artifacts.
804+
let _ = fs::remove_dir_all(&libdir);
805+
let _ = fs::remove_dir_all(&hostdir);
806+
}
807+
808+
add_to_sysroot(
809+
builder,
810+
&libdir,
811+
&hostdir,
812+
&build_stamp::libstd_stamp(builder, compiler, target),
813+
);
814814
}
815815
}
816816
}
@@ -1033,7 +1033,7 @@ impl Step for Rustc {
10331033
let compiler = self.compiler;
10341034
let target = self.target;
10351035

1036-
// NOTE: the ABI of the beta compiler is different from the ABI of the downloaded compiler,
1036+
// NOTE: the ABI of the stage0 compiler is different from the ABI of the downloaded compiler,
10371037
// so its artifacts can't be reused.
10381038
if builder.download_rustc() && compiler.stage != 0 {
10391039
trace!(stage = compiler.stage, "`download_rustc` requested");
@@ -1788,9 +1788,9 @@ impl Step for Sysroot {
17881788
t!(fs::create_dir_all(&sysroot));
17891789

17901790
// In some cases(see https://github.com./rust-lang/rust/issues/109314), when the stage0
1791-
// compiler relies on more recent version of LLVM than the beta compiler, it may not
1791+
// compiler relies on more recent version of LLVM than the stage0 compiler, it may not
17921792
// be able to locate the correct LLVM in the sysroot. This situation typically occurs
1793-
// when we upgrade LLVM version while the beta compiler continues to use an older version.
1793+
// when we upgrade LLVM version while the stage0 compiler continues to use an older version.
17941794
//
17951795
// Make sure to add the correct version of LLVM into the stage0 sysroot.
17961796
if compiler.stage == 0 {

Diff for: src/bootstrap/src/core/build_steps/test.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -1558,7 +1558,7 @@ impl Step for Compiletest {
15581558

15591559
if builder.top_stage == 0 && env::var("COMPILETEST_FORCE_STAGE0").is_err() {
15601560
eprintln!("\
1561-
ERROR: `--stage 0` runs compiletest on the beta compiler, not your local changes, and will almost always cause tests to fail
1561+
ERROR: `--stage 0` runs compiletest on the stage0 (precompiled) compiler, not your local changes, and will almost always cause tests to fail
15621562
HELP: to test the compiler, use `--stage 1` instead
15631563
HELP: to test the standard library, use `--stage 0 library/std` instead
15641564
NOTE: if you're sure you want to do this, please open an issue as to why. In the meantime, you can override this with `COMPILETEST_FORCE_STAGE0=1`."
@@ -1586,9 +1586,9 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
15861586
// NOTE: Only stage 1 is special cased because we need the rustc_private artifacts to match the
15871587
// running compiler in stage 2 when plugins run.
15881588
let (stage, stage_id) = if suite == "ui-fulldeps" && compiler.stage == 1 {
1589-
// At stage 0 (stage - 1) we are using the beta compiler. Using `self.target` can lead
1590-
// finding an incorrect compiler path on cross-targets, as the stage 0 beta compiler is
1591-
// always equal to `build.build` in the configuration.
1589+
// At stage 0 (stage - 1) we are using the stage0 compiler. Using `self.target` can lead
1590+
// finding an incorrect compiler path on cross-targets, as the stage 0 is always equal to
1591+
// `build.build` in the configuration.
15921592
let build = builder.build.build;
15931593
compiler = builder.compiler(compiler.stage - 1, build);
15941594
let test_stage = compiler.stage + 1;
@@ -1674,7 +1674,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
16741674
}
16751675

16761676
if mode == "rustdoc-json" {
1677-
// Use the beta compiler for jsondocck
1677+
// Use the stage0 compiler for jsondocck
16781678
let json_compiler = compiler.with_stage(0);
16791679
cmd.arg("--jsondocck-path")
16801680
.arg(builder.ensure(tool::JsonDocCk { compiler: json_compiler, target }).tool_path);

Diff for: src/bootstrap/src/core/build_steps/tool.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -330,9 +330,9 @@ pub(crate) fn get_tool_rustc_compiler(
330330
return target_compiler;
331331
}
332332

333-
if builder.download_rustc() && target_compiler.stage > 0 {
334-
// We already have the stage N compiler, we don't need to cut the stage.
335-
return builder.compiler(target_compiler.stage, builder.config.build);
333+
if builder.download_rustc() && target_compiler.stage == 1 {
334+
// We shouldn't drop to stage0 compiler when using CI rustc.
335+
return builder.compiler(1, builder.config.build);
336336
}
337337

338338
// Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise

0 commit comments

Comments
 (0)