Skip to content

Commit 484a825

Browse files
committed
Implement downloading GCC from CI
1 parent c033956 commit 484a825

File tree

2 files changed

+93
-10
lines changed

2 files changed

+93
-10
lines changed

src/bootstrap/src/core/build_steps/gcc.rs

+65-10
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ use std::path::{Path, PathBuf};
1313
use std::sync::OnceLock;
1414

1515
use build_helper::ci::CiEnv;
16+
use build_helper::git::get_closest_merge_commit;
1617

1718
use crate::Config;
1819
use crate::core::builder::{Builder, Cargo, Kind, RunConfig, ShouldRun, Step};
19-
use crate::core::config::TargetSelection;
20+
use crate::core::config::{GccCiMode, TargetSelection};
2021
use crate::utils::build_stamp::{BuildStamp, generate_smart_stamp_hash};
2122
use crate::utils::exec::command;
2223
use crate::utils::helpers::{self, t};
@@ -89,18 +90,12 @@ pub enum GccBuildStatus {
8990
ShouldBuild(Meta),
9091
}
9192

92-
/// This returns whether we've already previously built GCC.
93+
/// This returns information about whether GCC should be built or if it's already built.
94+
/// It transparently handles downloading GCC from CI if needed.
9395
///
9496
/// It's used to avoid busting caches during x.py check -- if we've already built
9597
/// GCC, it's fine for us to not try to avoid doing so.
9698
pub fn get_gcc_build_status(builder: &Builder<'_>, target: TargetSelection) -> GccBuildStatus {
97-
// Initialize the gcc submodule if not initialized already.
98-
builder.config.update_submodule("src/gcc");
99-
100-
let root = builder.src.join("src/gcc");
101-
let out_dir = builder.gcc_out(target).join("build");
102-
let install_dir = builder.gcc_out(target).join("install");
103-
10499
static STAMP_HASH_MEMO: OnceLock<String> = OnceLock::new();
105100
let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| {
106101
generate_smart_stamp_hash(
@@ -110,6 +105,35 @@ pub fn get_gcc_build_status(builder: &Builder<'_>, target: TargetSelection) -> G
110105
)
111106
});
112107

108+
// Try to download GCC from CI if configured and available
109+
if let GccCiMode::DownloadFromCi = &builder.config.gcc_ci_mode {
110+
if builder.build.build == "x86_64-unknown-linux-gnu" {
111+
let sha = detect_gcc_sha(
112+
&builder.config,
113+
builder.config.rust_info.is_managed_git_subrepository(),
114+
);
115+
let root = ci_gcc_root(&builder.config);
116+
let gcc_stamp = BuildStamp::new(&root).with_prefix("gcc").add_stamp(&sha);
117+
if !gcc_stamp.is_up_to_date() && !builder.config.dry_run() {
118+
builder.config.download_ci_gcc(&sha, &root);
119+
t!(gcc_stamp.write());
120+
}
121+
// FIXME: put libgccjit.so into a lib directory in dist::Gcc
122+
return GccBuildStatus::AlreadyBuilt(root.join("libgccjit.so"));
123+
} else {
124+
eprintln!(
125+
"GCC CI download is only available for the `x86_64-unknown-linux-gnu` target"
126+
);
127+
}
128+
}
129+
130+
// Initialize the gcc submodule if not initialized already.
131+
builder.config.update_submodule("src/gcc");
132+
133+
let root = builder.src.join("src/gcc");
134+
let out_dir = builder.gcc_out(target).join("build");
135+
let install_dir = builder.gcc_out(target).join("install");
136+
113137
let stamp = BuildStamp::new(&out_dir).with_prefix("gcc").add_stamp(smart_stamp_hash);
114138

115139
if stamp.is_up_to_date() {
@@ -142,7 +166,7 @@ fn libgccjit_built_path(install_dir: &Path) -> PathBuf {
142166
install_dir.join("lib/libgccjit.so")
143167
}
144168

145-
fn build_gcc(metadata: &Meta, builder: &Builder, target: TargetSelection) {
169+
fn build_gcc(metadata: &Meta, builder: &Builder<'_>, target: TargetSelection) {
146170
let Meta { stamp: _, out_dir, install_dir, root } = metadata;
147171

148172
t!(fs::create_dir_all(out_dir));
@@ -210,3 +234,34 @@ pub fn add_cg_gcc_cargo_flags(cargo: &mut Cargo, gcc: &GccOutput) {
210234
// Add the path to libgccjit.so to the linker search paths.
211235
cargo.rustflag(&format!("-L{}", gcc.libgccjit.parent().unwrap().to_str().unwrap()));
212236
}
237+
238+
/// The absolute path to the downloaded GCC artifacts.
239+
fn ci_gcc_root(config: &Config) -> PathBuf {
240+
config.out.join(config.build).join("ci-gcc")
241+
}
242+
243+
/// This retrieves the GCC sha we *want* to use, according to git history.
244+
fn detect_gcc_sha(config: &Config, is_git: bool) -> String {
245+
let gcc_sha = if is_git {
246+
get_closest_merge_commit(
247+
Some(&config.src),
248+
&config.git_config(),
249+
&[config.src.join("src/gcc"), config.src.join("src/bootstrap/download-ci-gcc-stamp")],
250+
)
251+
.unwrap()
252+
} else if let Some(info) = crate::utils::channel::read_commit_info_file(&config.src) {
253+
info.sha.trim().to_owned()
254+
} else {
255+
"".to_owned()
256+
};
257+
258+
if gcc_sha.is_empty() {
259+
eprintln!("error: could not find commit hash for downloading GCC");
260+
eprintln!("HELP: maybe your repository history is too shallow?");
261+
eprintln!("HELP: consider disabling `download-ci-gcc`");
262+
eprintln!("HELP: or fetch enough history to include one upstream commit");
263+
panic!();
264+
}
265+
266+
gcc_sha
267+
}

src/bootstrap/src/core/download.rs

+28
Original file line numberDiff line numberDiff line change
@@ -826,6 +826,34 @@ download-rustc = false
826826
let llvm_root = self.ci_llvm_root();
827827
self.unpack(&tarball, &llvm_root, "rust-dev");
828828
}
829+
830+
pub fn download_ci_gcc(&self, gcc_sha: &str, root_dir: &Path) {
831+
let cache_prefix = format!("gcc-{gcc_sha}");
832+
let cache_dst =
833+
self.bootstrap_cache_path.as_ref().cloned().unwrap_or_else(|| self.out.join("cache"));
834+
835+
let gcc_cache = cache_dst.join(cache_prefix);
836+
if !gcc_cache.exists() {
837+
t!(fs::create_dir_all(&gcc_cache));
838+
}
839+
let base = &self.stage0_metadata.config.artifacts_server;
840+
let filename = format!("gcc-nightly-{}.tar.xz", self.build.triple);
841+
let tarball = gcc_cache.join(&filename);
842+
if !tarball.exists() {
843+
let help_on_error = "ERROR: failed to download gcc from ci
844+
845+
HELP: There could be two reasons behind this:
846+
1) The host triple is not supported for `download-ci-gcc`.
847+
2) Old builds get deleted after a certain time.
848+
HELP: In either case, disable `download-ci-gcc` in your config.toml:
849+
850+
[gcc]
851+
download-ci-gcc = false
852+
";
853+
self.download_file(&format!("{base}/{gcc_sha}/{filename}"), &tarball, help_on_error);
854+
}
855+
self.unpack(&tarball, root_dir, "gcc");
856+
}
829857
}
830858

831859
fn path_is_dylib(path: &Path) -> bool {

0 commit comments

Comments
 (0)