Skip to content

Commit bb2cc59

Browse files
committedFeb 23, 2025
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
}

‎src/bootstrap/src/core/build_steps/tool.rs

+202-184
Large diffs are not rendered by default.

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

+15-18
Original file line numberDiff line numberDiff line change
@@ -1392,7 +1392,7 @@ impl<'a> Builder<'a> {
13921392
}
13931393

13941394
pub fn rustdoc(&self, compiler: Compiler) -> PathBuf {
1395-
self.ensure(tool::Rustdoc { compiler })
1395+
self.ensure(tool::Rustdoc { compiler }).tool_path
13961396
}
13971397

13981398
pub fn cargo_clippy_cmd(&self, run_compiler: Compiler) -> BootstrapCommand {
@@ -1408,38 +1408,35 @@ impl<'a> Builder<'a> {
14081408
return cmd;
14091409
}
14101410

1411-
let build_compiler = self.compiler(run_compiler.stage - 1, self.build.build);
1412-
self.ensure(tool::Clippy { compiler: build_compiler, target: self.build.build });
1411+
let _ = self.ensure(tool::Clippy { compiler: run_compiler, target: self.build.build });
14131412
let cargo_clippy =
1414-
self.ensure(tool::CargoClippy { compiler: build_compiler, target: self.build.build });
1413+
self.ensure(tool::CargoClippy { compiler: run_compiler, target: self.build.build });
14151414
let mut dylib_path = helpers::dylib_path();
14161415
dylib_path.insert(0, self.sysroot(run_compiler).join("lib"));
14171416

1418-
let mut cmd = command(cargo_clippy);
1417+
let mut cmd = command(cargo_clippy.tool_path);
14191418
cmd.env(helpers::dylib_path_var(), env::join_paths(&dylib_path).unwrap());
14201419
cmd.env("CARGO", &self.initial_cargo);
14211420
cmd
14221421
}
14231422

14241423
pub fn cargo_miri_cmd(&self, run_compiler: Compiler) -> BootstrapCommand {
14251424
assert!(run_compiler.stage > 0, "miri can not be invoked at stage 0");
1426-
let build_compiler = self.compiler(run_compiler.stage - 1, self.build.build);
1427-
14281425
// Prepare the tools
1429-
let miri = self.ensure(tool::Miri { compiler: build_compiler, target: self.build.build });
1426+
let miri = self.ensure(tool::Miri { compiler: run_compiler, target: self.build.build });
14301427
let cargo_miri =
1431-
self.ensure(tool::CargoMiri { compiler: build_compiler, target: self.build.build });
1428+
self.ensure(tool::CargoMiri { compiler: run_compiler, target: self.build.build });
14321429
// Invoke cargo-miri, make sure it can find miri and cargo.
1433-
let mut cmd = command(cargo_miri);
1434-
cmd.env("MIRI", &miri);
1430+
let mut cmd = command(cargo_miri.tool_path);
1431+
cmd.env("MIRI", &miri.tool_path);
14351432
cmd.env("CARGO", &self.initial_cargo);
1436-
// Need to add the `run_compiler` libs. Those are the libs produces *by* `build_compiler`,
1437-
// so they match the Miri we just built. However this means they are actually living one
1438-
// stage up, i.e. we are running `stage0-tools-bin/miri` with the libraries in `stage1/lib`.
1439-
// This is an unfortunate off-by-1 caused (possibly) by the fact that Miri doesn't have an
1440-
// "assemble" step like rustc does that would cross the stage boundary. We can't use
1441-
// `add_rustc_lib_path` as that's a NOP on Windows but we do need these libraries added to
1442-
// the PATH due to the stage mismatch.
1433+
// Need to add the `run_compiler` libs. Those are the libs produces *by* `build_compiler`
1434+
// in `tool::ToolBuild` step, so they match the Miri we just built. However this means they
1435+
// are actually living one stage up, i.e. we are running `stage0-tools-bin/miri` with the
1436+
// libraries in `stage1/lib`. This is an unfortunate off-by-1 caused (possibly) by the fact
1437+
// that Miri doesn't have an "assemble" step like rustc does that would cross the stage boundary.
1438+
// We can't use `add_rustc_lib_path` as that's a NOP on Windows but we do need these libraries
1439+
// added to the PATH due to the stage mismatch.
14431440
// Also see https://github.com/rust-lang/rust/pull/123192#issuecomment-2028901503.
14441441
add_dylib_path(self.rustc_lib_paths(run_compiler), &mut cmd);
14451442
cmd

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

+31
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,7 @@ mod dist {
525525
first(cache.all::<compile::Rustc>()),
526526
&[
527527
rustc!(TEST_TRIPLE_1 => TEST_TRIPLE_1, stage = 0),
528+
rustc!(TEST_TRIPLE_1 => TEST_TRIPLE_2, stage = 0),
528529
rustc!(TEST_TRIPLE_1 => TEST_TRIPLE_2, stage = 1),
529530
]
530531
);
@@ -1084,3 +1085,33 @@ fn test_is_builder_target() {
10841085
assert!(!builder.is_builder_target(target2));
10851086
}
10861087
}
1088+
1089+
#[test]
1090+
fn test_get_tool_rustc_compiler() {
1091+
let mut config = configure("build", &[], &[]);
1092+
config.download_rustc_commit = None;
1093+
let build = Build::new(config);
1094+
let builder = Builder::new(&build);
1095+
1096+
let target_triple_1 = TargetSelection::from_user(TEST_TRIPLE_1);
1097+
1098+
let compiler = Compiler { stage: 2, host: target_triple_1 };
1099+
let expected = Compiler { stage: 1, host: target_triple_1 };
1100+
let actual = tool::get_tool_rustc_compiler(&builder, compiler);
1101+
assert_eq!(expected, actual);
1102+
1103+
let compiler = Compiler { stage: 1, host: target_triple_1 };
1104+
let expected = Compiler { stage: 0, host: target_triple_1 };
1105+
let actual = tool::get_tool_rustc_compiler(&builder, compiler);
1106+
assert_eq!(expected, actual);
1107+
1108+
let mut config = configure("build", &[], &[]);
1109+
config.download_rustc_commit = Some("".to_owned());
1110+
let build = Build::new(config);
1111+
let builder = Builder::new(&build);
1112+
1113+
let compiler = Compiler { stage: 1, host: target_triple_1 };
1114+
let expected = Compiler { stage: 1, host: target_triple_1 };
1115+
let actual = tool::get_tool_rustc_compiler(&builder, compiler);
1116+
assert_eq!(expected, actual);
1117+
}

