Skip to content

Commit 07629c3

Browse files
Auto merge of #150538 - Kobzol:dist-cg-gcc-component, r=<try>
Add a dist component for cg_gcc try-job: dist-x86_64-linux
2 parents 629b092 + 6de834d commit 07629c3

File tree

8 files changed

+186
-88
lines changed

8 files changed

+186
-88
lines changed

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

Lines changed: 53 additions & 59 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, GccTargetPair, add_cg_gcc_cargo_flags};
22+
use crate::core::build_steps::gcc::{Gcc, GccOutput, GccTargetPair};
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;
@@ -1569,21 +1569,29 @@ impl Step for RustcLink {
15691569
}
15701570

15711571
/// Set of `libgccjit` dylibs that can be used by `cg_gcc` to compile code for a set of targets.
1572+
/// `libgccjit` requires a separate build for each `(host, target)` pair.
1573+
/// So if you are on linux-x64 and build for linux-aarch64, you will need at least:
1574+
/// - linux-x64 -> linux-x64 libgccjit (for building host code like proc macros)
1575+
/// - linux-x64 -> linux-aarch64 libgccjit (for the aarch64 target code)
15721576
#[derive(Clone)]
15731577
pub struct GccDylibSet {
15741578
dylibs: BTreeMap<GccTargetPair, GccOutput>,
1575-
host_pair: GccTargetPair,
15761579
}
15771580

