Skip to content

Commit 263a3ae

Browse files
committed
Auto merge of rust-lang#129788 - onur-ozkan:incompatibility-check-for-llvm, r=Kobzol
detect incompatible CI LLVM options more precisely Previously, the logic here was simply checking whether the option was set in `config.toml`. This approach was not manageable in our CI runners as we set so many options in config.toml. In reality, those values are not incompatible since they are usually the same value used to generate the CI llvm. Now, the new logic compares the configuration values with the values used to generate the CI llvm, so we get more precise results and make the process more manageable. Fixes rust-lang#129153
2 parents 085744b + 7b8cbe4 commit 263a3ae

File tree

2 files changed

+147
-34
lines changed

2 files changed

+147
-34
lines changed

Diff for: src/bootstrap/src/core/config/config.rs

+118-33
Original file line numberDiff line numberDiff line change
@@ -1216,13 +1216,23 @@ impl Config {
12161216
}
12171217
}
12181218

1219+
pub(crate) fn get_builder_toml(&self, build_name: &str) -> Result<TomlConfig, toml::de::Error> {
1220+
if self.dry_run() {
1221+
return Ok(TomlConfig::default());
1222+
}
1223+
1224+
let builder_config_path =
1225+
self.out.join(self.build.triple).join(build_name).join(BUILDER_CONFIG_FILENAME);
1226+
Self::get_toml(&builder_config_path)
1227+
}
1228+
12191229
#[cfg(test)]
1220-
fn get_toml(_: &Path) -> Result<TomlConfig, toml::de::Error> {
1230+
pub(crate) fn get_toml(_: &Path) -> Result<TomlConfig, toml::de::Error> {
12211231
Ok(TomlConfig::default())
12221232
}
12231233

12241234
#[cfg(not(test))]
1225-
fn get_toml(file: &Path) -> Result<TomlConfig, toml::de::Error> {
1235+
pub(crate) fn get_toml(file: &Path) -> Result<TomlConfig, toml::de::Error> {
12261236
let contents =
12271237
t!(fs::read_to_string(file), format!("config file {} not found", file.display()));
12281238
// Deserialize to Value and then TomlConfig to prevent the Deserialize impl of
@@ -1908,34 +1918,9 @@ impl Config {
19081918
"HELP: To use `llvm.libzstd` for LLVM/LLD builds, set `download-ci-llvm` option to false."
19091919
);
19101920
}
1911-
1912-
// None of the LLVM options, except assertions, are supported
1913-
// when using downloaded LLVM. We could just ignore these but
1914-
// that's potentially confusing, so force them to not be
1915-
// explicitly set. The defaults and CI defaults don't
1916-
// necessarily match but forcing people to match (somewhat
1917-
// arbitrary) CI configuration locally seems bad/hard.
1918-
check_ci_llvm!(optimize_toml);
1919-
check_ci_llvm!(thin_lto);
1920-
check_ci_llvm!(release_debuginfo);
1921-
check_ci_llvm!(targets);
1922-
check_ci_llvm!(experimental_targets);
1923-
check_ci_llvm!(clang_cl);
1924-
check_ci_llvm!(version_suffix);
1925-
check_ci_llvm!(cflags);
1926-
check_ci_llvm!(cxxflags);
1927-
check_ci_llvm!(ldflags);
1928-
check_ci_llvm!(use_libcxx);
1929-
check_ci_llvm!(use_linker);
1930-
check_ci_llvm!(allow_old_toolchain);
1931-
check_ci_llvm!(polly);
1932-
check_ci_llvm!(clang);
1933-
check_ci_llvm!(build_config);
1934-
check_ci_llvm!(plugins);
19351921
}
19361922

1937-
// NOTE: can never be hit when downloading from CI, since we call `check_ci_llvm!(thin_lto)` above.
1938-
if config.llvm_thin_lto && link_shared.is_none() {
1923+
if !config.llvm_from_ci && config.llvm_thin_lto && link_shared.is_none() {
19391924
// If we're building with ThinLTO on, by default we want to link
19401925
// to LLVM shared, to avoid re-doing ThinLTO (which happens in
19411926
// the link step) with each stage.
@@ -2374,18 +2359,15 @@ impl Config {
23742359
self.download_ci_rustc(commit);
23752360

23762361
if let Some(config_path) = &self.config {
2377-
let builder_config_path =
2378-
self.out.join(self.build.triple).join("ci-rustc").join(BUILDER_CONFIG_FILENAME);
2379-
2380-
let ci_config_toml = match Self::get_toml(&builder_config_path) {
2362+
let ci_config_toml = match self.get_builder_toml("ci-rustc") {
23812363
Ok(ci_config_toml) => ci_config_toml,
23822364
Err(e) if e.to_string().contains("unknown field") => {
23832365
println!("WARNING: CI rustc has some fields that are no longer supported in bootstrap; download-rustc will be disabled.");
23842366
println!("HELP: Consider rebasing to a newer commit if available.");
23852367
return None;
23862368
},
23872369
Err(e) => {
2388-
eprintln!("ERROR: Failed to parse CI rustc config at '{}': {e}", builder_config_path.display());
2370+
eprintln!("ERROR: Failed to parse CI rustc config.toml: {e}");
23892371
exit!(2);
23902372
},
23912373
};
@@ -2846,6 +2828,109 @@ impl Config {
28462828
}
28472829
}
28482830

2831+
/// Compares the current `Llvm` options against those in the CI LLVM builder and detects any incompatible options.
2832+
/// It does this by destructuring the `Llvm` instance to make sure every `Llvm` field is covered and not missing.
2833+
#[cfg(not(feature = "bootstrap-self-test"))]
2834+
pub(crate) fn check_incompatible_options_for_ci_llvm(
2835+
current_config_toml: TomlConfig,
2836+
ci_config_toml: TomlConfig,
2837+
) -> Result<(), String> {
2838+
macro_rules! err {
2839+
($current:expr, $expected:expr) => {
2840+
if let Some(current) = &$current {
2841+
if Some(current) != $expected.as_ref() {
2842+
return Err(format!(
2843+
"ERROR: Setting `llvm.{}` is incompatible with `llvm.download-ci-llvm`. \
2844+
Current value: {:?}, Expected value(s): {}{:?}",
2845+
stringify!($expected).replace("_", "-"),
2846+
$current,
2847+
if $expected.is_some() { "None/" } else { "" },
2848+
$expected,
2849+
));
2850+
};
2851+
};
2852+
};
2853+
}
2854+
2855+
macro_rules! warn {
2856+
($current:expr, $expected:expr) => {
2857+
if let Some(current) = &$current {
2858+
if Some(current) != $expected.as_ref() {
2859+
println!(
2860+
"WARNING: `llvm.{}` has no effect with `llvm.download-ci-llvm`. \
2861+
Current value: {:?}, Expected value(s): {}{:?}",
2862+
stringify!($expected).replace("_", "-"),
2863+
$current,
2864+
if $expected.is_some() { "None/" } else { "" },
2865+
$expected,
2866+
);
2867+
};
2868+
};
2869+
};
2870+
}
2871+
2872+
let (Some(current_llvm_config), Some(ci_llvm_config)) =
2873+
(current_config_toml.llvm, ci_config_toml.llvm)
2874+
else {
2875+
return Ok(());
2876+
};
2877+
2878+
let Llvm {
2879+
optimize,
2880+
thin_lto,
2881+
release_debuginfo,
2882+
assertions: _,
2883+
tests: _,
2884+
plugins,
2885+
ccache: _,
2886+
static_libstdcpp: _,
2887+
libzstd,
2888+
ninja: _,
2889+
targets,
2890+
experimental_targets,
2891+
link_jobs: _,
2892+
link_shared: _,
2893+
version_suffix,
2894+
clang_cl,
2895+
cflags,
2896+
cxxflags,
2897+
ldflags,
2898+
use_libcxx,
2899+
use_linker,
2900+
allow_old_toolchain,
2901+
polly,
2902+
clang,
2903+
enable_warnings,
2904+
download_ci_llvm: _,
2905+
build_config,
2906+
enzyme,
2907+
} = ci_llvm_config;
2908+
2909+
err!(current_llvm_config.optimize, optimize);
2910+
err!(current_llvm_config.thin_lto, thin_lto);
2911+
err!(current_llvm_config.release_debuginfo, release_debuginfo);
2912+
err!(current_llvm_config.libzstd, libzstd);
2913+
err!(current_llvm_config.targets, targets);
2914+
err!(current_llvm_config.experimental_targets, experimental_targets);
2915+
err!(current_llvm_config.clang_cl, clang_cl);
2916+
err!(current_llvm_config.version_suffix, version_suffix);
2917+
err!(current_llvm_config.cflags, cflags);
2918+
err!(current_llvm_config.cxxflags, cxxflags);
2919+
err!(current_llvm_config.ldflags, ldflags);
2920+
err!(current_llvm_config.use_libcxx, use_libcxx);
2921+
err!(current_llvm_config.use_linker, use_linker);
2922+
err!(current_llvm_config.allow_old_toolchain, allow_old_toolchain);
2923+
err!(current_llvm_config.polly, polly);
2924+
err!(current_llvm_config.clang, clang);
2925+
err!(current_llvm_config.build_config, build_config);
2926+
err!(current_llvm_config.plugins, plugins);
2927+
err!(current_llvm_config.enzyme, enzyme);
2928+
2929+
warn!(current_llvm_config.enable_warnings, enable_warnings);
2930+
2931+
Ok(())
2932+
}
2933+
28492934
/// Compares the current Rust options against those in the CI rustc builder and detects any incompatible options.
28502935
/// It does this by destructuring the `Rust` instance to make sure every `Rust` field is covered and not missing.
28512936
fn check_incompatible_options_for_ci_rustc(

Diff for: src/bootstrap/src/core/download.rs

+29-1
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,7 @@ impl Config {
316316
let mut tar = tar::Archive::new(decompressor);
317317

318318
let is_ci_rustc = dst.ends_with("ci-rustc");
319+
let is_ci_llvm = dst.ends_with("ci-llvm");
319320

320321
// `compile::Sysroot` needs to know the contents of the `rustc-dev` tarball to avoid adding
321322
// it to the sysroot unless it was explicitly requested. But parsing the 100 MB tarball is slow.
@@ -332,7 +333,9 @@ impl Config {
332333
let mut short_path = t!(original_path.strip_prefix(directory_prefix));
333334
let is_builder_config = short_path.to_str() == Some(BUILDER_CONFIG_FILENAME);
334335

335-
if !(short_path.starts_with(pattern) || (is_ci_rustc && is_builder_config)) {
336+
if !(short_path.starts_with(pattern)
337+
|| ((is_ci_rustc || is_ci_llvm) && is_builder_config))
338+
{
336339
continue;
337340
}
338341
short_path = short_path.strip_prefix(pattern).unwrap_or(short_path);
@@ -717,17 +720,22 @@ download-rustc = false
717720

718721
#[cfg(not(feature = "bootstrap-self-test"))]
719722
pub(crate) fn maybe_download_ci_llvm(&self) {
723+
use build_helper::exit;
724+
720725
use crate::core::build_steps::llvm::detect_llvm_sha;
726+
use crate::core::config::check_incompatible_options_for_ci_llvm;
721727

722728
if !self.llvm_from_ci {
723729
return;
724730
}
731+
725732
let llvm_root = self.ci_llvm_root();
726733
let llvm_stamp = llvm_root.join(".llvm-stamp");
727734
let llvm_sha = detect_llvm_sha(self, self.rust_info.is_managed_git_subrepository());
728735
let key = format!("{}{}", llvm_sha, self.llvm_assertions);
729736
if program_out_of_date(&llvm_stamp, &key) && !self.dry_run() {
730737
self.download_ci_llvm(&llvm_sha);
738+
731739
if self.should_fix_bins_and_dylibs() {
732740
for entry in t!(fs::read_dir(llvm_root.join("bin"))) {
733741
self.fix_bin_or_dylib(&t!(entry).path());
@@ -760,6 +768,26 @@ download-rustc = false
760768

761769
t!(fs::write(llvm_stamp, key));
762770
}
771+
772+
if let Some(config_path) = &self.config {
773+
let current_config_toml = Self::get_toml(config_path).unwrap();
774+
775+
match self.get_builder_toml("ci-llvm") {
776+
Ok(ci_config_toml) => {
777+
t!(check_incompatible_options_for_ci_llvm(current_config_toml, ci_config_toml));
778+
}
779+
Err(e) if e.to_string().contains("unknown field") => {
780+
println!(
781+
"WARNING: CI LLVM has some fields that are no longer supported in bootstrap; download-ci-llvm will be disabled."
782+
);
783+
println!("HELP: Consider rebasing to a newer commit if available.");
784+
}
785+
Err(e) => {
786+
eprintln!("ERROR: Failed to parse CI LLVM config.toml: {e}");
787+
exit!(2);
788+
}
789+
};
790+
};
763791
}
764792

765793
#[cfg(not(feature = "bootstrap-self-test"))]

0 commit comments

Comments
 (0)