‎src/bootstrap/src/utils/change_tracker.rs

+5
Original file line numberDiff line numberDiff line change
@@ -355,4 +355,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
355355
severity: ChangeSeverity::Info,
356356
summary: "It is now possible to configure `jemalloc` for each target",
357357
},
358+
ChangeInfo {
359+
change_id: 137215,
360+
severity: ChangeSeverity::Info,
361+
summary: "Added `build.test-stage = 2` to 'tools' profile defaults",
362+
},
358363
];

‎src/doc/rustc-dev-guide/src/SUMMARY.md

+1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
- [Prologue](./building/bootstrapping/intro.md)
7676
- [What Bootstrapping does](./building/bootstrapping/what-bootstrapping-does.md)
7777
- [How Bootstrap does it](./building/bootstrapping/how-bootstrap-does-it.md)
78+
- [Writing tools in Bootstrap](./building/bootstrapping/writing-tools-in-bootstrap.md)
7879
- [Debugging bootstrap](./building/bootstrapping/debugging-bootstrap.md)
7980

8081
# High-level Compiler Architecture
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Writing tools in Bootstrap
2+
3+
There are three types of tools you can write in bootstrap:
4+
5+
- **`Mode::ToolBootstrap`**
6+
Use this for tools that don’t need anything from the in-tree compiler and can run with the stage0 `rustc`.
7+
The output is placed in the "stage0-bootstrap-tools" directory. This mode is for general-purpose tools built
8+
entirely with the stage0 compiler, including target libraries and only works for stage 0.
9+
10+
- **`Mode::ToolStd`**
11+
Use this for tools that rely on the locally built std. The output goes into the "stageN-tools" directory.
12+
This mode is rarely used, mainly for `compiletest` which requires `libtest`.
13+
14+
- **`Mode::ToolRustc`**
15+
Use this for tools that depend on both the locally built `rustc` and the target `std`. This is more complex than
16+
the other modes because the tool must be built with the same compiler used for `rustc` and placed in the "stageN-tools"
17+
directory. When you choose `Mode::ToolRustc`, `ToolBuild` implementation takes care of this automatically.
18+
If you need to use the builder’s compiler for something specific, you can get it from `ToolBuildResult`, which is
19+
returned by the tool's [`Step`].
20+
21+
Regardless of the tool type you must return `ToolBuildResult` from the tool’s [`Step`] implementation and use `ToolBuild` inside it.
22+
23+
[`Step`]: https://doc.rust-lang.org/nightly/nightly-rustc/bootstrap/core/builder/trait.Step.html

0 commit comments

Comments
 (0)
Please sign in to comment.