Skip to content

Commit bb2cc59

Browse files
committed
Auto merge of #137215 - onur-ozkan:rustc-tool-build-stages, r=jieyouxu,Kobzol
stabilize stage management for rustc tools #135990 got out of control due to excessive complexity. This PR aims to achieve the same goal with a simpler approach, likely through multiple smaller PRs. I will keep the other one read-only and open as a reference for future work. This work stabilizes the staging logic for `ToolRustc` programs, so you no longer need to handle build and target compilers separately in steps. Previously, most tools didn't do this correctly, which was causing the compiler to be built twice (e.g., `x test cargo --stage 1` would compile the stage 2 compiler before, but now it only compiles the stage 1 compiler). I also tried to document how we should write `ToolRustc` steps as they are quite different and require more attention than other tools. Next goal is to stabilize how stages are handled for the rustc itself. Currently, `x build --stage 1` builds the stage 1 compiler which is fine, but `x build compiler --stage 1` builds stage 2 compiler. ~~for now, r? ghost~~
2 parents bca5f37 + 76063a6 commit bb2cc59

File tree

12 files changed

+340
-263
lines changed

12 files changed

+340
-263
lines changed

src/bootstrap/defaults/config.tools.toml

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ incremental = true
88
download-rustc = "if-unchanged"
99

1010
[build]
11+
# cargo and clippy tests don't pass on stage 1
12+
test-stage = 2
1113
# Document with the in-tree rustdoc by default, since `download-rustc` makes it quick to compile.
1214
doc-stage = 2
1315
# Contributors working on tools will probably expect compiler docs to be generated, so they can figure out how to use the API.

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

