| author | bors <bors@rust-lang.org> 2026-01-14 09:57:06 UTC |
| committer | bors <bors@rust-lang.org> 2026-01-14 09:57:06 UTC |
| log | 2fd6efc32704647e64d3d646d21c4c68eae100e4 |
| tree | 64c8d234e9eaad96a2a9d26b39767e4d9230470e |
| parent | 4931e09e3ac3182d2a00f38cccfdf68e8e385e1c |
| parent | b0aa77a0267040b6155d75487e8ecc7be7790bf9 |
Add a dist component for libgccjit
Companion to https://github.com/rust-lang/rust/pull/150538.
try-job: dist-x86_64-linux5 files changed, 117 insertions(+), 13 deletions(-)
src/bootstrap/src/core/build_steps/compile.rs+19-10| ... | ... | @@ -1630,26 +1630,35 @@ impl GccDylibSet { |
| 1630 | 1630 | "Trying to install libgccjit ({target_pair}) to a compiler with a different host ({})", |
| 1631 | 1631 | compiler.host |
| 1632 | 1632 | ); |
| 1633 | let libgccjit = libgccjit.libgccjit(); | |
| 1634 | let target_filename = libgccjit.file_name().unwrap().to_str().unwrap(); | |
| 1633 | let libgccjit_path = libgccjit.libgccjit(); | |
| 1635 | 1634 | |
| 1636 | 1635 | // If we build libgccjit ourselves, then `libgccjit` can actually be a symlink. |
| 1637 | 1636 | // In that case, we have to resolve it first, otherwise we'd create a symlink to a |
| 1638 | 1637 | // symlink, which wouldn't work. |
| 1639 | let actual_libgccjit_path = t!( | |
| 1640 | libgccjit.canonicalize(), | |
| 1641 | format!("Cannot find libgccjit at {}", libgccjit.display()) | |
| 1638 | let libgccjit_path = t!( | |
| 1639 | libgccjit_path.canonicalize(), | |
| 1640 | format!("Cannot find libgccjit at {}", libgccjit_path.display()) | |
| 1642 | 1641 | ); |
| 1643 | 1642 | |
| 1644 | // <cg-sysroot>/lib/<target>/libgccjit.so | |
| 1645 | let dest_dir = cg_sysroot.join("lib").join(target_pair.target()); | |
| 1646 | t!(fs::create_dir_all(&dest_dir)); | |
| 1647 | let dst = dest_dir.join(target_filename); | |
| 1648 | builder.copy_link(&actual_libgccjit_path, &dst, FileType::NativeLibrary); | |
| 1643 | let dst = cg_sysroot.join(libgccjit_path_relative_to_cg_dir(target_pair, libgccjit)); | |
| 1644 | t!(std::fs::create_dir_all(dst.parent().unwrap())); | |
| 1645 | builder.copy_link(&libgccjit_path, &dst, FileType::NativeLibrary); | |
| 1649 | 1646 | } |
| 1650 | 1647 | } |
| 1651 | 1648 | } |
| 1652 | 1649 | |
| 1650 | /// Returns a path where libgccjit.so should be stored, **relative** to the | |
| 1651 | /// **codegen backend directory**. | |
| 1652 | pub fn libgccjit_path_relative_to_cg_dir( | |
| 1653 | target_pair: &GccTargetPair, | |
| 1654 | libgccjit: &GccOutput, | |
| 1655 | ) -> PathBuf { | |
| 1656 | let target_filename = libgccjit.libgccjit().file_name().unwrap().to_str().unwrap(); | |
| 1657 | ||
| 1658 | // <cg-dir>/lib/<target>/libgccjit.so | |
| 1659 | Path::new("lib").join(target_pair.target()).join(target_filename) | |
| 1660 | } | |
| 1661 | ||
| 1653 | 1662 | /// Output of the `compile::GccCodegenBackend` step. |
| 1654 | 1663 | /// |
| 1655 | 1664 | /// It contains a build stamp with the path to the built cg_gcc dylib. |
src/bootstrap/src/core/build_steps/dist.rs+83-1| ... | ... | @@ -19,7 +19,9 @@ use object::read::archive::ArchiveFile; |
| 19 | 19 | #[cfg(feature = "tracing")] |
| 20 | 20 | use tracing::instrument; |
| 21 | 21 | |
| 22 | use crate::core::build_steps::compile::{get_codegen_backend_file, normalize_codegen_backend_name}; | |
| 22 | use crate::core::build_steps::compile::{ | |
| 23 | get_codegen_backend_file, libgccjit_path_relative_to_cg_dir, normalize_codegen_backend_name, | |
| 24 | }; | |
| 23 | 25 | use crate::core::build_steps::doc::DocumentationFormat; |
| 24 | 26 | use crate::core::build_steps::gcc::GccTargetPair; |
| 25 | 27 | use crate::core::build_steps::tool::{ |
| ... | ... | @@ -2992,3 +2994,83 @@ impl Step for GccDev { |
| 2992 | 2994 | Some(StepMetadata::dist("gcc-dev", self.target)) |
| 2993 | 2995 | } |
| 2994 | 2996 | } |
| 2997 | ||
| 2998 | /// Tarball containing a libgccjit dylib, | |
| 2999 | /// needed as a dependency for the GCC codegen backend (similarly to the LLVM | |
| 3000 | /// backend needing a prebuilt libLLVM). | |
| 3001 | /// | |
| 3002 | /// This component is used for distribution through rustup. | |
| 3003 | #[derive(Clone, Debug, Eq, Hash, PartialEq)] | |
| 3004 | pub struct Gcc { | |
| 3005 | host: TargetSelection, | |
| 3006 | target: TargetSelection, | |
| 3007 | } | |
| 3008 | ||
| 3009 | impl Step for Gcc { | |
| 3010 | type Output = Option<GeneratedTarball>; | |
| 3011 | ||
| 3012 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { | |
| 3013 | run.alias("gcc") | |
| 3014 | } | |
| 3015 | ||
| 3016 | fn make_run(run: RunConfig<'_>) { | |
| 3017 | // GCC is always built for a target pair, (host, target). | |
| 3018 | // We do not yet support cross-compilation here, so the host target is always inferred to | |
| 3019 | // be the bootstrap host target. | |
| 3020 | run.builder.ensure(Gcc { host: run.builder.host_target, target: run.target }); | |
| 3021 | } | |
| 3022 | ||
| 3023 | fn run(self, builder: &Builder<'_>) -> Self::Output { | |
| 3024 | // This prevents gcc from being built for "dist" | |
| 3025 | // or "install" on the stable/beta channels. It is not yet stable and | |
| 3026 | // should not be included. | |
| 3027 | if !builder.build.unstable_features() { | |
| 3028 | return None; | |
| 3029 | } | |
| 3030 | ||
| 3031 | let host = self.host; | |
| 3032 | let target = self.target; | |
| 3033 | if host != "x86_64-unknown-linux-gnu" { | |
| 3034 | builder.info(&format!("host target `{host}` not supported by gcc. skipping")); | |
| 3035 | return None; | |
| 3036 | } | |
| 3037 | ||
| 3038 | // We need the GCC sources to build GCC and also to add its license and README | |
| 3039 | // files to the tarball | |
| 3040 | builder.require_submodule( | |
| 3041 | "src/gcc", | |
| 3042 | Some("The src/gcc submodule is required for disting libgccjit"), | |
| 3043 | ); | |
| 3044 | ||
| 3045 | let target_pair = GccTargetPair::for_target_pair(host, target); | |
| 3046 | let libgccjit = builder.ensure(super::gcc::Gcc { target_pair }); | |
| 3047 | ||
| 3048 | // We have to include the target name in the component name, so that rustup can somehow | |
| 3049 | // distinguish that there are multiple gcc components on a given host target. | |
| 3050 | // So the tarball includes the target name. | |
| 3051 | let mut tarball = Tarball::new(builder, &format!("gcc-{target}"), &host.triple); | |
| 3052 | tarball.set_overlay(OverlayKind::Gcc); | |
| 3053 | tarball.is_preview(true); | |
| 3054 | tarball.add_legal_and_readme_to("share/doc/gcc"); | |
| 3055 | ||
| 3056 | // The path where to put libgccjit is determined by GccDylibSet. | |
| 3057 | // However, it requires a Compiler to figure out the path to the codegen backend sysroot. | |
| 3058 | // We don't really have any compiler here, because we just build libgccjit. | |
| 3059 | // So we duplicate the logic for determining the CG sysroot here. | |
| 3060 | let cg_dir = PathBuf::from(format!("lib/rustlib/{host}/codegen-backends")); | |
| 3061 | ||
| 3062 | // This returns the path to the actual file, but here we need its parent | |
| 3063 | let rel_libgccjit_path = libgccjit_path_relative_to_cg_dir(&target_pair, &libgccjit); | |
| 3064 | let path = cg_dir.join(rel_libgccjit_path.parent().unwrap()); | |
| 3065 | ||
| 3066 | tarball.add_file(libgccjit.libgccjit(), path, FileType::NativeLibrary); | |
| 3067 | Some(tarball.generate()) | |
| 3068 | } | |
| 3069 | ||
| 3070 | fn metadata(&self) -> Option<StepMetadata> { | |
| 3071 | Some(StepMetadata::dist( | |
| 3072 | "gcc", | |
| 3073 | TargetSelection::from_user(&format!("({}, {})", self.host, self.target)), | |
| 3074 | )) | |
| 3075 | } | |
| 3076 | } |
src/bootstrap/src/core/builder/mod.rs+2-1| ... | ... | @@ -990,7 +990,8 @@ impl<'a> Builder<'a> { |
| 990 | 990 | dist::PlainSourceTarballGpl, |
| 991 | 991 | dist::BuildManifest, |
| 992 | 992 | dist::ReproducibleArtifacts, |
| 993 | dist::GccDev | |
| 993 | dist::GccDev, | |
| 994 | dist::Gcc | |
| 994 | 995 | ), |
| 995 | 996 | Kind::Install => describe!( |
| 996 | 997 | install::Docs, |
src/bootstrap/src/utils/tarball.rs+10| ... | ... | @@ -26,6 +26,7 @@ pub(crate) enum OverlayKind { |
| 26 | 26 | RustAnalyzer, |
| 27 | 27 | RustcCodegenCranelift, |
| 28 | 28 | RustcCodegenGcc, |
| 29 | Gcc, | |
| 29 | 30 | LlvmBitcodeLinker, |
| 30 | 31 | } |
| 31 | 32 | |
| ... | ... | @@ -78,6 +79,14 @@ impl OverlayKind { |
| 78 | 79 | "LICENSE-MIT", |
| 79 | 80 | "src/tools/llvm-bitcode-linker/README.md", |
| 80 | 81 | ], |
| 82 | OverlayKind::Gcc => &[ | |
| 83 | "src/gcc/README", | |
| 84 | "src/gcc/COPYING", | |
| 85 | "src/gcc/COPYING.LIB", | |
| 86 | "src/gcc/COPYING.RUNTIME", | |
| 87 | "src/gcc/COPYING3", | |
| 88 | "src/gcc/COPYING3.LIB", | |
| 89 | ], | |
| 81 | 90 | } |
| 82 | 91 | } |
| 83 | 92 | |
| ... | ... | @@ -101,6 +110,7 @@ impl OverlayKind { |
| 101 | 110 | OverlayKind::RustcCodegenCranelift => builder.rust_version(), |
| 102 | 111 | OverlayKind::RustcCodegenGcc => builder.rust_version(), |
| 103 | 112 | OverlayKind::LlvmBitcodeLinker => builder.rust_version(), |
| 113 | OverlayKind::Gcc => builder.rust_version(), | |
| 104 | 114 | } |
| 105 | 115 | } |
| 106 | 116 | } |
src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh+3-1| ... | ... | @@ -14,5 +14,7 @@ python3 ../x.py build --set rust.debug=true opt-dist |
| 14 | 14 | # Use GCC for building GCC components, as it seems to behave badly when built with Clang |
| 15 | 15 | # Only build GCC on full builds, not try builds |
| 16 | 16 | if [ "${DIST_TRY_BUILD:-0}" == "0" ]; then |
| 17 | CC=/rustroot/bin/cc CXX=/rustroot/bin/c++ python3 ../x.py dist gcc-dev | |
| 17 | CC=/rustroot/bin/cc CXX=/rustroot/bin/c++ python3 ../x.py dist \ | |
| 18 | gcc-dev \ | |
| 19 | gcc | |
| 18 | 20 | fi |