From 70d4545ebdf96e76e7f74f6b3688c124af3677a6 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sat, 8 Nov 2025 11:36:01 -0500 Subject: [PATCH 1/7] Add libgccjit-libs-dir config --- src/bootstrap/src/core/build_steps/gcc.rs | 31 ++++++++++++++++++++++- src/bootstrap/src/core/config/config.rs | 4 ++- src/bootstrap/src/core/config/toml/gcc.rs | 1 + 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs index def794c98a41d..4337104b778ab 100644 --- a/src/bootstrap/src/core/build_steps/gcc.rs +++ b/src/bootstrap/src/core/build_steps/gcc.rs @@ -46,8 +46,37 @@ impl GccOutput { format!("Cannot find libgccjit at {}", self.libgccjit.display()) ); - let dst = directory.join(target_filename); + let dst = directory.join(&target_filename); builder.copy_link(&actual_libgccjit_path, &dst, FileType::NativeLibrary); + + if let Some(ref path) = builder.config.libgccjit_libs_dir { + let host_target = builder.config.host_target.triple; + + let source = path.join(host_target); + let dst = directory; + + let targets = builder.config.targets.iter() + .map(|target| target.triple) + .chain(std::iter::once(host_target)); + + for target in targets { + let source = source.join(target).join(&target_filename); + // To support symlinks in libgccjit-libs-dir, we have to resolve it first, + // otherwise we'd create a symlink to a symlink, which wouldn't work. + let actual_libgccjit_path = t!( + source.canonicalize(), + format!("Cannot find libgccjit at {}", self.libgccjit.display()) + ); + let target_dir = dst.join(target); + t!( + std::fs::create_dir_all(&target_dir), + format!("Cannot create target dir {} for libgccjit", target_dir.display()) + ); + let dst = target_dir.join(&target_filename); + builder.copy_link(&actual_libgccjit_path, &dst, FileType::NativeLibrary); + } + } + } } diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 2f493658ec0ec..a237639b931d6 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -188,6 +188,7 @@ pub struct Config { // gcc codegen options pub gcc_ci_mode: GccCiMode, + pub libgccjit_libs_dir: Option, // rust codegen options pub rust_optimize: RustOptimize, @@ -620,7 +621,7 @@ impl Config { vendor: dist_vendor, } = toml.dist.unwrap_or_default(); - let Gcc { download_ci_gcc: gcc_download_ci_gcc } = toml.gcc.unwrap_or_default(); + let Gcc { download_ci_gcc: gcc_download_ci_gcc, libgccjit_libs_dir } = toml.gcc.unwrap_or_default(); if rust_bootstrap_override_lld.is_some() && rust_bootstrap_override_lld_legacy.is_some() { panic!( @@ -1327,6 +1328,7 @@ impl Config { free_args: flags_free_args, full_bootstrap: build_full_bootstrap.unwrap_or(false), gcc_ci_mode, + libgccjit_libs_dir, gdb: build_gdb.map(PathBuf::from), host_target, hosts, diff --git a/src/bootstrap/src/core/config/toml/gcc.rs b/src/bootstrap/src/core/config/toml/gcc.rs index 9ea697edf159e..94d15a9baaff9 100644 --- a/src/bootstrap/src/core/config/toml/gcc.rs +++ b/src/bootstrap/src/core/config/toml/gcc.rs @@ -15,5 +15,6 @@ define_config! { #[derive(Default)] struct Gcc { download_ci_gcc: Option = "download-ci-gcc", + libgccjit_libs_dir: Option = "libgccjit-libs-dir", } } From 389cb6f58bbb515400195174c36673d3c84a9a61 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sat, 8 Nov 2025 16:32:02 -0500 Subject: [PATCH 2/7] Do not build or download libgccjit if using libgccjit-libs-dir --- src/bootstrap/src/core/build_steps/dist.rs | 4 +- src/bootstrap/src/core/build_steps/gcc.rs | 50 ++++++++++++++-------- src/bootstrap/src/core/build_steps/test.rs | 8 +++- src/bootstrap/src/core/config/config.rs | 7 +-- src/bootstrap/src/core/config/mod.rs | 1 + 5 files changed, 47 insertions(+), 23 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 0efe0cbbc80f0..a6e9362d40692 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -2857,7 +2857,9 @@ impl Step for Gcc { fn run(self, builder: &Builder<'_>) -> Self::Output { let tarball = Tarball::new(builder, "gcc", &self.target.triple); let output = builder.ensure(super::gcc::Gcc { target: self.target }); - tarball.add_file(&output.libgccjit, "lib", FileType::NativeLibrary); + if let Some(ref path) = output.libgccjit { + tarball.add_file(path, "lib", FileType::NativeLibrary); + } tarball.generate() } diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs index 4337104b778ab..c9e047ff58570 100644 --- a/src/bootstrap/src/core/build_steps/gcc.rs +++ b/src/bootstrap/src/core/build_steps/gcc.rs @@ -26,7 +26,11 @@ pub struct Gcc { #[derive(Clone)] pub struct GccOutput { - pub libgccjit: PathBuf, + /// Path to a built or downloaded libgccjit. + /// Is None when setting libgccjit-libs-dir. + /// FIXME: it seems wrong to make this an Option. + /// Perhaps it should be a Vec so that we can install all libs from libgccjit-libs-dir? + pub libgccjit: Option, } impl GccOutput { @@ -36,18 +40,20 @@ impl GccOutput { return; } - let target_filename = self.libgccjit.file_name().unwrap().to_str().unwrap().to_string(); + if let Some(ref path) = self.libgccjit { + let mut target_filename = path.file_name().unwrap().to_str().unwrap().to_string(); - // If we build libgccjit ourselves, then `self.libgccjit` can actually be a symlink. - // In that case, we have to resolve it first, otherwise we'd create a symlink to a symlink, - // which wouldn't work. - let actual_libgccjit_path = t!( - self.libgccjit.canonicalize(), - format!("Cannot find libgccjit at {}", self.libgccjit.display()) - ); + // If we build libgccjit ourselves, then `self.libgccjit` can actually be a symlink. + // In that case, we have to resolve it first, otherwise we'd create a symlink to a symlink, + // which wouldn't work. + let actual_libgccjit_path = t!( + path.canonicalize(), + format!("Cannot find libgccjit at {}", path.display()) + ); - let dst = directory.join(&target_filename); - builder.copy_link(&actual_libgccjit_path, &dst, FileType::NativeLibrary); + let dst = directory.join(&target_filename); + builder.copy_link(&actual_libgccjit_path, &dst, FileType::NativeLibrary); + } if let Some(ref path) = builder.config.libgccjit_libs_dir { let host_target = builder.config.host_target.triple; @@ -59,13 +65,14 @@ impl GccOutput { .map(|target| target.triple) .chain(std::iter::once(host_target)); + let target_filename = "libgccjit.so.0"; for target in targets { - let source = source.join(target).join(&target_filename); + let source = source.join(target).join(target_filename); // To support symlinks in libgccjit-libs-dir, we have to resolve it first, // otherwise we'd create a symlink to a symlink, which wouldn't work. let actual_libgccjit_path = t!( source.canonicalize(), - format!("Cannot find libgccjit at {}", self.libgccjit.display()) + format!("Cannot find libgccjit at {}", source.display()) ); let target_dir = dst.join(target); t!( @@ -99,7 +106,8 @@ impl Step for Gcc { // If GCC has already been built, we avoid building it again. let metadata = match get_gcc_build_status(builder, target) { - GccBuildStatus::AlreadyBuilt(path) => return GccOutput { libgccjit: path }, + GccBuildStatus::AlreadyBuilt(path) => return GccOutput { libgccjit: Some(path) }, + GccBuildStatus::InLibsDir => return GccOutput { libgccjit: None }, GccBuildStatus::ShouldBuild(m) => m, }; @@ -109,14 +117,14 @@ impl Step for Gcc { let libgccjit_path = libgccjit_built_path(&metadata.install_dir); if builder.config.dry_run() { - return GccOutput { libgccjit: libgccjit_path }; + return GccOutput { libgccjit: Some(libgccjit_path) }; } build_gcc(&metadata, builder, target); t!(metadata.stamp.write()); - GccOutput { libgccjit: libgccjit_path } + GccOutput { libgccjit: Some(libgccjit_path) } } } @@ -130,6 +138,7 @@ pub struct Meta { pub enum GccBuildStatus { /// libgccjit is already built at this path AlreadyBuilt(PathBuf), + InLibsDir, ShouldBuild(Meta), } @@ -194,6 +203,11 @@ fn try_download_gcc(_builder: &Builder<'_>, _target: TargetSelection) -> Option< /// It's used to avoid busting caches during x.py check -- if we've already built /// GCC, it's fine for us to not try to avoid doing so. pub fn get_gcc_build_status(builder: &Builder<'_>, target: TargetSelection) -> GccBuildStatus { + if matches!(builder.config.gcc_ci_mode, crate::core::config::GccCiMode::CopyFromLibsDir) { + // TODO: check if this is OK. + return GccBuildStatus::InLibsDir; + } + if let Some(path) = try_download_gcc(builder, target) { return GccBuildStatus::AlreadyBuilt(path); } @@ -317,7 +331,9 @@ fn build_gcc(metadata: &Meta, builder: &Builder<'_>, target: TargetSelection) { /// Configures a Cargo invocation so that it can build the GCC codegen backend. pub fn add_cg_gcc_cargo_flags(cargo: &mut Cargo, gcc: &GccOutput) { // Add the path to libgccjit.so to the linker search paths. - cargo.rustflag(&format!("-L{}", gcc.libgccjit.parent().unwrap().to_str().unwrap())); + if let Some(ref path) = gcc.libgccjit { + cargo.rustflag(&format!("-L{}", path.parent().unwrap().to_str().unwrap())); + } } /// The absolute path to the downloaded GCC artifacts. diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index d888e63275cda..8a050d1adc604 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -3938,13 +3938,17 @@ impl Step for CodegenGCC { .arg("test") .arg("--use-backend") .arg("gcc") - .arg("--gcc-path") - .arg(gcc.libgccjit.parent().unwrap()) .arg("--out-dir") .arg(builder.stage_out(compilers.build_compiler(), Mode::Codegen).join("cg_gcc")) .arg("--release") .arg("--mini-tests") .arg("--std-tests"); + + if let Some(ref path) = gcc.libgccjit { + cargo + .arg("--gcc-path") + .arg(path.parent().unwrap()); + } cargo.args(builder.config.test_args()); cargo.into_cmd().run(builder); diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index a237639b931d6..12678c6a3ff6e 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1219,12 +1219,13 @@ impl Config { Warnings::Default => rust_deny_warnings.unwrap_or(true), }; - let gcc_ci_mode = match gcc_download_ci_gcc { - Some(value) => match value { + let gcc_ci_mode = match (&libgccjit_libs_dir, gcc_download_ci_gcc) { + (Some(_), _) => GccCiMode::CopyFromLibsDir, + (None, Some(value)) => match value { true => GccCiMode::DownloadFromCi, false => GccCiMode::BuildLocally, }, - None => GccCiMode::default(), + (None, None) => GccCiMode::default(), }; let targets = flags_target diff --git a/src/bootstrap/src/core/config/mod.rs b/src/bootstrap/src/core/config/mod.rs index 007ed4aaba13f..bbc273ec27178 100644 --- a/src/bootstrap/src/core/config/mod.rs +++ b/src/bootstrap/src/core/config/mod.rs @@ -433,6 +433,7 @@ pub enum GccCiMode { /// If it is not available on CI, it will be built locally instead. #[default] DownloadFromCi, + CopyFromLibsDir, } pub fn threads_from_config(v: u32) -> u32 { From 4209f9599d140aa2863299a00d4b064ff24f304d Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Wed, 26 Nov 2025 09:05:52 -0500 Subject: [PATCH 3/7] Formatting --- src/bootstrap/src/core/build_steps/gcc.rs | 12 ++++++------ src/bootstrap/src/core/build_steps/test.rs | 4 +--- src/bootstrap/src/core/config/config.rs | 3 ++- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs index c9e047ff58570..ae361ec11071d 100644 --- a/src/bootstrap/src/core/build_steps/gcc.rs +++ b/src/bootstrap/src/core/build_steps/gcc.rs @@ -46,10 +46,8 @@ impl GccOutput { // If we build libgccjit ourselves, then `self.libgccjit` can actually be a symlink. // In that case, we have to resolve it first, otherwise we'd create a symlink to a symlink, // which wouldn't work. - let actual_libgccjit_path = t!( - path.canonicalize(), - format!("Cannot find libgccjit at {}", path.display()) - ); + let actual_libgccjit_path = + t!(path.canonicalize(), format!("Cannot find libgccjit at {}", path.display())); let dst = directory.join(&target_filename); builder.copy_link(&actual_libgccjit_path, &dst, FileType::NativeLibrary); @@ -61,7 +59,10 @@ impl GccOutput { let source = path.join(host_target); let dst = directory; - let targets = builder.config.targets.iter() + let targets = builder + .config + .targets + .iter() .map(|target| target.triple) .chain(std::iter::once(host_target)); @@ -83,7 +84,6 @@ impl GccOutput { builder.copy_link(&actual_libgccjit_path, &dst, FileType::NativeLibrary); } } - } } diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 8a050d1adc604..5c57bc39e5ccf 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -3945,9 +3945,7 @@ impl Step for CodegenGCC { .arg("--std-tests"); if let Some(ref path) = gcc.libgccjit { - cargo - .arg("--gcc-path") - .arg(path.parent().unwrap()); + cargo.arg("--gcc-path").arg(path.parent().unwrap()); } cargo.args(builder.config.test_args()); diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 12678c6a3ff6e..73141433e7662 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -621,7 +621,8 @@ impl Config { vendor: dist_vendor, } = toml.dist.unwrap_or_default(); - let Gcc { download_ci_gcc: gcc_download_ci_gcc, libgccjit_libs_dir } = toml.gcc.unwrap_or_default(); + let Gcc { download_ci_gcc: gcc_download_ci_gcc, libgccjit_libs_dir } = + toml.gcc.unwrap_or_default(); if rust_bootstrap_override_lld.is_some() && rust_bootstrap_override_lld_legacy.is_some() { panic!( From df050f6c1a4b289b18559f47c95cf0f91aab0cd2 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Wed, 26 Nov 2025 09:19:07 -0500 Subject: [PATCH 4/7] Fix tidy --- src/bootstrap/src/core/build_steps/gcc.rs | 2 +- src/bootstrap/src/core/config/config.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs index ae361ec11071d..fb46daf62fa97 100644 --- a/src/bootstrap/src/core/build_steps/gcc.rs +++ b/src/bootstrap/src/core/build_steps/gcc.rs @@ -204,7 +204,7 @@ fn try_download_gcc(_builder: &Builder<'_>, _target: TargetSelection) -> Option< /// GCC, it's fine for us to not try to avoid doing so. pub fn get_gcc_build_status(builder: &Builder<'_>, target: TargetSelection) -> GccBuildStatus { if matches!(builder.config.gcc_ci_mode, crate::core::config::GccCiMode::CopyFromLibsDir) { - // TODO: check if this is OK. + // FIXME: check if this is OK. return GccBuildStatus::InLibsDir; } diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 73141433e7662..b6c0e930f01be 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1330,7 +1330,6 @@ impl Config { free_args: flags_free_args, full_bootstrap: build_full_bootstrap.unwrap_or(false), gcc_ci_mode, - libgccjit_libs_dir, gdb: build_gdb.map(PathBuf::from), host_target, hosts, @@ -1350,6 +1349,7 @@ impl Config { keep_stage: flags_keep_stage, keep_stage_std: flags_keep_stage_std, libdir: install_libdir.map(PathBuf::from), + libgccjit_libs_dir, library_docs_private_items: build_library_docs_private_items.unwrap_or(false), lld_enabled, lldb: build_lldb.map(PathBuf::from), From 3ed2b1b95fdd9b28ed9238a58fe81ab65b6c0087 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Wed, 26 Nov 2025 09:51:05 -0500 Subject: [PATCH 5/7] Add new config in example --- bootstrap.example.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/bootstrap.example.toml b/bootstrap.example.toml index 4e850810a30a9..9d784e5f288d9 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -190,6 +190,7 @@ # modifications to the `src/gcc` submodule. # Currently, this is only supported for the `x86_64-unknown-linux-gnu` target. #gcc.download-ci-gcc = false +#libgccjit-libs-dir = "/path/to/libgccjit-libs-dir" # ============================================================================= # General build configuration options From 2125647670a7922a39c3e557660ec57fb91bcfe5 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Wed, 26 Nov 2025 09:51:12 -0500 Subject: [PATCH 6/7] Fix clippy warning --- src/bootstrap/src/core/build_steps/gcc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs index fb46daf62fa97..e7350edee733d 100644 --- a/src/bootstrap/src/core/build_steps/gcc.rs +++ b/src/bootstrap/src/core/build_steps/gcc.rs @@ -80,7 +80,7 @@ impl GccOutput { std::fs::create_dir_all(&target_dir), format!("Cannot create target dir {} for libgccjit", target_dir.display()) ); - let dst = target_dir.join(&target_filename); + let dst = target_dir.join(target_filename); builder.copy_link(&actual_libgccjit_path, &dst, FileType::NativeLibrary); } } From 33683811c667a7eeb8de5dc2bfb9cbe58fee5ce5 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Fri, 28 Nov 2025 11:43:09 -0500 Subject: [PATCH 7/7] Remove mut --- src/bootstrap/src/core/build_steps/gcc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs index e7350edee733d..6e490adf65b10 100644 --- a/src/bootstrap/src/core/build_steps/gcc.rs +++ b/src/bootstrap/src/core/build_steps/gcc.rs @@ -41,7 +41,7 @@ impl GccOutput { } if let Some(ref path) = self.libgccjit { - let mut target_filename = path.file_name().unwrap().to_str().unwrap().to_string(); + let target_filename = path.file_name().unwrap().to_str().unwrap().to_string(); // If we build libgccjit ourselves, then `self.libgccjit` can actually be a symlink. // In that case, we have to resolve it first, otherwise we'd create a symlink to a symlink,