Skip to content

Commit 3ccf433

Browse files
Kobzolantoyo
authored andcommitted
Explicitly model GCC target pairs
1 parent 86ef07b commit 3ccf433

File tree

5 files changed

+176
-63
lines changed

5 files changed

+176
-63
lines changed

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

Lines changed: 86 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use serde_derive::Deserialize;
1919
#[cfg(feature = "tracing")]
2020
use tracing::span;
2121

22-
use crate::core::build_steps::gcc::{Gcc, GccOutput, add_cg_gcc_cargo_flags};
22+
use crate::core::build_steps::gcc::{Gcc, GccOutput, GccTargetPair, add_cg_gcc_cargo_flags};
2323
use crate::core::build_steps::tool::{RustcPrivateCompilers, SourceType, copy_lld_artifacts};
2424
use crate::core::build_steps::{dist, llvm};
2525
use crate::core::builder;
@@ -1579,16 +1579,16 @@ impl Step for RustcLink {
15791579
/// Set of `libgccjit` dylibs that can be used by `cg_gcc` to compile code for a set of targets.
15801580
#[derive(Clone)]
15811581
pub struct GccDylibSet {
1582-
dylibs: BTreeMap<TargetSelection, GccOutput>,
1583-
host_target: TargetSelection,
1582+
dylibs: BTreeMap<GccTargetPair, GccOutput>,
1583+
host_pair: GccTargetPair,
15841584
}
15851585

15861586
impl GccDylibSet {
15871587
/// Returns the libgccjit.so dylib that corresponds to a host target on which `cg_gcc` will be
15881588
/// executed.
15891589
fn host_dylib(&self) -> &GccOutput {
1590-
self.dylibs.get(&self.host_target).unwrap_or_else(|| {
1591-
panic!("libgccjit.so was not build for host target {}", self.host_target)
1590+
self.dylibs.get(&self.host_pair).unwrap_or_else(|| {
1591+
panic!("libgccjit.so was not build for host target {}", self.host_pair)
15921592
})
15931593
}
15941594

@@ -1601,7 +1601,13 @@ impl GccDylibSet {
16011601
// <rustc>/lib/<host-target>/codegen-backends
16021602
let cg_sysroot = builder.sysroot_codegen_backends(compiler);
16031603

1604-
for (target, libgccjit) in &self.dylibs {
1604+
for (target_pair, libgccjit) in &self.dylibs {
1605+
assert_eq!(
1606+
target_pair.host(),
1607+
compiler.host,
1608+
"Trying to install libgccjit ({target_pair}) to a compiler with a different host ({})",
1609+
compiler.host
1610+
);
16051611
let libgccjit = libgccjit.libgccjit();
16061612
let target_filename = libgccjit.file_name().unwrap().to_str().unwrap();
16071613

@@ -1614,7 +1620,7 @@ impl GccDylibSet {
16141620
);
16151621

16161622
// <cg-sysroot>/lib/<target>/libgccjit.so
1617-
let dest_dir = cg_sysroot.join("lib").join(target);
1623+
let dest_dir = cg_sysroot.join("lib").join(target_pair.target());
16181624
t!(fs::create_dir_all(&dest_dir));
16191625
let dst = dest_dir.join(target_filename);
16201626
builder.copy_link(&actual_libgccjit_path, &dst, FileType::NativeLibrary);
@@ -1648,15 +1654,12 @@ pub struct GccCodegenBackend {
16481654
}
16491655

16501656
impl GccCodegenBackend {
1651-
/// Create a cg_gcc backend that can compile code for all targets for which we build the
1652-
/// standard library, plus the host target on which `cg_gcc` will run, so that it can compile
1653-
/// host code (e.g. proc macros).
1654-
pub fn for_all_std_targets(builder: &Builder<'_>, compilers: RustcPrivateCompilers) -> Self {
1655-
// All std targets + the cg_gcc host target
1656-
let target_set: HashSet<TargetSelection> =
1657-
builder.targets.iter().copied().chain(std::iter::once(compilers.target())).collect();
1658-
1659-
let mut targets: Vec<TargetSelection> = target_set.into_iter().collect();
1657+
/// Build `cg_gcc` that will run on host `H` (`compilers.target_compiler.host`) and will be
1658+
/// able to produce code target pairs (`H`, `T`) for all `T` from `targets`.
1659+
pub fn for_targets(
1660+
compilers: RustcPrivateCompilers,
1661+
mut targets: Vec<TargetSelection>,
1662+
) -> Self {
16601663
// Sort targets to improve step cache hits
16611664
targets.sort();
16621665
Self { compilers, targets }
@@ -1673,30 +1676,33 @@ impl Step for GccCodegenBackend {
16731676
}
16741677

16751678
fn make_run(run: RunConfig<'_>) {
1676-
run.builder.ensure(GccCodegenBackend::for_all_std_targets(
1677-
run.builder,
1678-
RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
1679-
));
1679+
// By default, build cg_gcc that will only be able to compile native code for the given
1680+
// host target.
1681+
let compilers = RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target);
1682+
run.builder.ensure(GccCodegenBackend { compilers, targets: vec![run.target] });
16801683
}
16811684

16821685
fn run(self, builder: &Builder<'_>) -> Self::Output {
1683-
let target = self.compilers.target();
1686+
let host = self.compilers.target();
16841687
let build_compiler = self.compilers.build_compiler();
16851688

16861689
let stamp = build_stamp::codegen_backend_stamp(
16871690
builder,
16881691
build_compiler,
1689-
target,
1692+
host,
16901693
&CodegenBackendKind::Gcc,
16911694
);
16921695

16931696
let dylib_set = GccDylibSet {
16941697
dylibs: self
16951698
.targets
16961699
.iter()
1697-
.map(|&target| (target, builder.ensure(Gcc { target })))
1700+
.map(|&target| {
1701+
let target_pair = GccTargetPair::for_cross_build(host, target);
1702+
(target_pair, builder.ensure(Gcc { target_pair }))
1703+
})
16981704
.collect(),
1699-
host_target: target,
1705+
host_pair: GccTargetPair::for_native_build(host),
17001706
};
17011707

17021708
if builder.config.keep_stage.contains(&build_compiler.stage) {
@@ -1715,16 +1721,16 @@ impl Step for GccCodegenBackend {
17151721
build_compiler,
17161722
Mode::Codegen,
17171723
SourceType::InTree,
1718-
target,
1724+
host,
17191725
Kind::Build,
17201726
);
17211727
cargo.arg("--manifest-path").arg(builder.src.join("compiler/rustc_codegen_gcc/Cargo.toml"));
1722-
rustc_cargo_env(builder, &mut cargo, target);
1728+
rustc_cargo_env(builder, &mut cargo, host);
17231729

17241730
add_cg_gcc_cargo_flags(&mut cargo, dylib_set.host_dylib());
17251731

17261732
let _guard =
1727-
builder.msg(Kind::Build, "codegen backend gcc", Mode::Codegen, build_compiler, target);
1733+
builder.msg(Kind::Build, "codegen backend gcc", Mode::Codegen, build_compiler, host);
17281734
let files = run_cargo(builder, cargo, vec![], &stamp, vec![], false, false);
17291735

17301736
GccCodegenBackendOutput {
@@ -2406,9 +2412,59 @@ impl Step for Assemble {
24062412
copy_codegen_backends_to_sysroot(builder, stamp, target_compiler);
24072413
}
24082414
CodegenBackendKind::Gcc => {
2409-
let output = builder.ensure(GccCodegenBackend::for_all_std_targets(
2410-
builder,
2411-
prepare_compilers(),
2415+
// We need to build cg_gcc for the host target of the compiler which we
2416+
// build here, which is `target_compiler`.
2417+
// But we also need to build libgccjit for some additional targets, in
2418+
// the most general case.
2419+
// 1. We need to build (target_compiler.host, stdlib target) libgccjit
2420+
// for all stdlibs that we build, so that cg_gcc can be used to build code
2421+
// for all those targets.
2422+
// 2. We need to build (target_compiler.host, target_compiler.host)
2423+
// libgccjit, so that the target compiler can compile host code (e.g. proc
2424+
// macros).
2425+
// 3. We need to build (target_compiler.host, host target) libgccjit
2426+
// for all *host targets* that we build, so that cg_gcc can be used to
2427+
// build a (possibly cross-compiled) stage 2+ rustc.
2428+
//
2429+
// Assume that we are on host T1 and we do a stage2 build of rustc for T2.
2430+
// We want the T2 rustc compiler to be able to use cg_gcc and build code
2431+
// for T2 (host) and T3 (target). We also want to build the stage2 compiler
2432+
// itself using cg_gcc.
2433+
// This could correspond to the following bootstrap invocation:
2434+
// `x build rustc --build T1 --host T2 --target T3 --set codegen-backends=['gcc', 'llvm']`
2435+
//
2436+
// For that, we will need the following GCC target pairs:
2437+
// 1. T1 -> T2 (to cross-compile a T2 rustc using cg_gcc running on T1)
2438+
// 2. T2 -> T2 (to build host code with the stage 2 rustc running on T2)
2439+
// 3. T2 -> T3 (to cross-compile code with the stage 2 rustc running on T2)
2440+
//
2441+
// Note that this set of targets is *maximal*, in reality we might need
2442+
// less libgccjits at this current build stage. So below we try to determine
2443+
// which target pairs we actually need at this stage.
2444+
2445+
let compilers = prepare_compilers();
2446+
2447+
// The left side of the target pairs below is implied. It has to match the
2448+
// host target on which cg_gcc will run, which is the host target of
2449+
// `target_compiler`. We only pass the right side of the target pairs to
2450+
// the `GccCodegenBackend` constructor.
2451+
let mut targets = HashSet::new();
2452+
// Add all host targets, so that we are able to build host code in this
2453+
// bootstrap invocation using cg_gcc.
2454+
for target in &builder.hosts {
2455+
targets.insert(*target);
2456+
}
2457+
// Add all stdlib targets, so that the built rustc can produce code for them
2458+
for target in &builder.targets {
2459+
targets.insert(*target);
2460+
}
2461+
// Add the host target of the built rustc itself, so that it can build
2462+
// host code (e.g. proc macros) using cg_gcc.
2463+
targets.insert(compilers.target_compiler().host);
2464+
2465+
let output = builder.ensure(GccCodegenBackend::for_targets(
2466+
compilers,
2467+
targets.into_iter().collect(),
24122468
));
24132469
copy_codegen_backends_to_sysroot(builder, output.stamp, target_compiler);
24142470
// Also copy all requires libgccjit dylibs to the corresponding

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use tracing::instrument;
2121

2222
use crate::core::build_steps::compile::{get_codegen_backend_file, normalize_codegen_backend_name};
2323
use crate::core::build_steps::doc::DocumentationFormat;
24+
use crate::core::build_steps::gcc::GccTargetPair;
2425
use crate::core::build_steps::tool::{
2526
self, RustcPrivateCompilers, ToolTargetBuildMode, get_tool_target_compiler,
2627
};
@@ -2856,7 +2857,8 @@ impl Step for Gcc {
28562857

28572858
fn run(self, builder: &Builder<'_>) -> Self::Output {
28582859
let tarball = Tarball::new(builder, "gcc", &self.target.triple);
2859-
let output = builder.ensure(super::gcc::Gcc { target: self.target });
2860+
let output = builder
2861+
.ensure(super::gcc::Gcc { target_pair: GccTargetPair::for_native_build(self.target) });
28602862
tarball.add_file(output.libgccjit(), "lib", FileType::NativeLibrary);
28612863
tarball.generate()
28622864
}

0 commit comments

Comments
 (0)