Skip to content

Commit 2fbc642

Browse files
committed
Add Mode::ToolTarget
1 parent 86c6197 commit 2fbc642

File tree

6 files changed

+104
-39
lines changed

6 files changed

+104
-39
lines changed

src/bootstrap/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ build/
105105
debuginfo/
106106
...
107107

108-
# Bootstrap host tools (which are always compiled with the stage0 compiler)
108+
# Host tools (which are always compiled with the stage0 compiler)
109109
# are stored here.
110110
bootstrap-tools/
111111

src/bootstrap/src/core/build_steps/check.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ use crate::core::build_steps::compile::{
44
add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, std_crates_for_run_make,
55
};
66
use crate::core::build_steps::tool;
7-
use crate::core::build_steps::tool::{COMPILETEST_ALLOW_FEATURES, SourceType, prepare_tool_cargo};
7+
use crate::core::build_steps::tool::{
8+
COMPILETEST_ALLOW_FEATURES, SourceType, get_tool_target_compiler, prepare_tool_cargo,
9+
};
810
use crate::core::builder::{
911
self, Alias, Builder, Kind, RunConfig, ShouldRun, Step, StepMetadata, crate_description,
1012
};
@@ -247,8 +249,10 @@ fn prepare_compiler_for_check(
247249
mode: Mode,
248250
) -> Compiler {
249251
let host = builder.host_target;
252+
250253
match mode {
251254
Mode::ToolBootstrap => builder.compiler(0, host),
255+
Mode::ToolTarget => get_tool_target_compiler(builder, target),
252256
Mode::ToolStd => {
253257
// These tools require the local standard library to be checked
254258
let build_compiler = builder.compiler(builder.top_stage, host);

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,17 @@ pub(crate) fn get_tool_rustc_compiler(
365365
builder.compiler(target_compiler.stage.saturating_sub(1), builder.config.host_target)
366366
}
367367

368+
/// Returns a compiler that is able to compile a `ToolTarget` tool for the given `target`.
369+
pub(crate) fn get_tool_target_compiler(builder: &Builder<'_>, target: TargetSelection) -> Compiler {
370+
todo!("FIX");
371+
if builder.host_target == target {
372+
builder.compiler(0, builder.host_target)
373+
} else {
374+
// FIXME: should this be builder.top_stage to avoid rebuilds?
375+
builder.compiler(1, target)
376+
}
377+
}
378+
368379
/// Links a built tool binary with the given `name` from the build directory to the
369380
/// tools directory.
370381
fn copy_link_tool_bin(

src/bootstrap/src/core/builder/cargo.rs

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -537,23 +537,25 @@ impl Builder<'_> {
537537
}
538538
}
539539

540-
let stage = if compiler.stage == 0 && self.local_rebuild {
540+
let build_compiler_stage = if compiler.stage == 0 && self.local_rebuild {
541541
// Assume the local-rebuild rustc already has stage1 features.
542542
1
543543
} else {
544544
compiler.stage
545545
};
546546

547547
// We synthetically interpret a stage0 compiler used to build tools as a
548-
// "raw" compiler in that it's the exact snapshot we download. Normally
549-
// the stage0 build means it uses libraries build by the stage0
550-
// compiler, but for tools we just use the precompiled libraries that
551-
// we've downloaded
552-
let use_snapshot = mode == Mode::ToolBootstrap;
553-
assert!(!use_snapshot || stage == 0 || self.local_rebuild);
554-
555-
let maybe_sysroot = self.sysroot(compiler);
556-
let sysroot = if use_snapshot { self.rustc_snapshot_sysroot() } else { &maybe_sysroot };
548+
// "raw" compiler in that it's the exact snapshot we download. For things like
549+
// ToolRustc, we would have to use the artificial stage0-sysroot compiler instead.
550+
let use_snapshot =
551+
mode == Mode::ToolBootstrap || (mode == Mode::ToolTarget && build_compiler_stage == 0);
552+
assert!(!use_snapshot || build_compiler_stage == 0 || self.local_rebuild);
553+
554+
let sysroot = if use_snapshot {
555+
self.rustc_snapshot_sysroot().to_path_buf()
556+
} else {
557+
self.sysroot(compiler)
558+
};
557559
let libdir = self.rustc_libdir(compiler);
558560

559561
let sysroot_str = sysroot.as_os_str().to_str().expect("sysroot should be UTF-8");
@@ -562,7 +564,7 @@ impl Builder<'_> {
562564
}
563565

564566
let mut rustflags = Rustflags::new(target);
565-
if stage != 0 {
567+
if build_compiler_stage != 0 {
566568
if let Ok(s) = env::var("CARGOFLAGS_NOT_BOOTSTRAP") {
567569
cargo.args(s.split_whitespace());
568570
}
@@ -604,7 +606,7 @@ impl Builder<'_> {
604606
// sysroot. Passing this cfg enables raw-dylib support instead, which makes the native
605607
// library unnecessary. This can be removed when windows-rs enables raw-dylib
606608
// unconditionally.
607-
if let Mode::Rustc | Mode::ToolRustc | Mode::ToolBootstrap = mode {
609+
if let Mode::Rustc | Mode::ToolRustc | Mode::ToolBootstrap | Mode::ToolTarget = mode {
608610
rustflags.arg("--cfg=windows_raw_dylib");
609611
}
610612

@@ -657,7 +659,7 @@ impl Builder<'_> {
657659
// FIXME(rust-lang/cargo#5754) we shouldn't be using special command arguments
658660
// to the host invocation here, but rather Cargo should know what flags to pass rustc
659661
// itself.
660-
if stage == 0 {
662+
if build_compiler_stage == 0 {
661663
hostflags.arg("--cfg=bootstrap");
662664
}
663665

@@ -666,7 +668,7 @@ impl Builder<'_> {
666668
// #71458.
667669
let mut rustdocflags = rustflags.clone();
668670
rustdocflags.propagate_cargo_env("RUSTDOCFLAGS");
669-
if stage == 0 {
671+
if build_compiler_stage == 0 {
670672
rustdocflags.env("RUSTDOCFLAGS_BOOTSTRAP");
671673
} else {
672674
rustdocflags.env("RUSTDOCFLAGS_NOT_BOOTSTRAP");
@@ -677,7 +679,7 @@ impl Builder<'_> {
677679
}
678680

679681
match mode {
680-
Mode::Std | Mode::ToolBootstrap | Mode::ToolStd => {}
682+
Mode::Std | Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolTarget => {}
681683
Mode::Rustc | Mode::Codegen | Mode::ToolRustc => {
682684
// Build proc macros both for the host and the target unless proc-macros are not
683685
// supported by the target.
@@ -719,7 +721,7 @@ impl Builder<'_> {
719721
// feature on the rustc side.
720722
cargo.arg("-Zbinary-dep-depinfo");
721723
let allow_features = match mode {
722-
Mode::ToolBootstrap | Mode::ToolStd => {
724+
Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolTarget => {
723725
// Restrict the allowed features so we don't depend on nightly
724726
// accidentally.
725727
//
@@ -827,7 +829,7 @@ impl Builder<'_> {
827829
cargo
828830
.env("RUSTBUILD_NATIVE_DIR", self.native_dir(target))
829831
.env("RUSTC_REAL", self.rustc(compiler))
830-
.env("RUSTC_STAGE", stage.to_string())
832+
.env("RUSTC_STAGE", build_compiler_stage.to_string())
831833
.env("RUSTC_SYSROOT", sysroot)
832834
.env("RUSTC_LIBDIR", libdir)
833835
.env("RUSTDOC", self.bootstrap_out.join("rustdoc"))
@@ -872,7 +874,7 @@ impl Builder<'_> {
872874
let debuginfo_level = match mode {
873875
Mode::Rustc | Mode::Codegen => self.config.rust_debuginfo_level_rustc,
874876
Mode::Std => self.config.rust_debuginfo_level_std,
875-
Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolRustc => {
877+
Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolRustc | Mode::ToolTarget => {
876878
self.config.rust_debuginfo_level_tools
877879
}
878880
};
@@ -884,11 +886,10 @@ impl Builder<'_> {
884886
profile_var("DEBUG_ASSERTIONS"),
885887
match mode {
886888
Mode::Std => self.config.std_debug_assertions,
887-
Mode::Rustc => self.config.rustc_debug_assertions,
888-
Mode::Codegen => self.config.rustc_debug_assertions,
889-
Mode::ToolBootstrap => self.config.tools_debug_assertions,
890-
Mode::ToolStd => self.config.tools_debug_assertions,
891-
Mode::ToolRustc => self.config.tools_debug_assertions,
889+
Mode::Rustc | Mode::Codegen => self.config.rustc_debug_assertions,
890+
Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolRustc | Mode::ToolTarget => {
891+
self.config.tools_debug_assertions
892+
}
892893
}
893894
.to_string(),
894895
);
@@ -959,7 +960,11 @@ impl Builder<'_> {
959960
cargo.env("CFG_VIRTUAL_RUSTC_DEV_SOURCE_BASE_DIR", map_to);
960961
}
961962
}
962-
Mode::Std | Mode::ToolBootstrap | Mode::ToolRustc | Mode::ToolStd => {
963+
Mode::Std
964+
| Mode::ToolBootstrap
965+
| Mode::ToolRustc
966+
| Mode::ToolStd
967+
| Mode::ToolTarget => {
963968
if let Some(ref map_to) =
964969
self.build.debuginfo_map_to(GitRepo::Rustc, RemapScheme::NonCompiler)
965970
{
@@ -1274,7 +1279,7 @@ impl Builder<'_> {
12741279
};
12751280

12761281
if let Some(limit) = limit
1277-
&& (stage == 0
1282+
&& (build_compiler_stage == 0
12781283
|| self.config.default_codegen_backend(target).unwrap_or_default() == "llvm")
12791284
{
12801285
rustflags.arg(&format!("-Cllvm-args=-import-instr-limit={limit}"));

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -959,6 +959,7 @@ impl<'a> Builder<'a> {
959959
tool::RemoteTestServer,
960960
tool::RemoteTestClient,
961961
tool::RustInstaller,
962+
tool::FeaturesStatusDump,
962963
tool::Cargo,
963964
tool::RustAnalyzer,
964965
tool::RustAnalyzerProcMacroSrv,

src/bootstrap/src/lib.rs

Lines changed: 56 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -253,12 +253,24 @@ pub enum Mode {
253253
/// These tools are intended to be only executed on the host system that
254254
/// invokes bootstrap, and they thus cannot be cross-compiled.
255255
///
256-
/// They are always built using the stage0 compiler, and typically they
256+
/// They are always built using the stage0 compiler, and they
257257
/// can be compiled with stable Rust.
258258
///
259259
/// These tools also essentially do not participate in staging.
260260
ToolBootstrap,
261261

262+
/// Build a cross-compilable helper tool. These tools do not depend on unstable features or
263+
/// compiler internals, but they might be cross-compilable (so we cannot build them using the
264+
/// stage0 compiler, unlike `ToolBootstrap`).
265+
///
266+
/// Some of these tools are also shipped in our `dist` archives.
267+
/// While we could compile them using the stage0 compiler when not cross-compiling, we instead
268+
/// use the in-tree compiler (and std) to build them, so that we can ship e.g. std security
269+
/// fixes and avoid depending fully on stage0 for the artifacts that we ship.
270+
///
271+
/// This mode is used e.g. for linkers and linker tools invoked by rustc on its host target.
272+
ToolTarget,
273+
262274
/// Build a tool which uses the locally built std, placing output in the
263275
/// "stageN-tools" directory. Its usage is quite rare, mainly used by
264276
/// compiletest which needs libtest.
@@ -273,11 +285,21 @@ pub enum Mode {
273285

274286
impl Mode {
275287
pub fn is_tool(&self) -> bool {
276-
matches!(self, Mode::ToolBootstrap | Mode::ToolRustc | Mode::ToolStd)
288+
match self {
289+
Mode::ToolBootstrap | Mode::ToolRustc | Mode::ToolStd | Mode::ToolTarget => true,
290+
Mode::Std | Mode::Codegen | Mode::Rustc => false,
291+
}
277292
}
278293

279294
pub fn must_support_dlopen(&self) -> bool {
280-
matches!(self, Mode::Std | Mode::Codegen)
295+
match self {
296+
Mode::Std | Mode::Codegen => true,
297+
Mode::ToolBootstrap
298+
| Mode::ToolRustc
299+
| Mode::ToolStd
300+
| Mode::ToolTarget
301+
| Mode::Rustc => false,
302+
}
281303
}
282304
}
283305

@@ -804,17 +826,39 @@ impl Build {
804826
/// stage when running with a particular host compiler.
805827
///
806828
/// The mode indicates what the root directory is for.
807-
fn stage_out(&self, compiler: Compiler, mode: Mode) -> PathBuf {
808-
let suffix = match mode {
809-
Mode::Std => "-std",
810-
Mode::Rustc => "-rustc",
811-
Mode::Codegen => "-codegen",
812-
Mode::ToolBootstrap => {
813-
return self.out.join(compiler.host).join("bootstrap-tools");
829+
fn stage_out(&self, build_compiler: Compiler, mode: Mode) -> PathBuf {
830+
use std::fmt::Write;
831+
832+
fn bootstrap_tool() -> (Option<u32>, &'static str) {
833+
(None, "bootstrap-tools")
834+
}
835+
fn staged_tool(build_compiler: Compiler) -> (Option<u32>, &'static str) {
836+
(Some(build_compiler.stage), "tools")
837+
}
838+
839+
let (stage, suffix) = match mode {
840+
Mode::Std => (Some(build_compiler.stage), "std"),
841+
Mode::Rustc => (Some(build_compiler.stage), "rustc"),
842+
Mode::Codegen => (Some(build_compiler.stage), "codegen"),
843+
Mode::ToolBootstrap => bootstrap_tool(),
844+
Mode::ToolStd | Mode::ToolRustc => (Some(build_compiler.stage), "tools"),
845+
Mode::ToolTarget => {
846+
// If we're not cross-compiling (the common case), share the target directory with
847+
// bootstrap tools to reuse the build cache.
848+
if build_compiler.stage == 0 {
849+
bootstrap_tool()
850+
} else {
851+
staged_tool(build_compiler)
852+
}
814853
}
815-
Mode::ToolStd | Mode::ToolRustc => "-tools",
816854
};
817-
self.out.join(compiler.host).join(format!("stage{}{}", compiler.stage, suffix))
855+
let path = self.out.join(build_compiler.host);
856+
let mut dir_name = String::new();
857+
if let Some(stage) = stage {
858+
write!(dir_name, "stage{stage}-").unwrap();
859+
}
860+
dir_name.push_str(suffix);
861+
path.join(dir_name)
818862
}
819863

820864
/// Returns the root output directory for all Cargo output in a given stage,

0 commit comments

Comments
 (0)