authorbors <bors@rust-lang.org> 2026-01-08 09:53:23 UTC
committerGitHub <noreply@github.com> 2026-01-08 09:53:23 UTC
log32fe406b5e71afbb0d8b95280e50e67d1549224c
treee42b2332ba86993d22423d38eb454879516ee6f9
parentbca37a20bd376ce3fd138e7cdee7fe704e0f8814
parent04707f4f86ea0b484da9c368dcb81fdfb7939bf2

Auto merge of #150538 - Kobzol:dist-cg-gcc-component, r=jieyouxu

Add a dist component for cg_gcc try-job: dist-x86_64-linux

6 files changed, 174 insertions(+), 78 deletions(-)

src/bootstrap/src/core/build_steps/compile.rs+54-60
......@@ -19,7 +19,7 @@ use serde_derive::Deserialize;
1919#[cfg(feature = "tracing")]
2020use tracing::span;
2121
22use crate::core::build_steps::gcc::{Gcc, GccOutput, GccTargetPair, add_cg_gcc_cargo_flags};
22use crate::core::build_steps::gcc::{Gcc, GccOutput, GccTargetPair};
2323use crate::core::build_steps::tool::{RustcPrivateCompilers, SourceType, copy_lld_artifacts};
2424use crate::core::build_steps::{dist, llvm};
2525use 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)]
15731577pub struct GccDylibSet {
15741578 dylibs: BTreeMap<GccTargetPair, GccOutput>,
1575 host_pair: GccTargetPair,
15761579}
15771580
15781581impl 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)]
16311639pub struct GccCodegenBackendOutput {
16321640 stamp: BuildStamp,
1633 dylib_set: GccDylibSet,
1641}
1642
1643impl 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)]
16471656pub struct GccCodegenBackend {
16481657 compilers: RustcPrivateCompilers,
1649 targets: Vec<TargetSelection>,
1658 target: TargetSelection,
16501659}
16511660
16521661impl 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,19 +1690,7 @@ 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
1704 if builder.config.keep_stage.contains(&build_compiler.stage) {
1693 if builder.config.keep_stage.contains(&build_compiler.stage) && stamp.path().exists() {
17051694 trace!("`keep-stage` requested");
17061695 builder.info(
17071696 "WARNING: Using a potentially old codegen backend. \
......@@ -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+108-17
......@@ -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)]
1672pub struct GccCodegenBackend {
1673 pub compilers: RustcPrivateCompilers,
1674 pub target: TargetSelection,
1675}
1676
1677impl 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.
1750fn 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)]
16851776pub struct Rustfmt {
16861777 pub compilers: RustcPrivateCompilers,
src/bootstrap/src/core/builder/mod.rs+1
......@@ -967,6 +967,7 @@ impl<'a> Builder<'a> {
967967 dist::Mingw,
968968 dist::Rustc,
969969 dist::CraneliftCodegenBackend,
970 dist::GccCodegenBackend,
970971 dist::Std,
971972 dist::RustcDev,
972973 dist::Analysis,
src/bootstrap/src/utils/tarball.rs+7
......@@ -25,6 +25,7 @@ pub(crate) enum OverlayKind {
2525 Rustfmt,
2626 RustAnalyzer,
2727 RustcCodegenCranelift,
28 RustcCodegenGcc,
2829 LlvmBitcodeLinker,
2930}
3031
......@@ -66,6 +67,11 @@ impl OverlayKind {
6667 "compiler/rustc_codegen_cranelift/LICENSE-APACHE",
6768 "compiler/rustc_codegen_cranelift/LICENSE-MIT",
6869 ],
70 OverlayKind::RustcCodegenGcc => &[
71 "compiler/rustc_codegen_gcc/Readme.md",
72 "compiler/rustc_codegen_gcc/LICENSE-APACHE",
73 "compiler/rustc_codegen_gcc/LICENSE-MIT",
74 ],
6975 OverlayKind::LlvmBitcodeLinker => &[
7076 "COPYRIGHT",
7177 "LICENSE-APACHE",
......@@ -93,6 +99,7 @@ impl OverlayKind {
9399 .rust_analyzer_info
94100 .version(builder, &builder.release_num("rust-analyzer/crates/rust-analyzer")),
95101 OverlayKind::RustcCodegenCranelift => builder.rust_version(),
102 OverlayKind::RustcCodegenGcc => builder.rust_version(),
96103 OverlayKind::LlvmBitcodeLinker => builder.rust_version(),
97104 }
98105 }
src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh+3-1
......@@ -7,7 +7,9 @@ python3 ../x.py build --set rust.debug=true opt-dist
77./build/$HOSTS/stage1-tools-bin/opt-dist linux-ci -- python3 ../x.py dist \
88 --host $HOSTS --target $HOSTS \
99 --include-default-paths \
10 build-manifest bootstrap
10 build-manifest \
11 bootstrap \
12 rustc_codegen_gcc
1113
1214# Use GCC for building GCC components, as it seems to behave badly when built with Clang
1315# Only build GCC on full builds, not try builds
src/tools/opt-dist/src/main.rs+1
......@@ -456,6 +456,7 @@ fn main() -> anyhow::Result<()> {
456456 "rustfmt",
457457 "generate-copyright",
458458 "bootstrap",
459 "rustc_codegen_gcc",
459460 ] {
460461 build_args.extend(["--skip".to_string(), target.to_string()]);
461462 }