Skip to content

Commit e7d4f10

Browse files
committed
Migrate LLVM CI change detection to check_path_modifications
1 parent 4527723 commit e7d4f10

File tree

6 files changed

+102
-94
lines changed

6 files changed

+102
-94
lines changed

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

+4-1
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@ use std::fs;
1212
use std::path::{Path, PathBuf};
1313
use std::sync::OnceLock;
1414

15+
use build_helper::ci::CiEnv;
16+
1517
use crate::core::builder::{Builder, Cargo, Kind, RunConfig, ShouldRun, Step};
1618
use crate::core::config::TargetSelection;
1719
use crate::utils::build_stamp::{BuildStamp, generate_smart_stamp_hash};
1820
use crate::utils::exec::command;
1921
use crate::utils::helpers::{self, t};
20-
use build_helper::ci::CiEnv;
2122

2223
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
2324
pub struct Gcc {
@@ -97,6 +98,8 @@ pub enum GccBuildStatus {
9798
/// Returns a path to the libgccjit.so file.
9899
#[cfg(not(test))]
99100
fn try_download_gcc(builder: &Builder<'_>, target: TargetSelection) -> Option<PathBuf> {
101+
use build_helper::git::PathFreshness;
102+
100103
// Try to download GCC from CI if configured and available
101104
if !matches!(builder.config.gcc_ci_mode, crate::core::config::GccCiMode::DownloadFromCi) {
102105
return None;

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

+67-84
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};
@@ -24,7 +26,7 @@ use crate::utils::exec::command;
2426
use crate::utils::helpers::{
2527
self, exe, get_clang_cl_resource_dir, t, unhashed_basename, up_to_date,
2628
};
27-
use crate::{CLang, GitRepo, Kind};
29+
use crate::{CLang, GitRepo, Kind, trace};
2830

2931
#[derive(Clone)]
3032
pub struct LlvmResult {
@@ -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)]
@@ -469,6 +469,10 @@ impl Step for Llvm {
469469
cfg.define("LLVM_BUILD_32_BITS", "ON");
470470
}
471471

472+
if target.starts_with("x86_64") && target.contains("ohos") {
473+
cfg.define("LLVM_TOOL_LLVM_RTDYLD_BUILD", "OFF");
474+
}
475+
472476
let mut enabled_llvm_projects = Vec::new();
473477

474478
if helpers::forcing_clang_based_tests() {
@@ -516,7 +520,7 @@ impl Step for Llvm {
516520
}
517521

518522
// https://llvm.org/docs/HowToCrossCompileLLVM.html
519-
if !builder.is_builder_target(&target) {
523+
if !builder.is_builder_target(target) {
520524
let LlvmResult { llvm_config, .. } =
521525
builder.ensure(Llvm { target: builder.config.build });
522526
if !builder.config.dry_run() {
@@ -668,7 +672,7 @@ fn configure_cmake(
668672
}
669673
cfg.target(&target.triple).host(&builder.config.build.triple);
670674

671-
if !builder.is_builder_target(&target) {
675+
if !builder.is_builder_target(target) {
672676
cfg.define("CMAKE_CROSSCOMPILING", "True");
673677

674678
if target.contains("netbsd") {
@@ -733,57 +737,17 @@ fn configure_cmake(
733737
None => (builder.cc(target), builder.cxx(target).unwrap()),
734738
};
735739

736-
// Handle msvc + ninja + ccache specially (this is what the bots use)
737-
if target.is_msvc() && builder.ninja() && builder.config.ccache.is_some() {
738-
let mut wrap_cc = env::current_exe().expect("failed to get cwd");
739-
wrap_cc.set_file_name("sccache-plus-cl.exe");
740-
741-
cfg.define("CMAKE_C_COMPILER", sanitize_cc(&wrap_cc))
742-
.define("CMAKE_CXX_COMPILER", sanitize_cc(&wrap_cc));
743-
cfg.env("SCCACHE_PATH", builder.config.ccache.as_ref().unwrap())
744-
.env("SCCACHE_TARGET", target.triple)
745-
.env("SCCACHE_CC", &cc)
746-
.env("SCCACHE_CXX", &cxx);
747-
748-
// Building LLVM on MSVC can be a little ludicrous at times. We're so far
749-
// off the beaten path here that I'm not really sure this is even half
750-
// supported any more. Here we're trying to:
751-
//
752-
// * Build LLVM on MSVC
753-
// * Build LLVM with `clang-cl` instead of `cl.exe`
754-
// * Build a project with `sccache`
755-
// * Build for 32-bit as well
756-
// * Build with Ninja
757-
//
758-
// For `cl.exe` there are different binaries to compile 32/64 bit which
759-
// we use but for `clang-cl` there's only one which internally
760-
// multiplexes via flags. As a result it appears that CMake's detection
761-
// of a compiler's architecture and such on MSVC **doesn't** pass any
762-
// custom flags we pass in CMAKE_CXX_FLAGS below. This means that if we
763-
// use `clang-cl.exe` it's always diagnosed as a 64-bit compiler which
764-
// definitely causes problems since all the env vars are pointing to
765-
// 32-bit libraries.
766-
//
767-
// To hack around this... again... we pass an argument that's
768-
// unconditionally passed in the sccache shim. This'll get CMake to
769-
// correctly diagnose it's doing a 32-bit compilation and LLVM will
770-
// internally configure itself appropriately.
771-
if builder.config.llvm_clang_cl.is_some() && target.contains("i686") {
772-
cfg.env("SCCACHE_EXTRA_ARGS", "-m32");
740+
// If ccache is configured we inform the build a little differently how
741+
// to invoke ccache while also invoking our compilers.
742+
if use_compiler_launcher {
743+
if let Some(ref ccache) = builder.config.ccache {
744+
cfg.define("CMAKE_C_COMPILER_LAUNCHER", ccache)
745+
.define("CMAKE_CXX_COMPILER_LAUNCHER", ccache);
773746
}
774-
} else {
775-
// If ccache is configured we inform the build a little differently how
776-
// to invoke ccache while also invoking our compilers.
777-
if use_compiler_launcher {
778-
if let Some(ref ccache) = builder.config.ccache {
779-
cfg.define("CMAKE_C_COMPILER_LAUNCHER", ccache)
780-
.define("CMAKE_CXX_COMPILER_LAUNCHER", ccache);
781-
}
782-
}
783-
cfg.define("CMAKE_C_COMPILER", sanitize_cc(&cc))
784-
.define("CMAKE_CXX_COMPILER", sanitize_cc(&cxx))
785-
.define("CMAKE_ASM_COMPILER", sanitize_cc(&cc));
786747
}
748+
cfg.define("CMAKE_C_COMPILER", sanitize_cc(&cc))
749+
.define("CMAKE_CXX_COMPILER", sanitize_cc(&cxx))
750+
.define("CMAKE_ASM_COMPILER", sanitize_cc(&cc));
787751

788752
cfg.build_arg("-j").build_arg(builder.jobs().to_string());
789753
// FIXME(madsmtm): Allow `cmake-rs` to select flags by itself by passing
@@ -807,7 +771,9 @@ fn configure_cmake(
807771
cflags.push(" ");
808772
cflags.push(s);
809773
}
810-
774+
if target.contains("ohos") {
775+
cflags.push(" -D_LINUX_SYSINFO_H");
776+
}
811777
if builder.config.llvm_clang_cl.is_some() {
812778
cflags.push(format!(" --target={target}"));
813779
}
@@ -828,6 +794,9 @@ fn configure_cmake(
828794
cxxflags.push(" ");
829795
cxxflags.push(s);
830796
}
797+
if target.contains("ohos") {
798+
cxxflags.push(" -D_LINUX_SYSINFO_H");
799+
}
831800
if builder.config.llvm_clang_cl.is_some() {
832801
cxxflags.push(format!(" --target={target}"));
833802
}
@@ -934,6 +903,15 @@ impl Step for Enzyme {
934903
}
935904

936905
/// Compile Enzyme for `target`.
906+
#[cfg_attr(
907+
feature = "tracing",
908+
instrument(
909+
level = "debug",
910+
name = "Enzyme::run",
911+
skip_all,
912+
fields(target = ?self.target),
913+
),
914+
)]
937915
fn run(self, builder: &Builder<'_>) -> PathBuf {
938916
builder.require_submodule(
939917
"src/tools/enzyme",
@@ -959,7 +937,9 @@ impl Step for Enzyme {
959937
let out_dir = builder.enzyme_out(target);
960938
let stamp = BuildStamp::new(&out_dir).with_prefix("enzyme").add_stamp(smart_stamp_hash);
961939

940+
trace!("checking build stamp to see if we need to rebuild enzyme artifacts");
962941
if stamp.is_up_to_date() {
942+
trace!(?out_dir, "enzyme build artifacts are up to date");
963943
if stamp.stamp().is_empty() {
964944
builder.info(
965945
"Could not determine the Enzyme submodule commit hash. \
@@ -973,6 +953,7 @@ impl Step for Enzyme {
973953
return out_dir;
974954
}
975955

956+
trace!(?target, "(re)building enzyme artifacts");
976957
builder.info(&format!("Building Enzyme for {}", target));
977958
t!(stamp.remove());
978959
let _time = helpers::timeit(builder);
@@ -982,25 +963,23 @@ impl Step for Enzyme {
982963
.config
983964
.update_submodule(Path::new("src").join("tools").join("enzyme").to_str().unwrap());
984965
let mut cfg = cmake::Config::new(builder.src.join("src/tools/enzyme/enzyme/"));
985-
// FIXME(ZuseZ4): Find a nicer way to use Enzyme Debug builds
986-
//cfg.profile("Debug");
987-
//cfg.define("CMAKE_BUILD_TYPE", "Debug");
988966
configure_cmake(builder, target, &mut cfg, true, LdFlags::default(), &[]);
989967

990968
// Re-use the same flags as llvm to control the level of debug information
991-
// generated for lld.
969+
// generated by Enzyme.
970+
// FIXME(ZuseZ4): Find a nicer way to use Enzyme Debug builds.
992971
let profile = match (builder.config.llvm_optimize, builder.config.llvm_release_debuginfo) {
993972
(false, _) => "Debug",
994973
(true, false) => "Release",
995974
(true, true) => "RelWithDebInfo",
996975
};
976+
trace!(?profile);
997977

998978
cfg.out_dir(&out_dir)
999979
.profile(profile)
1000980
.env("LLVM_CONFIG_REAL", &llvm_config)
1001981
.define("LLVM_ENABLE_ASSERTIONS", "ON")
1002982
.define("ENZYME_EXTERNAL_SHARED_LIB", "ON")
1003-
.define("ENZYME_RUNPASS", "ON")
1004983
.define("LLVM_DIR", builder.llvm_out(target));
1005984

1006985
cfg.build();
@@ -1118,7 +1097,7 @@ impl Step for Lld {
11181097
.define("LLVM_CMAKE_DIR", llvm_cmake_dir)
11191098
.define("LLVM_INCLUDE_TESTS", "OFF");
11201099

1121-
if !builder.is_builder_target(&target) {
1100+
if !builder.is_builder_target(target) {
11221101
// Use the host llvm-tblgen binary.
11231102
cfg.define(
11241103
"LLVM_TABLEGEN_EXE",
@@ -1204,6 +1183,10 @@ impl Step for Sanitizers {
12041183
cfg.define("COMPILER_RT_USE_LIBCXX", "OFF");
12051184
cfg.define("LLVM_CONFIG_PATH", &llvm_config);
12061185

1186+
if self.target.contains("ohos") {
1187+
cfg.define("COMPILER_RT_USE_BUILTINS_LIBRARY", "ON");
1188+
}
1189+
12071190
// On Darwin targets the sanitizer runtimes are build as universal binaries.
12081191
// Unfortunately sccache currently lacks support to build them successfully.
12091192
// Disable compiler launcher on Darwin targets to avoid potential issues.

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")]
@@ -3041,9 +3043,7 @@ impl Config {
30413043
self.update_submodule("src/llvm-project");
30423044

30433045
// Check for untracked changes in `src/llvm-project`.
3044-
let has_changes = self
3045-
.last_modified_commit(&["src/llvm-project"], "download-ci-llvm", true)
3046-
.is_none();
3046+
let has_changes = self.has_changes_from_upstream(&["src/llvm-project"]);
30473047

30483048
// Return false if there are untracked changes, otherwise check if CI LLVM is available.
30493049
if has_changes { false } else { llvm::is_ci_llvm_available(self, asserts) }
@@ -3067,6 +3067,17 @@ impl Config {
30673067
}
30683068
}
30693069

3070+
/// Returns true if any of the `paths` have been modified locally.
3071+
fn has_changes_from_upstream(&self, paths: &[&str]) -> bool {
3072+
let freshness =
3073+
check_path_modifications(Some(&self.src), &self.git_config(), paths, CiEnv::current())
3074+
.unwrap();
3075+
match freshness {
3076+
PathFreshness::LastModifiedUpstream { .. } => false,
3077+
PathFreshness::HasLocalModifications { .. } => true,
3078+
}
3079+
}
3080+
30703081
/// Returns the last commit in which any of `modified_paths` were changed,
30713082
/// or `None` if there are untracked changes in the working directory and `if_unchanged` is true.
30723083
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 {

0 commit comments

Comments
 (0)