Skip to content

Commit 694b14c

Browse files
committed
Enable building/disting standard library in stage 0
1 parent 4356e83 commit 694b14c

File tree

5 files changed

+79
-26
lines changed

5 files changed

+79
-26
lines changed

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,13 @@ impl Step for Std {
167167
fn run(self, builder: &Builder<'_>) -> Self::Output {
168168
let target = self.target;
169169

170-
// We already have std ready to be used for stage 0.
171-
if self.build_compiler.stage == 0 {
170+
// In most cases, we already have the std ready to be used for stage 0.
171+
// However, if we are doing a local rebuild (so the build compiler can compile the standard
172+
// library even on stage 0), and we're cross-compiling (so the stage0 standard library for
173+
// *target* is not available), we still allow the stdlib to be built here.
174+
if self.build_compiler.stage == 0
175+
&& !(builder.local_rebuild && target != builder.host_target)
176+
{
172177
let compiler = self.build_compiler;
173178
builder.ensure(StdLink::from_std(self, compiler));
174179

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

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1432,22 +1432,30 @@ impl<'a> Builder<'a> {
14321432
// FIXME: make the `Std` step return some type-level "proof" that std was indeed built,
14331433
// and then require passing that to all Cargo invocations that we do.
14341434

1435-
// The "stage 0" std is always precompiled and comes with the stage0 compiler, so we have
1436-
// special logic for it, to avoid creating needless and confusing Std steps that don't
1435+
// The "stage 0" std is almost always precompiled and comes with the stage0 compiler, so we
1436+
// have special logic for it, to avoid creating needless and confusing Std steps that don't
14371437
// actually build anything.
1438+
// We only allow building the stage0 stdlib if we do a local rebuild, so the stage0 compiler
1439+
// actually comes from in-tree sources, and we're cross-compiling, so the stage0 for the
1440+
// given `target` is not available.
14381441
if compiler.stage == 0 {
14391442
if target != compiler.host {
1440-
panic!(
1441-
r"It is not possible to build the standard library for `{target}` using the stage0 compiler.
1443+
if self.local_rebuild {
1444+
self.ensure(Std::new(compiler, target))
1445+
} else {
1446+
panic!(
1447+
r"It is not possible to build the standard library for `{target}` using the stage0 compiler.
14421448
You have to build a stage1 compiler for `{}` first, and then use it to build a standard library for `{target}`.
1449+
Alternatively, you can set `build.local-rebuild=true` and use a stage0 compiler built from in-tree sources.
14431450
",
1444-
compiler.host
1445-
)
1451+
compiler.host
1452+
)
1453+
}
1454+
} else {
1455+
// We still need to link the prebuilt standard library into the ephemeral stage0 sysroot
1456+
self.ensure(StdLink::from_std(Std::new(compiler, target), compiler));
1457+
None
14461458
}
1447-
1448-
// We still need to link the prebuilt standard library into the ephemeral stage0 sysroot
1449-
self.ensure(StdLink::from_std(Std::new(compiler, target), compiler));
1450-
None
14511459
} else {
14521460
// This step both compiles the std and links it into the compiler's sysroot.
14531461
// Yes, it's quite magical and side-effecty.. would be nice to refactor later.

src/bootstrap/src/core/builder/tests.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,18 @@ mod snapshot {
853853
ctx.config("build").path("library").stage(0).run();
854854
}
855855

856+
#[test]
857+
fn build_library_stage_0_local_rebuild() {
858+
let ctx = TestCtx::new();
859+
insta::assert_snapshot!(
860+
ctx.config("build")
861+
.path("library")
862+
.stage(0)
863+
.targets(&[TEST_TRIPLE_1])
864+
.args(&["--set", "build.local-rebuild=true"])
865+
.render_steps(), @"[build] rustc 0 <host> -> std 0 <target1>");
866+
}
867+
856868
#[test]
857869
fn build_library_stage_1() {
858870
let ctx = TestCtx::new();
@@ -1640,6 +1652,22 @@ mod snapshot {
16401652
");
16411653
}
16421654

1655+
#[test]
1656+
fn dist_library_stage_0_local_rebuild() {
1657+
let ctx = TestCtx::new();
1658+
insta::assert_snapshot!(
1659+
ctx.config("dist")
1660+
.path("rust-std")
1661+
.stage(0)
1662+
.targets(&[TEST_TRIPLE_1])
1663+
.args(&["--set", "build.local-rebuild=true"])
1664+
.render_steps(), @r"
1665+
[build] rustc 0 <host> -> std 0 <target1>
1666+
[build] rustc 0 <host> -> RustInstaller 1 <host>
1667+
[dist] rustc 0 <host> -> std 0 <target1>
1668+
");
1669+
}
1670+
16431671
#[test]
16441672
fn check_compiler_no_explicit_stage() {
16451673
let ctx = TestCtx::new();

src/bootstrap/src/core/config/config.rs

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -969,31 +969,38 @@ impl Config {
969969
| Subcommand::Vendor { .. } => flags_stage.unwrap_or(0),
970970
};
971971

972-
// Now check that the selected stage makes sense, and if not, print a warning and end
972+
let local_rebuild = build_local_rebuild.unwrap_or(false);
973+
974+
let check_stage0 = |kind: &str| {
975+
if local_rebuild {
976+
eprintln!("WARNING: running {kind} in stage 0. This might not work as expected.");
977+
} else {
978+
eprintln!(
979+
"ERROR: cannot {kind} anything on stage 0. Use at least stage 1 or set build.local-rebuild=true and use a stage0 compiler built from in-tree sources."
980+
);
981+
exit!(1);
982+
}
983+
};
984+
985+
// Now check that the selected stage makes sense, and if not, print an error and end
973986
match (stage, &flags_cmd) {
974987
(0, Subcommand::Build { .. }) => {
975-
eprintln!("ERROR: cannot build anything on stage 0. Use at least stage 1.");
976-
exit!(1);
988+
check_stage0("build");
977989
}
978990
(0, Subcommand::Check { .. }) => {
979-
eprintln!("ERROR: cannot check anything on stage 0. Use at least stage 1.");
980-
exit!(1);
991+
check_stage0("check");
981992
}
982993
(0, Subcommand::Doc { .. }) => {
983-
eprintln!("ERROR: cannot document anything on stage 0. Use at least stage 1.");
984-
exit!(1);
994+
check_stage0("doc");
985995
}
986996
(0, Subcommand::Clippy { .. }) => {
987-
eprintln!("ERROR: cannot run clippy on stage 0. Use at least stage 1.");
988-
exit!(1);
997+
check_stage0("clippy");
989998
}
990999
(0, Subcommand::Dist) => {
991-
eprintln!("ERROR: cannot dist anything on stage 0. Use at least stage 1.");
992-
exit!(1);
1000+
check_stage0("dist");
9931001
}
9941002
(0, Subcommand::Install) => {
995-
eprintln!("ERROR: cannot install anything on stage 0. Use at least stage 1.");
996-
exit!(1);
1003+
check_stage0("install");
9971004
}
9981005
_ => {}
9991006
}
@@ -1234,7 +1241,7 @@ impl Config {
12341241
llvm_use_libcxx: llvm_use_libcxx.unwrap_or(false),
12351242
llvm_use_linker,
12361243
llvm_version_suffix,
1237-
local_rebuild: build_local_rebuild.unwrap_or(false),
1244+
local_rebuild,
12381245
locked_deps: build_locked_deps.unwrap_or(false),
12391246
low_priority: build_low_priority.unwrap_or(false),
12401247
mandir: install_mandir.map(PathBuf::from),

src/bootstrap/src/utils/change_tracker.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,4 +526,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
526526
severity: ChangeSeverity::Info,
527527
summary: "The `optimized-compiler-builtins` option now accepts a path to an existing compiler-rt builtins library.",
528528
},
529+
ChangeInfo {
530+
change_id: 145876,
531+
severity: ChangeSeverity::Info,
532+
summary: "It is now possible to `check/build/dist` the standard stage 0 library if you use a stage0 rustc built from in-tree sources. This is useful for quickly cross-compiling the standard library. You have to enable build.local-rebuild for this to work.",
533+
},
529534
];

0 commit comments

Comments
 (0)