Skip to content

Commit de05120

Browse files
committed
Add Mode::ToolTarget
1 parent c58c236 commit de05120

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
@@ -532,23 +532,25 @@ impl Builder<'_> {
532532
}
533533
}
534534

535-
let stage = if compiler.stage == 0 && self.local_rebuild {
535+
let build_compiler_stage = if compiler.stage == 0 && self.local_rebuild {
536536
// Assume the local-rebuild rustc already has stage1 features.
537537
1
538538
} else {
539539
compiler.stage
540540
};
541541

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

554556
let sysroot_str = sysroot.as_os_str().to_str().expect("sysroot should be UTF-8");
@@ -557,7 +559,7 @@ impl Builder<'_> {
557559
}
558560

559561
let mut rustflags = Rustflags::new(target);
560-
if stage != 0 {
562+
if build_compiler_stage != 0 {
561563
if let Ok(s) = env::var("CARGOFLAGS_NOT_BOOTSTRAP") {
562564
cargo.args(s.split_whitespace());
563565
}
@@ -599,7 +601,7 @@ impl Builder<'_> {
599601
// sysroot. Passing this cfg enables raw-dylib support instead, which makes the native
600602
// library unnecessary. This can be removed when windows-rs enables raw-dylib
601603
// unconditionally.
602-
if let Mode::Rustc | Mode::ToolRustc | Mode::ToolBootstrap = mode {
604+
if let Mode::Rustc | Mode::ToolRustc | Mode::ToolBootstrap | Mode::ToolTarget = mode {
603605
rustflags.arg("--cfg=windows_raw_dylib");
604606
}
605607

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

@@ -661,7 +663,7 @@ impl Builder<'_> {
661663
// #71458.
662664
let mut rustdocflags = rustflags.clone();
663665
rustdocflags.propagate_cargo_env("RUSTDOCFLAGS");
664-
if stage == 0 {
666+
if build_compiler_stage == 0 {
665667
rustdocflags.env("RUSTDOCFLAGS_BOOTSTRAP");
666668
} else {
667669
rustdocflags.env("RUSTDOCFLAGS_NOT_BOOTSTRAP");
@@ -672,7 +674,7 @@ impl Builder<'_> {
672674
}
673675

674676
match mode {
675-
Mode::Std | Mode::ToolBootstrap | Mode::ToolStd => {}
677+
Mode::Std | Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolTarget => {}
676678
Mode::Rustc | Mode::Codegen | Mode::ToolRustc => {
677679
// Build proc macros both for the host and the target unless proc-macros are not
678680
// supported by the target.
@@ -714,7 +716,7 @@ impl Builder<'_> {
714716
// feature on the rustc side.
715717
cargo.arg("-Zbinary-dep-depinfo");
716718
let allow_features = match mode {
717-
Mode::ToolBootstrap | Mode::ToolStd => {
719+
Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolTarget => {
718720
// Restrict the allowed features so we don't depend on nightly
719721
// accidentally.
720722
//
@@ -822,7 +824,7 @@ impl Builder<'_> {
822824
cargo
823825
.env("RUSTBUILD_NATIVE_DIR", self.native_dir(target))
824826
.env("RUSTC_REAL", self.rustc(compiler))
825-
.env("RUSTC_STAGE", stage.to_string())
827+
.env("RUSTC_STAGE", build_compiler_stage.to_string())
826828
.env("RUSTC_SYSROOT", sysroot)
827829
.env("RUSTC_LIBDIR", libdir)
828830
.env("RUSTDOC", self.bootstrap_out.join("rustdoc"))
@@ -867,7 +869,7 @@ impl Builder<'_> {
867869
let debuginfo_level = match mode {
868870
Mode::Rustc | Mode::Codegen => self.config.rust_debuginfo_level_rustc,
869871
Mode::Std => self.config.rust_debuginfo_level_std,
870-
Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolRustc => {
872+
Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolRustc | Mode::ToolTarget => {
871873
self.config.rust_debuginfo_level_tools
872874
}
873875
};
@@ -879,11 +881,10 @@ impl Builder<'_> {
879881
profile_var("DEBUG_ASSERTIONS"),
880882
match mode {
881883
Mode::Std => self.config.std_debug_assertions,
882-
Mode::Rustc => self.config.rustc_debug_assertions,
883-
Mode::Codegen => self.config.rustc_debug_assertions,
884-
Mode::ToolBootstrap => self.config.tools_debug_assertions,
885-
Mode::ToolStd => self.config.tools_debug_assertions,
886-
Mode::ToolRustc => self.config.tools_debug_assertions,
884+
Mode::Rustc | Mode::Codegen => self.config.rustc_debug_assertions,
885+
Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolRustc | Mode::ToolTarget => {
886+
self.config.tools_debug_assertions
887+
}
887888
}
888889
.to_string(),
889890
);
@@ -954,7 +955,11 @@ impl Builder<'_> {
954955
cargo.env("CFG_VIRTUAL_RUSTC_DEV_SOURCE_BASE_DIR", map_to);
955956
}
956957
}
957-
Mode::Std | Mode::ToolBootstrap | Mode::ToolRustc | Mode::ToolStd => {
958+
Mode::Std
959+
| Mode::ToolBootstrap
960+
| Mode::ToolRustc
961+
| Mode::ToolStd
962+
| Mode::ToolTarget => {
958963
if let Some(ref map_to) =
959964
self.build.debuginfo_map_to(GitRepo::Rustc, RemapScheme::NonCompiler)
960965
{
@@ -1269,7 +1274,7 @@ impl Builder<'_> {
12691274
};
12701275

12711276
if let Some(limit) = limit
1272-
&& (stage == 0
1277+
&& (build_compiler_stage == 0
12731278
|| self.config.default_codegen_backend(target).unwrap_or_default() == "llvm")
12741279
{
12751280
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)