+13-13
Original file line numberDiff line numberDiff line change
@@ -1983,13 +1983,14 @@ impl Step for Assemble {
19831983
let maybe_install_llvm_bitcode_linker = |compiler| {
19841984
if builder.config.llvm_bitcode_linker_enabled {
19851985
trace!("llvm-bitcode-linker enabled, installing");
1986-
let src_path = builder.ensure(crate::core::build_steps::tool::LlvmBitcodeLinker {
1987-
compiler,
1988-
target: target_compiler.host,
1989-
extra_features: vec![],
1990-
});
1986+
let llvm_bitcode_linker =
1987+
builder.ensure(crate::core::build_steps::tool::LlvmBitcodeLinker {
1988+
compiler,
1989+
target: target_compiler.host,
1990+
extra_features: vec![],
1991+
});
19911992
let tool_exe = exe("llvm-bitcode-linker", target_compiler.host);
1992-
builder.copy_link(&src_path, &libdir_bin.join(tool_exe));
1993+
builder.copy_link(&llvm_bitcode_linker.tool_path, &libdir_bin.join(tool_exe));
19931994
}
19941995
};
19951996

@@ -2181,14 +2182,13 @@ impl Step for Assemble {
21812182
// logic to create the final binary. This is used by the
21822183
// `wasm32-wasip2` target of Rust.
21832184
if builder.tool_enabled("wasm-component-ld") {
2184-
let wasm_component_ld_exe =
2185-
builder.ensure(crate::core::build_steps::tool::WasmComponentLd {
2186-
compiler: build_compiler,
2187-
target: target_compiler.host,
2188-
});
2185+
let wasm_component = builder.ensure(crate::core::build_steps::tool::WasmComponentLd {
2186+
compiler: build_compiler,
2187+
target: target_compiler.host,
2188+
});
21892189
builder.copy_link(
2190-
&wasm_component_ld_exe,
2191-
&libdir_bin.join(wasm_component_ld_exe.file_name().unwrap()),
2190+
&wasm_component.tool_path,
2191+
&libdir_bin.join(wasm_component.tool_path.file_name().unwrap()),
21922192
);
21932193
}
21942194

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

+11-11
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ impl Step for Rustc {
430430
},
431431
builder.kind,
432432
) {
433-
builder.install(&ra_proc_macro_srv, &image.join("libexec"), 0o755);
433+
builder.install(&ra_proc_macro_srv.tool_path, &image.join("libexec"), 0o755);
434434
}
435435

436436
let libdir_relative = builder.libdir_relative(compiler);
@@ -1145,7 +1145,7 @@ impl Step for Cargo {
11451145
let mut tarball = Tarball::new(builder, "cargo", &target.triple);
11461146
tarball.set_overlay(OverlayKind::Cargo);
11471147

1148-
tarball.add_file(cargo, "bin", 0o755);
1148+
tarball.add_file(cargo.tool_path, "bin", 0o755);
11491149
tarball.add_file(etc.join("_cargo"), "share/zsh/site-functions", 0o644);
11501150
tarball.add_renamed_file(etc.join("cargo.bashcomp.sh"), "etc/bash_completion.d", "cargo");
11511151
tarball.add_dir(etc.join("man"), "share/man/man1");
@@ -1191,7 +1191,7 @@ impl Step for Rls {
11911191
let mut tarball = Tarball::new(builder, "rls", &target.triple);
11921192
tarball.set_overlay(OverlayKind::Rls);
11931193
tarball.is_preview(true);
1194-
tarball.add_file(rls, "bin", 0o755);
1194+
tarball.add_file(rls.tool_path, "bin", 0o755);
11951195
tarball.add_legal_and_readme_to("share/doc/rls");
11961196
Some(tarball.generate())
11971197
}
@@ -1233,7 +1233,7 @@ impl Step for RustAnalyzer {
12331233
let mut tarball = Tarball::new(builder, "rust-analyzer", &target.triple);
12341234
tarball.set_overlay(OverlayKind::RustAnalyzer);
12351235
tarball.is_preview(true);
1236-
tarball.add_file(rust_analyzer, "bin", 0o755);
1236+
tarball.add_file(rust_analyzer.tool_path, "bin", 0o755);
12371237
tarball.add_legal_and_readme_to("share/doc/rust-analyzer");
12381238
Some(tarball.generate())
12391239
}
@@ -1279,8 +1279,8 @@ impl Step for Clippy {
12791279
let mut tarball = Tarball::new(builder, "clippy", &target.triple);
12801280
tarball.set_overlay(OverlayKind::Clippy);
12811281
tarball.is_preview(true);
1282-
tarball.add_file(clippy, "bin", 0o755);
1283-
tarball.add_file(cargoclippy, "bin", 0o755);
1282+
tarball.add_file(clippy.tool_path, "bin", 0o755);
1283+
tarball.add_file(cargoclippy.tool_path, "bin", 0o755);
12841284
tarball.add_legal_and_readme_to("share/doc/clippy");
12851285
Some(tarball.generate())
12861286
}
@@ -1329,8 +1329,8 @@ impl Step for Miri {
13291329
let mut tarball = Tarball::new(builder, "miri", &target.triple);
13301330
tarball.set_overlay(OverlayKind::Miri);
13311331
tarball.is_preview(true);
1332-
tarball.add_file(miri, "bin", 0o755);
1333-
tarball.add_file(cargomiri, "bin", 0o755);
1332+
tarball.add_file(miri.tool_path, "bin", 0o755);
1333+
tarball.add_file(cargomiri.tool_path, "bin", 0o755);
13341334
tarball.add_legal_and_readme_to("share/doc/miri");
13351335
Some(tarball.generate())
13361336
}
@@ -1460,8 +1460,8 @@ impl Step for Rustfmt {
14601460
let mut tarball = Tarball::new(builder, "rustfmt", &target.triple);
14611461
tarball.set_overlay(OverlayKind::Rustfmt);
14621462
tarball.is_preview(true);
1463-
tarball.add_file(rustfmt, "bin", 0o755);
1464-
tarball.add_file(cargofmt, "bin", 0o755);
1463+
tarball.add_file(rustfmt.tool_path, "bin", 0o755);
1464+
tarball.add_file(cargofmt.tool_path, "bin", 0o755);
14651465
tarball.add_legal_and_readme_to("share/doc/rustfmt");
14661466
Some(tarball.generate())
14671467
}
@@ -2283,7 +2283,7 @@ impl Step for LlvmBitcodeLinker {
22832283
tarball.set_overlay(OverlayKind::LlvmBitcodeLinker);
22842284
tarball.is_preview(true);
22852285

2286-
tarball.add_file(llbc_linker, self_contained_bin_dir, 0o755);
2286+
tarball.add_file(llbc_linker.tool_path, self_contained_bin_dir, 0o755);
22872287

22882288
Some(tarball.generate())
22892289
}

src/bootstrap/src/core/build_steps/perf.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ Consider setting `rust.debuginfo-level = 1` in `config.toml`."#);
166166
let results_dir = rustc_perf_dir.join("results");
167167
builder.create_dir(&results_dir);
168168

169-
let mut cmd = command(collector);
169+
let mut cmd = command(collector.tool_path);
170170

171171
// We need to set the working directory to `src/tools/rustc-perf`, so that it can find the directory
172172
// with compile-time benchmarks.

src/bootstrap/src/core/build_steps/run.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -126,11 +126,7 @@ impl Step for Miri {
126126

127127
// This compiler runs on the host, we'll just use it for the target.
128128
let target_compiler = builder.compiler(stage, host);
129-
// Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise
130-
// we'd have stageN/bin/rustc and stageN/bin/rustdoc be effectively different stage
131-
// compilers, which isn't what we want. Rustdoc should be linked in the same way as the
132-
// rustc compiler it's paired with, so it must be built with the previous stage compiler.
133-
let host_compiler = builder.compiler(stage - 1, host);
129+
let host_compiler = tool::get_tool_rustc_compiler(builder, target_compiler);
134130

135131
// Get a target sysroot for Miri.
136132
let miri_sysroot = test::Miri::build_miri_sysroot(builder, target_compiler, target);

src/bootstrap/src/core/build_steps/test.rs

+35-31
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ impl Step for Cargotest {
263263

264264
let _time = helpers::timeit(builder);
265265
let mut cmd = builder.tool_cmd(Tool::CargoTest);
266-
cmd.arg(&cargo)
266+
cmd.arg(&cargo.tool_path)
267267
.arg(&out_dir)
268268
.args(builder.config.test_args())
269269
.env("RUSTC", builder.rustc(compiler))
@@ -298,9 +298,16 @@ impl Step for Cargo {
298298

299299
/// Runs `cargo test` for `cargo` packaged with Rust.
300300
fn run(self, builder: &Builder<'_>) {
301+
if self.stage < 2 {
302+
eprintln!("WARNING: cargo tests on stage {} may not behave well.", self.stage);
303+
eprintln!("HELP: consider using stage 2");
304+
}
305+
301306
let compiler = builder.compiler(self.stage, self.host);
302307

303-
builder.ensure(tool::Cargo { compiler, target: self.host });
308+
let cargo = builder.ensure(tool::Cargo { compiler, target: self.host });
309+
let compiler = cargo.build_compiler;
310+
304311
let cargo = tool::prepare_tool_cargo(
305312
builder,
306313
compiler,
@@ -367,6 +374,7 @@ impl Step for RustAnalyzer {
367374
let stage = self.stage;
368375
let host = self.host;
369376
let compiler = builder.compiler(stage, host);
377+
let compiler = tool::get_tool_rustc_compiler(builder, compiler);
370378

371379
// We don't need to build the whole Rust Analyzer for the proc-macro-srv test suite,
372380
// but we do need the standard library to be present.
@@ -427,7 +435,8 @@ impl Step for Rustfmt {
427435
let host = self.host;
428436
let compiler = builder.compiler(stage, host);
429437

430-
builder.ensure(tool::Rustfmt { compiler, target: self.host });
438+
let tool_result = builder.ensure(tool::Rustfmt { compiler, target: self.host });
439+
let compiler = tool_result.build_compiler;
431440

432441
let mut cargo = tool::prepare_tool_cargo(
433442
builder,
@@ -522,16 +531,11 @@ impl Step for Miri {
522531

523532
// This compiler runs on the host, we'll just use it for the target.
524533
let target_compiler = builder.compiler(stage, host);
525-
// Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise
526-
// we'd have stageN/bin/rustc and stageN/bin/rustdoc be effectively different stage
527-
// compilers, which isn't what we want. Rustdoc should be linked in the same way as the
528-
// rustc compiler it's paired with, so it must be built with the previous stage compiler.
529-
let host_compiler = builder.compiler(stage - 1, host);
530534

531535
// Build our tools.
532-
let miri = builder.ensure(tool::Miri { compiler: host_compiler, target: host });
536+
let miri = builder.ensure(tool::Miri { compiler: target_compiler, target: host });
533537
// the ui tests also assume cargo-miri has been built
534-
builder.ensure(tool::CargoMiri { compiler: host_compiler, target: host });
538+
builder.ensure(tool::CargoMiri { compiler: target_compiler, target: host });
535539

536540
// We also need sysroots, for Miri and for the host (the latter for build scripts).
537541
// This is for the tests so everything is done with the target compiler.
@@ -542,7 +546,8 @@ impl Step for Miri {
542546
// Miri has its own "target dir" for ui test dependencies. Make sure it gets cleared when
543547
// the sysroot gets rebuilt, to avoid "found possibly newer version of crate `std`" errors.
544548
if !builder.config.dry_run() {
545-
let ui_test_dep_dir = builder.stage_out(host_compiler, Mode::ToolStd).join("miri_ui");
549+
let ui_test_dep_dir =
550+
builder.stage_out(miri.build_compiler, Mode::ToolStd).join("miri_ui");
546551
// The mtime of `miri_sysroot` changes when the sysroot gets rebuilt (also see
547552
// <https://github.com/RalfJung/rustc-build-sysroot/commit/10ebcf60b80fe2c3dc765af0ff19fdc0da4b7466>).
548553
// We can hence use that directly as a signal to clear the ui test dir.
@@ -553,7 +558,7 @@ impl Step for Miri {
553558
// This is with the Miri crate, so it uses the host compiler.
554559
let mut cargo = tool::prepare_tool_cargo(
555560
builder,
556-
host_compiler,
561+
miri.build_compiler,
557562
Mode::ToolRustc,
558563
host,
559564
Kind::Test,
@@ -571,7 +576,7 @@ impl Step for Miri {
571576
// miri tests need to know about the stage sysroot
572577
cargo.env("MIRI_SYSROOT", &miri_sysroot);
573578
cargo.env("MIRI_HOST_SYSROOT", &host_sysroot);
574-
cargo.env("MIRI", &miri);
579+
cargo.env("MIRI", &miri.tool_path);
575580

576581
// Set the target.
577582
cargo.env("MIRI_TEST_TARGET", target.rustc_target_arg());
@@ -743,7 +748,13 @@ impl Step for Clippy {
743748
let host = self.host;
744749
let compiler = builder.compiler(stage, host);
745750

746-
builder.ensure(tool::Clippy { compiler, target: self.host });
751+
if stage < 2 {
752+
eprintln!("WARNING: clippy tests on stage {stage} may not behave well.");
753+
eprintln!("HELP: consider using stage 2");
754+
}
755+
756+
let tool_result = builder.ensure(tool::Clippy { compiler, target: self.host });
757+
let compiler = tool_result.build_compiler;
747758
let mut cargo = tool::prepare_tool_cargo(
748759
builder,
749760
compiler,
@@ -1728,18 +1739,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
17281739
// If we're using `--stage 0`, we should provide the bootstrap cargo.
17291740
builder.initial_cargo.clone()
17301741
} else {
1731-
// We need to properly build cargo using the suitable stage compiler.
1732-
1733-
let compiler = builder.download_rustc().then_some(compiler).unwrap_or_else(||
1734-
// HACK: currently tool stages are off-by-one compared to compiler stages, i.e. if
1735-
// you give `tool::Cargo` a stage 1 rustc, it will cause stage 2 rustc to be built
1736-
// and produce a cargo built with stage 2 rustc. To fix this, we need to chop off
1737-
// the compiler stage by 1 to align with expected `./x test run-make --stage N`
1738-
// behavior, i.e. we need to pass `N - 1` compiler stage to cargo. See also Miri
1739-
// which does a similar hack.
1740-
builder.compiler(builder.top_stage - 1, compiler.host));
1741-
1742-
builder.ensure(tool::Cargo { compiler, target: compiler.host })
1742+
builder.ensure(tool::Cargo { compiler, target: compiler.host }).tool_path
17431743
};
17441744

17451745
cmd.arg("--cargo-path").arg(cargo_path);
@@ -1760,9 +1760,10 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
17601760
// Use the beta compiler for jsondocck
17611761
let json_compiler = compiler.with_stage(0);
17621762
cmd.arg("--jsondocck-path")
1763-
.arg(builder.ensure(tool::JsonDocCk { compiler: json_compiler, target }));
1764-
cmd.arg("--jsondoclint-path")
1765-
.arg(builder.ensure(tool::JsonDocLint { compiler: json_compiler, target }));
1763+
.arg(builder.ensure(tool::JsonDocCk { compiler: json_compiler, target }).tool_path);
1764+
cmd.arg("--jsondoclint-path").arg(
1765+
builder.ensure(tool::JsonDocLint { compiler: json_compiler, target }).tool_path,
1766+
);
17661767
}
17671768

17681769
if matches!(mode, "coverage-map" | "coverage-run") {
@@ -2999,12 +3000,15 @@ impl Step for RemoteCopyLibs {
29993000

30003001
builder.info(&format!("REMOTE copy libs to emulator ({target})"));
30013002

3002-
let server = builder.ensure(tool::RemoteTestServer { compiler, target });
3003+
let remote_test_server = builder.ensure(tool::RemoteTestServer { compiler, target });
30033004

30043005
// Spawn the emulator and wait for it to come online
30053006
let tool = builder.tool_exe(Tool::RemoteTestClient);
30063007
let mut cmd = command(&tool);
3007-
cmd.arg("spawn-emulator").arg(target.triple).arg(&server).arg(builder.tempdir());
3008+
cmd.arg("spawn-emulator")
3009+
.arg(target.triple)
3010+
.arg(&remote_test_server.tool_path)
3011+
.arg(builder.tempdir());
30083012
if let Some(rootfs) = builder.qemu_rootfs(target) {
30093013
cmd.arg(rootfs);
30103014
}

0 commit comments

Comments
 (0)