Skip to content

Commit 3e14fc0

Browse files
committed
Migrate LLVM CI change detection to check_path_modifications
1 parent b2bdc02 commit 3e14fc0

File tree

6 files changed

+118
-36
lines changed

6 files changed

+118
-36
lines changed

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

+62-2
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,72 @@ use std::sync::OnceLock;
1414

1515
use build_helper::ci::CiEnv;
1616

17-
use crate::Kind;
18-
use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
1917
use crate::core::builder::{Builder, Cargo, Kind, RunConfig, ShouldRun, Step};
2018
use crate::core::config::TargetSelection;
2119
use crate::utils::build_stamp::{BuildStamp, generate_smart_stamp_hash};
2220
use crate::utils::exec::command;
2321
use crate::utils::helpers::{self, t};
2422

23+
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
24+
pub struct Gcc {
25+
pub target: TargetSelection,
26+
}
27+
28+
#[derive(Clone)]
29+
pub struct GccOutput {
30+
pub libgccjit: PathBuf,
31+
}
32+
33+
impl Step for Gcc {
34+
type Output = GccOutput;
35+
36+
const ONLY_HOSTS: bool = true;
37+
38+
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
39+
run.path("src/gcc").alias("gcc")
40+
}
41+
42+
fn make_run(run: RunConfig<'_>) {
43+
run.builder.ensure(Gcc { target: run.target });
44+
}
45+
46+
/// Compile GCC (specifically `libgccjit`) for `target`.
47+
fn run(self, builder: &Builder<'_>) -> Self::Output {
48+
let target = self.target;
49+
50+
// If GCC has already been built, we avoid building it again.
51+
let metadata = match get_gcc_build_status(builder, target) {
52+
GccBuildStatus::AlreadyBuilt(path) => return GccOutput { libgccjit: path },
53+
GccBuildStatus::ShouldBuild(m) => m,
54+
};
55+
56+
let _guard = builder.msg_unstaged(Kind::Build, "GCC", target);
57+
t!(metadata.stamp.remove());
58+
let _time = helpers::timeit(builder);
59+
60+
let libgccjit_path = libgccjit_built_path(&metadata.install_dir);
61+
if builder.config.dry_run() {
62+
return GccOutput { libgccjit: libgccjit_path };
63+
}
64+
65+
build_gcc(&metadata, builder, target);
66+
create_lib_alias(builder, &libgccjit_path);
67+
68+
t!(metadata.stamp.write());
69+
70+
GccOutput { libgccjit: libgccjit_path }
71+
}
72+
}
73+
74+
/// Creates a libgccjit.so.0 alias next to libgccjit.so if it does not
75+
/// already exist
76+
fn create_lib_alias(builder: &Builder<'_>, libgccjit: &PathBuf) {
77+
let lib_alias = libgccjit.parent().unwrap().join("libgccjit.so.0");
78+
if !lib_alias.exists() {
79+
t!(builder.symlink_file(libgccjit, lib_alias));
80+
}
81+
}
82+
2583
pub struct Meta {
2684
stamp: BuildStamp,
2785
out_dir: PathBuf,
@@ -39,6 +97,8 @@ pub enum GccBuildStatus {
3997
/// Returns a path to the libgccjit.so file.
4098
#[cfg(not(test))]
4199
fn try_download_gcc(builder: &Builder<'_>, target: TargetSelection) -> Option<PathBuf> {
100+
use build_helper::git::PathFreshness;
101+
42102
// Try to download GCC from CI if configured and available
43103
if !matches!(builder.config.gcc_ci_mode, crate::core::config::GccCiMode::DownloadFromCi) {
44104
return None;

src/bootstrap/src/core/build_steps/llvm.rs

+25-25
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ use std::sync::OnceLock;
1515
use std::{env, fs};
1616

1717
use build_helper::ci::CiEnv;
18-
use build_helper::git::get_closest_merge_commit;
18+
use build_helper::git::{PathFreshness, check_path_modifications};
19+
#[cfg(feature = "tracing")]
20+
use tracing::instrument;
1921

2022
use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
2123
use crate::core::config::{Config, TargetSelection};
@@ -172,35 +174,38 @@ pub fn prebuilt_llvm_config(
172174
LlvmBuildStatus::ShouldBuild(Meta { stamp, res, out_dir, root: root.into() })
173175
}
174176

175-
/// This retrieves the LLVM sha we *want* to use, according to git history.
176-
pub(crate) fn detect_llvm_sha(config: &Config, is_git: bool) -> String {
177-
let llvm_sha = if is_git {
178-
get_closest_merge_commit(
179-
Some(&config.src),
180-
&config.git_config(),
181-
&[
182-
config.src.join("src/llvm-project"),
183-
config.src.join("src/bootstrap/download-ci-llvm-stamp"),
184-
// the LLVM shared object file is named `LLVM-12-rust-{version}-nightly`
185-
config.src.join("src/version"),
186-
],
177+
/// Detect whether LLVM sources have been modified locally or not.
178+
pub(crate) fn detect_llvm_freshness(config: &Config, is_git: bool) -> PathFreshness {
179+
let freshness = if is_git {
180+
Some(
181+
check_path_modifications(
182+
Some(&config.src),
183+
&config.git_config(),
184+
&[
185+
"src/llvm-project",
186+
"src/bootstrap/download-ci-llvm-stamp",
187+
// the LLVM shared object file is named `LLVM-12-rust-{version}-nightly`
188+
"src/version",
189+
],
190+
CiEnv::current(),
191+
)
192+
.unwrap(),
187193
)
188-
.unwrap()
189194
} else if let Some(info) = crate::utils::channel::read_commit_info_file(&config.src) {
190-
info.sha.trim().to_owned()
195+
Some(PathFreshness::LastModifiedUpstream { upstream: info.sha.trim().to_owned() })
191196
} else {
192-
"".to_owned()
197+
None
193198
};
194199

195-
if llvm_sha.is_empty() {
200+
let Some(freshness) = freshness else {
196201
eprintln!("error: could not find commit hash for downloading LLVM");
197202
eprintln!("HELP: maybe your repository history is too shallow?");
198203
eprintln!("HELP: consider disabling `download-ci-llvm`");
199204
eprintln!("HELP: or fetch enough history to include one upstream commit");
200205
panic!();
201-
}
206+
};
202207

203-
llvm_sha
208+
freshness
204209
}
205210

206211
/// Returns whether the CI-found LLVM is currently usable.
@@ -280,12 +285,7 @@ pub(crate) fn is_ci_llvm_modified(config: &Config) -> bool {
280285
return false;
281286
}
282287

283-
let llvm_sha = detect_llvm_sha(config, true);
284-
let head_sha = crate::output(
285-
helpers::git(Some(&config.src)).arg("rev-parse").arg("HEAD").as_command_mut(),
286-
);
287-
let head_sha = head_sha.trim();
288-
llvm_sha == head_sha
288+
matches!(detect_llvm_freshness(config, true), PathFreshness::HasLocalModifications { .. })
289289
}
290290

291291
#[derive(Debug, Clone, Hash, PartialEq, Eq)]

src/bootstrap/src/core/config/config.rs

+15-4
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ use std::{cmp, env, fs};
1515

1616
use build_helper::ci::CiEnv;
1717
use build_helper::exit;
18-
use build_helper::git::{GitConfig, get_closest_merge_commit, output_result};
18+
use build_helper::git::{
19+
GitConfig, PathFreshness, check_path_modifications, get_closest_merge_commit, output_result,
20+
};
1921
use serde::{Deserialize, Deserializer};
2022
use serde_derive::Deserialize;
2123
#[cfg(feature = "tracing")]
@@ -3008,9 +3010,7 @@ impl Config {
30083010
self.update_submodule("src/llvm-project");
30093011

30103012
// Check for untracked changes in `src/llvm-project`.
3011-
let has_changes = self
3012-
.last_modified_commit(&["src/llvm-project"], "download-ci-llvm", true)
3013-
.is_none();
3013+
let has_changes = self.has_changes_from_upstream(&["src/llvm-project"]);
30143014

30153015
// Return false if there are untracked changes, otherwise check if CI LLVM is available.
30163016
if has_changes { false } else { llvm::is_ci_llvm_available(self, asserts) }
@@ -3034,6 +3034,17 @@ impl Config {
30343034
}
30353035
}
30363036

3037+
/// Returns true if any of the `paths` have been modified locally.
3038+
fn has_changes_from_upstream(&self, paths: &[&str]) -> bool {
3039+
let freshness =
3040+
check_path_modifications(Some(&self.src), &self.git_config(), paths, CiEnv::current())
3041+
.unwrap();
3042+
match freshness {
3043+
PathFreshness::LastModifiedUpstream { .. } => false,
3044+
PathFreshness::HasLocalModifications { .. } => true,
3045+
}
3046+
}
3047+
30373048
/// Returns the last commit in which any of `modified_paths` were changed,
30383049
/// or `None` if there are untracked changes in the working directory and `if_unchanged` is true.
30393050
pub fn last_modified_commit(

src/bootstrap/src/core/download.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -721,16 +721,21 @@ download-rustc = false
721721
#[cfg(not(test))]
722722
pub(crate) fn maybe_download_ci_llvm(&self) {
723723
use build_helper::exit;
724+
use build_helper::git::PathFreshness;
724725

725-
use crate::core::build_steps::llvm::detect_llvm_sha;
726+
use crate::core::build_steps::llvm::detect_llvm_freshness;
726727
use crate::core::config::check_incompatible_options_for_ci_llvm;
727728

728729
if !self.llvm_from_ci {
729730
return;
730731
}
731732

732733
let llvm_root = self.ci_llvm_root();
733-
let llvm_sha = detect_llvm_sha(self, self.rust_info.is_managed_git_subrepository());
734+
let llvm_sha =
735+
match detect_llvm_freshness(self, self.rust_info.is_managed_git_subrepository()) {
736+
PathFreshness::LastModifiedUpstream { upstream } => upstream,
737+
PathFreshness::HasLocalModifications { upstream } => upstream,
738+
};
734739
let stamp_key = format!("{}{}", llvm_sha, self.llvm_assertions);
735740
let llvm_stamp = BuildStamp::new(&llvm_root).with_prefix("llvm").add_stamp(stamp_key);
736741
if !llvm_stamp.is_up_to_date() && !self.dry_run() {

src/build_helper/src/git.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,11 @@ pub fn check_path_modifications(
253253
upstream_sha
254254
};
255255

256+
// For local environments, we want to find out if something has changed
257+
// from the latest upstream commit.
258+
// However, that should be equivalent to checking if something has changed
259+
// from the latest upstream commit *that modified `target_paths`*, and
260+
// with this approach we do not need to invoke git an additional time.
256261
if has_changed_since(git_dir, &upstream_sha, target_paths) {
257262
Ok(PathFreshness::HasLocalModifications { upstream: upstream_sha })
258263
} else {
@@ -261,7 +266,7 @@ pub fn check_path_modifications(
261266
}
262267

263268
/// Returns true if any of the passed `paths` have changed since the `base` commit.
264-
pub fn has_changed_since(git_dir: Option<&Path>, base: &str, paths: &[&Path]) -> bool {
269+
fn has_changed_since(git_dir: Option<&Path>, base: &str, paths: &[&str]) -> bool {
265270
let mut git = Command::new("git");
266271

267272
if let Some(git_dir) = git_dir {

src/build_helper/src/git/tests.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
use crate::ci::CiEnv;
2-
use crate::git::{GitConfig, PathFreshness, check_path_modifications};
31
use std::ffi::OsStr;
42
use std::fs::OpenOptions;
53
use std::process::Command;
64

5+
use crate::ci::CiEnv;
6+
use crate::git::{GitConfig, PathFreshness, check_path_modifications};
7+
78
#[test]
89
fn test_pr_ci_unchanged_anywhere() {
910
git_test(|ctx| {

0 commit comments

Comments
 (0)