15781581
impl GccDylibSet {
1579-
/// Returns the libgccjit.so dylib that corresponds to a host target on which `cg_gcc` will be
1580-
/// executed, and which will target the host. So e.g. if `cg_gcc` will be executed on
1581-
/// x86_64-unknown-linux-gnu, the host dylib will be for compilation pair
1582-
/// `(x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu)`.
1583-
fn host_dylib(&self) -> &GccOutput {
1584-
self.dylibs.get(&self.host_pair).unwrap_or_else(|| {
1585-
panic!("libgccjit.so was not built for host target {}", self.host_pair)
1586-
})
1582+
/// Build a set of libgccjit dylibs that will be executed on `host` and will generate code for
1583+
/// each specified target.
1584+
pub fn build(
1585+
builder: &Builder<'_>,
1586+
host: TargetSelection,
1587+
targets: Vec<TargetSelection>,
1588+
) -> Self {
1589+
let dylibs = targets
1590+
.iter()
1591+
.map(|t| GccTargetPair::for_target_pair(host, *t))
1592+
.map(|target_pair| (target_pair, builder.ensure(Gcc { target_pair })))
1593+
.collect();
1594+
Self { dylibs }
15871595
}
15881596

15891597
/// Install the libgccjit dylibs to the corresponding target directories of the given compiler.
@@ -1626,39 +1634,34 @@ impl GccDylibSet {
16261634

16271635
/// Output of the `compile::GccCodegenBackend` step.
16281636
///
1629-
/// It contains paths to all built libgccjit libraries on which this backend depends here.
1637+
/// It contains a build stamp with the path to the built cg_gcc dylib.
16301638
#[derive(Clone)]
16311639
pub struct GccCodegenBackendOutput {
16321640
stamp: BuildStamp,
1633-
dylib_set: GccDylibSet,
1641+
}
1642+
1643+
impl GccCodegenBackendOutput {
1644+
pub fn stamp(&self) -> &BuildStamp {
1645+
&self.stamp
1646+
}
16341647
}
16351648

16361649
/// Builds the GCC codegen backend (`cg_gcc`).
1637-
/// The `cg_gcc` backend uses `libgccjit`, which requires a separate build for each
1638-
/// `host -> target` pair. So if you are on linux-x64 and build for linux-aarch64,
1639-
/// you will need at least:
1640-
/// - linux-x64 -> linux-x64 libgccjit (for building host code like proc macros)
1641-
/// - linux-x64 -> linux-aarch64 libgccjit (for the aarch64 target code)
1642-
///
1643-
/// We model this by having a single cg_gcc for a given host target, which contains one
1644-
/// libgccjit per (host, target) pair.
1645-
/// Note that the host target is taken from `self.compilers.target_compiler.host`.
1650+
/// Note that this **does not** build libgccjit, which is a dependency of cg_gcc.
1651+
/// That has to be built separately, because a separate copy of libgccjit is required
1652+
/// for each (host, target) compilation pair.
1653+
/// cg_gcc goes to great lengths to ensure that it does not *directly* link to libgccjit,
1654+
/// so we respect that here and allow building cg_gcc without building libgccjit itself.
16461655
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
16471656
pub struct GccCodegenBackend {
16481657
compilers: RustcPrivateCompilers,
1649-
targets: Vec<TargetSelection>,
1658+
target: TargetSelection,
16501659
}
16511660

16521661
impl GccCodegenBackend {
1653-
/// Build `cg_gcc` that will run on host `H` (`compilers.target_compiler.host`) and will be
1654-
/// able to produce code target pairs (`H`, `T`) for all `T` from `targets`.
1655-
pub fn for_targets(
1656-
compilers: RustcPrivateCompilers,
1657-
mut targets: Vec<TargetSelection>,
1658-
) -> Self {
1659-
// Sort targets to improve step cache hits
1660-
targets.sort();
1661-
Self { compilers, targets }
1662+
/// Build `cg_gcc` that will run on the given host target.
1663+
pub fn for_target(compilers: RustcPrivateCompilers, target: TargetSelection) -> Self {
1664+
Self { compilers, target }
16621665
}
16631666
}
16641667

@@ -1672,10 +1675,8 @@ impl Step for GccCodegenBackend {
16721675
}
16731676

16741677
fn make_run(run: RunConfig<'_>) {
1675-
// By default, build cg_gcc that will only be able to compile native code for the given
1676-
// host target.
16771678
let compilers = RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target);
1678-
run.builder.ensure(GccCodegenBackend { compilers, targets: vec![run.target] });
1679+
run.builder.ensure(GccCodegenBackend::for_target(compilers, run.target));
16791680
}
16801681

16811682
fn run(self, builder: &Builder<'_>) -> Self::Output {
@@ -1689,18 +1690,6 @@ impl Step for GccCodegenBackend {
16891690
&CodegenBackendKind::Gcc,
16901691
);
16911692

1692-
let dylib_set = GccDylibSet {
1693-
dylibs: self
1694-
.targets
1695-
.iter()
1696-
.map(|&target| {
1697-
let target_pair = GccTargetPair::for_target_pair(host, target);
1698-
(target_pair, builder.ensure(Gcc { target_pair }))
1699-
})
1700-
.collect(),
1701-
host_pair: GccTargetPair::for_native_build(host),
1702-
};
1703-
17041693
if builder.config.keep_stage.contains(&build_compiler.stage) {
17051694
trace!("`keep-stage` requested");
17061695
builder.info(
@@ -1709,7 +1698,7 @@ impl Step for GccCodegenBackend {
17091698
);
17101699
// Codegen backends are linked separately from this step today, so we don't do
17111700
// anything here.
1712-
return GccCodegenBackendOutput { stamp, dylib_set };
1701+
return GccCodegenBackendOutput { stamp };
17131702
}
17141703

17151704
let mut cargo = builder::Cargo::new(
@@ -1723,15 +1712,12 @@ impl Step for GccCodegenBackend {
17231712
cargo.arg("--manifest-path").arg(builder.src.join("compiler/rustc_codegen_gcc/Cargo.toml"));
17241713
rustc_cargo_env(builder, &mut cargo, host);
17251714

1726-
add_cg_gcc_cargo_flags(&mut cargo, dylib_set.host_dylib());
1727-
17281715
let _guard =
17291716
builder.msg(Kind::Build, "codegen backend gcc", Mode::Codegen, build_compiler, host);
17301717
let files = run_cargo(builder, cargo, vec![], &stamp, vec![], false, false);
17311718

17321719
GccCodegenBackendOutput {
17331720
stamp: write_codegen_backend_stamp(stamp, files, builder.config.dry_run()),
1734-
dylib_set,
17351721
}
17361722
}
17371723

@@ -2457,12 +2443,18 @@ impl Step for Assemble {
24572443
// GCC dylibs built below by taking a look at the current stage and whether
24582444
// cg_gcc is used as the default codegen backend.
24592445

2446+
// First, the easy part: build cg_gcc
24602447
let compilers = prepare_compilers();
2448+
let cg_gcc = builder
2449+
.ensure(GccCodegenBackend::for_target(compilers, target_compiler.host));
2450+
copy_codegen_backends_to_sysroot(builder, cg_gcc.stamp, target_compiler);
2451+
2452+
// Then, the hard part: prepare all required libgccjit dylibs.
24612453

24622454
// The left side of the target pairs below is implied. It has to match the
2463-
// host target on which cg_gcc will run, which is the host target of
2455+
// host target on which libgccjit will be used, which is the host target of
24642456
// `target_compiler`. We only pass the right side of the target pairs to
2465-
// the `GccCodegenBackend` constructor.
2457+
// the `GccDylibSet` constructor.
24662458
let mut targets = HashSet::new();
24672459
// Add all host targets, so that we are able to build host code in this
24682460
// bootstrap invocation using cg_gcc.
@@ -2477,14 +2469,16 @@ impl Step for Assemble {
24772469
// host code (e.g. proc macros) using cg_gcc.
24782470
targets.insert(compilers.target_compiler().host);
24792471

2480-
let output = builder.ensure(GccCodegenBackend::for_targets(
2481-
compilers,
2472+
// Now build all the required libgccjit dylibs
2473+
let dylib_set = GccDylibSet::build(
2474+
builder,
2475+
compilers.target_compiler().host,
24822476
targets.into_iter().collect(),
2483-
));
2484-
copy_codegen_backends_to_sysroot(builder, output.stamp, target_compiler);
2485-
// Also copy all requires libgccjit dylibs to the corresponding
2486-
// library sysroots, so that they are available for the codegen backend.
2487-
output.dylib_set.install_to(builder, target_compiler);
2477+
);
2478+
2479+
// And then copy all the dylibs to the corresponding
2480+
// library sysroots, so that they are available for cg_gcc.
2481+
dylib_set.install_to(builder, target_compiler);
24882482
}
24892483
CodegenBackendKind::Llvm | CodegenBackendKind::Custom(_) => continue,
24902484
}

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

Lines changed: 116 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1652,23 +1652,7 @@ impl Step for CraneliftCodegenBackend {
16521652
return None;
16531653
}
16541654

1655-
// Get the relative path of where the codegen backend should be stored.
1656-
let backends_dst = builder.sysroot_codegen_backends(compilers.target_compiler());
1657-
let backends_rel = backends_dst
1658-
.strip_prefix(builder.sysroot(compilers.target_compiler()))
1659-
.unwrap()
1660-
.strip_prefix(builder.sysroot_libdir_relative(compilers.target_compiler()))
1661-
.unwrap();
1662-
// Don't use custom libdir here because ^lib/ will be resolved again with installer
1663-
let backends_dst = PathBuf::from("lib").join(backends_rel);
1664-
1665-
let codegen_backend_dylib = get_codegen_backend_file(&stamp);
1666-
tarball.add_renamed_file(
1667-
&codegen_backend_dylib,
1668-
&backends_dst,
1669-
&normalize_codegen_backend_name(builder, &codegen_backend_dylib),
1670-
FileType::NativeLibrary,
1671-
);
1655+
add_codegen_backend_to_tarball(builder, &tarball, compilers.target_compiler(), &stamp);
16721656

16731657
Some(tarball.generate())
16741658
}
@@ -1681,6 +1665,113 @@ impl Step for CraneliftCodegenBackend {
16811665
}
16821666
}
16831667

1668+
/// Builds a dist component containing the GCC codegen backend.
1669+
/// Note that for this backend to work, it must have a set of libgccjit dylibs available
1670+
/// at runtime.
1671+
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1672+
pub struct GccCodegenBackend {
1673+
pub compilers: RustcPrivateCompilers,
1674+
pub target: TargetSelection,
1675+
}
1676+
1677+
impl Step for GccCodegenBackend {
1678+
type Output = Option<GeneratedTarball>;
1679+
const IS_HOST: bool = true;
1680+
1681+
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1682+
run.alias("rustc_codegen_gcc")
1683+
}
1684+
1685+
fn is_default_step(builder: &Builder<'_>) -> bool {
1686+
// We only want to build the gcc backend in `x dist` if the backend was enabled
1687+
// in rust.codegen-backends.
1688+
// Sadly, we don't have access to the actual target for which we're disting clif here..
1689+
// So we just use the host target.
1690+
builder
1691+
.config
1692+
.enabled_codegen_backends(builder.host_target)
1693+
.contains(&CodegenBackendKind::Gcc)
1694+
}
1695+
1696+
fn make_run(run: RunConfig<'_>) {
1697+
run.builder.ensure(GccCodegenBackend {
1698+
compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
1699+
target: run.target,
1700+
});
1701+
}
1702+
1703+
fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1704+
// This prevents rustc_codegen_gcc from being built for "dist"
1705+
// or "install" on the stable/beta channels. It is not yet stable and
1706+
// should not be included.
1707+
if !builder.build.unstable_features() {
1708+
return None;
1709+
}
1710+
1711+
let target = self.target;
1712+
if target != "x86_64-unknown-linux-gnu" {
1713+
builder
1714+
.info(&format!("target `{target}` not supported by rustc_codegen_gcc. skipping"));
1715+
return None;
1716+
}
1717+
1718+
let mut tarball = Tarball::new(builder, "rustc-codegen-gcc", &target.triple);
1719+
tarball.set_overlay(OverlayKind::RustcCodegenGcc);
1720+
tarball.is_preview(true);
1721+
tarball.add_legal_and_readme_to("share/doc/rustc_codegen_gcc");
1722+
1723+
let compilers = self.compilers;
1724+
let backend = builder.ensure(compile::GccCodegenBackend::for_target(compilers, target));
1725+
1726+
if builder.config.dry_run() {
1727+
return None;
1728+
}
1729+
1730+
add_codegen_backend_to_tarball(
1731+
builder,
1732+
&tarball,
1733+
compilers.target_compiler(),
1734+
backend.stamp(),
1735+
);
1736+
1737+
Some(tarball.generate())
1738+
}
1739+
1740+
fn metadata(&self) -> Option<StepMetadata> {
1741+
Some(
1742+
StepMetadata::dist("rustc_codegen_gcc", self.target)
1743+
.built_by(self.compilers.build_compiler()),
1744+
)
1745+
}
1746+
}
1747+
1748+
/// Add a codegen backend built for `compiler`, with its artifacts stored in `stamp`, to the given
1749+
/// `tarball` at the correct place.
1750+
fn add_codegen_backend_to_tarball(
1751+
builder: &Builder<'_>,
1752+
tarball: &Tarball<'_>,
1753+
compiler: Compiler,
1754+
stamp: &BuildStamp,
1755+
) {
1756+
// Get the relative path of where the codegen backend should be stored.
1757+
let backends_dst = builder.sysroot_codegen_backends(compiler);
1758+
let backends_rel = backends_dst
1759+
.strip_prefix(builder.sysroot(compiler))
1760+
.unwrap()
1761+
.strip_prefix(builder.sysroot_libdir_relative(compiler))
1762+
.unwrap();
1763+
// Don't use custom libdir here because ^lib/ will be resolved again with installer
1764+
let backends_dst = PathBuf::from("lib").join(backends_rel);
1765+
1766+
let codegen_backend_dylib = get_codegen_backend_file(stamp);
1767+
tarball.add_renamed_file(
1768+
&codegen_backend_dylib,
1769+
&backends_dst,
1770+
&normalize_codegen_backend_name(builder, &codegen_backend_dylib),
1771+
FileType::NativeLibrary,
1772+
);
1773+
}
1774+
16841775
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
16851776
pub struct Rustfmt {
16861777
pub compilers: RustcPrivateCompilers,
@@ -2871,31 +2962,33 @@ impl Step for ReproducibleArtifacts {
28712962
/// Tarball containing a prebuilt version of the libgccjit library,
28722963
/// needed as a dependency for the GCC codegen backend (similarly to the LLVM
28732964
/// backend needing a prebuilt libLLVM).
2965+
///
2966+
/// This component is used for `download-ci-gcc`.
28742967
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
2875-
pub struct Gcc {
2968+
pub struct CiGcc {
28762969
target: TargetSelection,
28772970
}
28782971

2879-
impl Step for Gcc {
2972+
impl Step for CiGcc {
28802973
type Output = GeneratedTarball;
28812974

28822975
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2883-
run.alias("gcc")
2976+
run.alias("ci-gcc")
28842977
}
28852978

28862979
fn make_run(run: RunConfig<'_>) {
2887-
run.builder.ensure(Gcc { target: run.target });
2980+
run.builder.ensure(CiGcc { target: run.target });
28882981
}
28892982

28902983
fn run(self, builder: &Builder<'_>) -> Self::Output {
2891-
let tarball = Tarball::new(builder, "gcc", &self.target.triple);
2984+
let tarball = Tarball::new(builder, "ci-gcc", &self.target.triple);
28922985
let output = builder
28932986
.ensure(super::gcc::Gcc { target_pair: GccTargetPair::for_native_build(self.target) });
28942987
tarball.add_file(output.libgccjit(), "lib", FileType::NativeLibrary);
28952988
tarball.generate()
28962989
}
28972990

28982991
fn metadata(&self) -> Option<StepMetadata> {
2899-
Some(StepMetadata::dist("gcc", self.target))
2992+
Some(StepMetadata::dist("ci-gcc", self.target))
29002993
}
29012994
}

0 commit comments

Comments
 (0)