Auto merge of #149354 - antoyo:bootstrap-config/libgccjit-libs-dir, r… · rust-lang/rust@cec7008 (original) (raw)
`@@ -7,7 +7,7 @@
`
7
7
`//! goes along from the output of the previous stage.
`
8
8
``
9
9
`use std::borrow::Cow;
`
10
``
`-
use std::collections::{HashMap, HashSet};
`
``
10
`+
use std::collections::{BTreeMap, HashMap, HashSet};
`
11
11
`use std::ffi::OsStr;
`
12
12
`use std::io::BufReader;
`
13
13
`use std::io::prelude::*;
`
`@@ -19,7 +19,7 @@ use serde_derive::Deserialize;
`
19
19
`#[cfg(feature = "tracing")]
`
20
20
`use tracing::span;
`
21
21
``
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};
`
23
23
`use crate::core::build_steps::tool::{RustcPrivateCompilers, SourceType, copy_lld_artifacts};
`
24
24
`use crate::core::build_steps::{dist, llvm};
`
25
25
`use crate::core::builder;
`
`@@ -1576,17 +1576,98 @@ impl Step for RustcLink {
`
1576
1576
`}
`
1577
1577
`}
`
1578
1578
``
``
1579
`` +
/// Set of libgccjit dylibs that can be used by cg_gcc to compile code for a set of targets.
``
``
1580
`+
#[derive(Clone)]
`
``
1581
`+
pub struct GccDylibSet {
`
``
1582
`+
dylibs: BTreeMap<GccTargetPair, GccOutput>,
`
``
1583
`+
host_pair: GccTargetPair,
`
``
1584
`+
}
`
``
1585
+
``
1586
`+
impl GccDylibSet {
`
``
1587
`` +
/// Returns the libgccjit.so dylib that corresponds to a host target on which cg_gcc will be
``
``
1588
`` +
/// executed, and which will target the host. So e.g. if cg_gcc will be executed on
``
``
1589
`+
/// x86_64-unknown-linux-gnu, the host dylib will be for compilation pair
`
``
1590
`` +
/// (x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu).
``
``
1591
`+
fn host_dylib(&self) -> &GccOutput {
`
``
1592
`+
self.dylibs.get(&self.host_pair).unwrap_or_else(|| {
`
``
1593
`+
panic!("libgccjit.so was not built for host target {}", self.host_pair)
`
``
1594
`+
})
`
``
1595
`+
}
`
``
1596
+
``
1597
`+
/// Install the libgccjit dylibs to the corresponding target directories of the given compiler.
`
``
1598
`+
/// cg_gcc know how to search for the libgccjit dylibs in these directories, according to the
`
``
1599
`+
/// (host, target) pair that is being compiled by rustc and cg_gcc.
`
``
1600
`+
pub fn install_to(&self, builder: &Builder<'_>, compiler: Compiler) {
`
``
1601
`+
if builder.config.dry_run() {
`
``
1602
`+
return;
`
``
1603
`+
}
`
``
1604
+
``
1605
`+
// /lib//codegen-backends
`
``
1606
`+
let cg_sysroot = builder.sysroot_codegen_backends(compiler);
`
``
1607
+
``
1608
`+
for (target_pair, libgccjit) in &self.dylibs {
`
``
1609
`+
assert_eq!(
`
``
1610
`+
target_pair.host(),
`
``
1611
`+
compiler.host,
`
``
1612
`+
"Trying to install libgccjit ({target_pair}) to a compiler with a different host ({})",
`
``
1613
`+
compiler.host
`
``
1614
`+
);
`
``
1615
`+
let libgccjit = libgccjit.libgccjit();
`
``
1616
`+
let target_filename = libgccjit.file_name().unwrap().to_str().unwrap();
`
``
1617
+
``
1618
`` +
// If we build libgccjit ourselves, then libgccjit can actually be a symlink.
``
``
1619
`+
// In that case, we have to resolve it first, otherwise we'd create a symlink to a
`
``
1620
`+
// symlink, which wouldn't work.
`
``
1621
`+
let actual_libgccjit_path = t!(
`
``
1622
`+
libgccjit.canonicalize(),
`
``
1623
`+
format!("Cannot find libgccjit at {}", libgccjit.display())
`
``
1624
`+
);
`
``
1625
+
``
1626
`+
// /lib//libgccjit.so
`
``
1627
`+
let dest_dir = cg_sysroot.join("lib").join(target_pair.target());
`
``
1628
`+
t!(fs::create_dir_all(&dest_dir));
`
``
1629
`+
let dst = dest_dir.join(target_filename);
`
``
1630
`+
builder.copy_link(&actual_libgccjit_path, &dst, FileType::NativeLibrary);
`
``
1631
`+
}
`
``
1632
`+
}
`
``
1633
`+
}
`
``
1634
+
1579
1635
`` /// Output of the compile::GccCodegenBackend step.
``
1580
``
`-
/// It includes the path to the libgccjit library on which this backend depends.
`
``
1636
`+
///
`
``
1637
`+
/// It contains paths to all built libgccjit libraries on which this backend depends here.
`
1581
1638
`#[derive(Clone)]
`
1582
1639
`pub struct GccCodegenBackendOutput {
`
1583
1640
`stamp: BuildStamp,
`
1584
``
`-
gcc: GccOutput,
`
``
1641
`+
dylib_set: GccDylibSet,
`
1585
1642
`}
`
1586
1643
``
``
1644
`` +
/// Builds the GCC codegen backend (cg_gcc).
``
``
1645
`` +
/// The cg_gcc backend uses libgccjit, which requires a separate build for each
``
``
1646
`` +
/// host -> target pair. So if you are on linux-x64 and build for linux-aarch64,
``
``
1647
`+
/// you will need at least:
`
``
1648
`+
/// - linux-x64 -> linux-x64 libgccjit (for building host code like proc macros)
`
``
1649
`+
/// - linux-x64 -> linux-aarch64 libgccjit (for the aarch64 target code)
`
``
1650
`+
///
`
``
1651
`+
/// We model this by having a single cg_gcc for a given host target, which contains one
`
``
1652
`+
/// libgccjit per (host, target) pair.
`
``
1653
`` +
/// Note that the host target is taken from self.compilers.target_compiler.host.
``
1587
1654
`#[derive(Debug, Clone, PartialEq, Eq, Hash)]
`
1588
1655
`pub struct GccCodegenBackend {
`
1589
1656
`compilers: RustcPrivateCompilers,
`
``
1657
`+
targets: Vec,
`
``
1658
`+
}
`
``
1659
+
``
1660
`+
impl GccCodegenBackend {
`
``
1661
`` +
/// Build cg_gcc that will run on host H (compilers.target_compiler.host) and will be
``
``
1662
`` +
/// able to produce code target pairs (H, T) for all T from targets.
``
``
1663
`+
pub fn for_targets(
`
``
1664
`+
compilers: RustcPrivateCompilers,
`
``
1665
`+
mut targets: Vec,
`
``
1666
`+
) -> Self {
`
``
1667
`+
// Sort targets to improve step cache hits
`
``
1668
`+
targets.sort();
`
``
1669
`+
Self { compilers, targets }
`
``
1670
`+
}
`
1590
1671
`}
`
1591
1672
``
1592
1673
`impl Step for GccCodegenBackend {
`
`@@ -1599,23 +1680,34 @@ impl Step for GccCodegenBackend {
`
1599
1680
`}
`
1600
1681
``
1601
1682
`fn make_run(run: RunConfig<'_>) {
`
1602
``
`-
run.builder.ensure(GccCodegenBackend {
`
1603
``
`-
compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
`
1604
``
`-
});
`
``
1683
`+
// By default, build cg_gcc that will only be able to compile native code for the given
`
``
1684
`+
// host target.
`
``
1685
`+
let compilers = RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target);
`
``
1686
`+
run.builder.ensure(GccCodegenBackend { compilers, targets: vec![run.target] });
`
1605
1687
`}
`
1606
1688
``
1607
1689
`fn run(self, builder: &Builder<'_>) -> Self::Output {
`
1608
``
`-
let target = self.compilers.target();
`
``
1690
`+
let host = self.compilers.target();
`
1609
1691
`let build_compiler = self.compilers.build_compiler();
`
1610
1692
``
1611
1693
`let stamp = build_stamp::codegen_backend_stamp(
`
1612
1694
` builder,
`
1613
1695
` build_compiler,
`
1614
``
`-
target,
`
``
1696
`+
host,
`
1615
1697
`&CodegenBackendKind::Gcc,
`
1616
1698
`);
`
1617
1699
``
1618
``
`-
let gcc = builder.ensure(Gcc { target });
`
``
1700
`+
let dylib_set = GccDylibSet {
`
``
1701
`+
dylibs: self
`
``
1702
`+
.targets
`
``
1703
`+
.iter()
`
``
1704
`+
.map(|&target| {
`
``
1705
`+
let target_pair = GccTargetPair::for_target_pair(host, target);
`
``
1706
`+
(target_pair, builder.ensure(Gcc { target_pair }))
`
``
1707
`+
})
`
``
1708
`+
.collect(),
`
``
1709
`+
host_pair: GccTargetPair::for_native_build(host),
`
``
1710
`+
};
`
1619
1711
``
1620
1712
`if builder.config.keep_stage.contains(&build_compiler.stage) {
`
1621
1713
`` trace!("keep-stage requested");
``
`@@ -1625,29 +1717,29 @@ impl Step for GccCodegenBackend {
`
1625
1717
`);
`
1626
1718
`// Codegen backends are linked separately from this step today, so we don't do
`
1627
1719
`// anything here.
`
1628
``
`-
return GccCodegenBackendOutput { stamp, gcc };
`
``
1720
`+
return GccCodegenBackendOutput { stamp, dylib_set };
`
1629
1721
`}
`
1630
1722
``
1631
1723
`let mut cargo = builder::Cargo::new(
`
1632
1724
` builder,
`
1633
1725
` build_compiler,
`
1634
1726
`Mode::Codegen,
`
1635
1727
`SourceType::InTree,
`
1636
``
`-
target,
`
``
1728
`+
host,
`
1637
1729
`Kind::Build,
`
1638
1730
`);
`
1639
1731
` cargo.arg("--manifest-path").arg(builder.src.join("compiler/rustc_codegen_gcc/Cargo.toml"));
`
1640
``
`-
rustc_cargo_env(builder, &mut cargo, target);
`
``
1732
`+
rustc_cargo_env(builder, &mut cargo, host);
`
1641
1733
``
1642
``
`-
add_cg_gcc_cargo_flags(&mut cargo, &gcc);
`
``
1734
`+
add_cg_gcc_cargo_flags(&mut cargo, dylib_set.host_dylib());
`
1643
1735
``
1644
1736
`let _guard =
`
1645
``
`-
builder.msg(Kind::Build, "codegen backend gcc", Mode::Codegen, build_compiler, target);
`
``
1737
`+
builder.msg(Kind::Build, "codegen backend gcc", Mode::Codegen, build_compiler, host);
`
1646
1738
`let files = run_cargo(builder, cargo, vec![], &stamp, vec![], false, false);
`
1647
1739
``
1648
1740
`GccCodegenBackendOutput {
`
1649
1741
`stamp: write_codegen_backend_stamp(stamp, files, builder.config.dry_run()),
`
1650
``
`-
gcc,
`
``
1742
`+
dylib_set,
`
1651
1743
`}
`
1652
1744
`}
`
1653
1745
``
`@@ -2324,12 +2416,65 @@ impl Step for Assemble {
`
2324
2416
`copy_codegen_backends_to_sysroot(builder, stamp, target_compiler);
`
2325
2417
`}
`
2326
2418
`CodegenBackendKind::Gcc => {
`
2327
``
`-
let output =
`
2328
``
`-
builder.ensure(GccCodegenBackend { compilers: prepare_compilers() });
`
``
2419
`+
// We need to build cg_gcc for the host target of the compiler which we
`
``
2420
`` +
// build here, which is target_compiler.
``
``
2421
`+
// But we also need to build libgccjit for some additional targets, in
`
``
2422
`+
// the most general case.
`
``
2423
`+
// 1. We need to build (target_compiler.host, stdlib target) libgccjit
`
``
2424
`+
// for all stdlibs that we build, so that cg_gcc can be used to build code
`
``
2425
`+
// for all those targets.
`
``
2426
`+
// 2. We need to build (target_compiler.host, target_compiler.host)
`
``
2427
`+
// libgccjit, so that the target compiler can compile host code (e.g. proc
`
``
2428
`+
// macros).
`
``
2429
`+
// 3. We need to build (target_compiler.host, host target) libgccjit
`
``
2430
`+
// for all host targets that we build, so that cg_gcc can be used to
`
``
2431
`+
// build a (possibly cross-compiled) stage 2+ rustc.
`
``
2432
`+
//
`
``
2433
`+
// Assume that we are on host T1 and we do a stage2 build of rustc for T2.
`
``
2434
`+
// We want the T2 rustc compiler to be able to use cg_gcc and build code
`
``
2435
`+
// for T2 (host) and T3 (target). We also want to build the stage2 compiler
`
``
2436
`+
// itself using cg_gcc.
`
``
2437
`+
// This could correspond to the following bootstrap invocation:
`
``
2438
`` +
// x build rustc --build T1 --host T2 --target T3 --set codegen-backends=['gcc', 'llvm']
``
``
2439
`+
//
`
``
2440
`+
// For that, we will need the following GCC target pairs:
`
``
2441
`+
// 1. T1 -> T2 (to cross-compile a T2 rustc using cg_gcc running on T1)
`
``
2442
`+
// 2. T2 -> T2 (to build host code with the stage 2 rustc running on T2)
`
``
2443
`+
// 3. T2 -> T3 (to cross-compile code with the stage 2 rustc running on T2)
`
``
2444
`+
//
`
``
2445
`+
// FIXME: this set of targets is maximal, in reality we might need
`
``
2446
`+
// less libgccjits at this current build stage. Try to reduce the set of
`
``
2447
`+
// GCC dylibs built below by taking a look at the current stage and whether
`
``
2448
`+
// cg_gcc is used as the default codegen backend.
`
``
2449
+
``
2450
`+
let compilers = prepare_compilers();
`
``
2451
+
``
2452
`+
// The left side of the target pairs below is implied. It has to match the
`
``
2453
`+
// host target on which cg_gcc will run, which is the host target of
`
``
2454
`` +
// target_compiler. We only pass the right side of the target pairs to
``
``
2455
`` +
// the GccCodegenBackend constructor.
``
``
2456
`+
let mut targets = HashSet::new();
`
``
2457
`+
// Add all host targets, so that we are able to build host code in this
`
``
2458
`+
// bootstrap invocation using cg_gcc.
`
``
2459
`+
for target in &builder.hosts {
`
``
2460
`+
targets.insert(*target);
`
``
2461
`+
}
`
``
2462
`+
// Add all stdlib targets, so that the built rustc can produce code for them
`
``
2463
`+
for target in &builder.targets {
`
``
2464
`+
targets.insert(*target);
`
``
2465
`+
}
`
``
2466
`+
// Add the host target of the built rustc itself, so that it can build
`
``
2467
`+
// host code (e.g. proc macros) using cg_gcc.
`
``
2468
`+
targets.insert(compilers.target_compiler().host);
`
``
2469
+
``
2470
`+
let output = builder.ensure(GccCodegenBackend::for_targets(
`
``
2471
`+
compilers,
`
``
2472
`+
targets.into_iter().collect(),
`
``
2473
`+
));
`
2329
2474
`copy_codegen_backends_to_sysroot(builder, output.stamp, target_compiler);
`
2330
``
`-
// Also copy libgccjit to the library sysroot, so that it is available for
`
2331
``
`-
// the codegen backend.
`
2332
``
`-
output.gcc.install_to(builder, &rustc_libdir);
`
``
2475
`+
// Also copy all requires libgccjit dylibs to the corresponding
`
``
2476
`+
// library sysroots, so that they are available for the codegen backend.
`
``
2477
`+
output.dylib_set.install_to(builder, target_compiler);
`
2333
2478
`}
`
2334
2479
`CodegenBackendKind::Llvm | CodegenBackendKind::Custom(_) => continue,
`
2335
2480
`}
`