Skip to content

Commit de8e02c

Browse files
committed
Add a new if-identical mode to llvm.from_ci
It downloads llvm-opts from CI and checks if it is equal to the LLVM compiled on CI.
1 parent 1e6f9a1 commit de8e02c

File tree

6 files changed

+82
-23
lines changed

6 files changed

+82
-23
lines changed

src/bootstrap/builder.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1105,7 +1105,7 @@ impl<'a> Builder<'a> {
11051105
let mut dylib_dirs = vec![self.rustc_libdir(compiler)];
11061106

11071107
// Ensure that the downloaded LLVM libraries can be found.
1108-
if self.config.llvm.from_ci {
1108+
if self.config.llvm_from_ci {
11091109
let ci_llvm_lib = self.out.join(&*compiler.host.triple).join("ci-llvm").join("lib");
11101110
dylib_dirs.push(ci_llvm_lib);
11111111
}

src/bootstrap/config.rs

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ impl Display for DebuginfoLevel {
101101
}
102102
}
103103

104-
#[derive(Default, Clone)]
104+
#[derive(Default, Clone, PartialEq, serde_derive::Serialize, serde_derive::Deserialize)]
105105
pub struct LLVMConfig {
106106
pub assertions: bool,
107107
pub tests: bool,
@@ -111,9 +111,6 @@ pub struct LLVMConfig {
111111
pub release_debuginfo: bool,
112112
pub static_stdcpp: bool,
113113
/// `None` if `llvm_from_ci` is true and we haven't yet downloaded llvm.
114-
#[cfg(not(test))]
115-
link_shared: Cell<Option<bool>>,
116-
#[cfg(test)]
117114
pub link_shared: Cell<Option<bool>>,
118115
pub clang_cl: Option<String>,
119116
pub targets: Option<String>,
@@ -125,7 +122,6 @@ pub struct LLVMConfig {
125122
pub polly: bool,
126123
pub clang: bool,
127124
pub enable_warnings: bool,
128-
pub from_ci: bool,
129125
pub build_config: HashMap<String, String>,
130126

131127
pub use_lld: bool,
@@ -204,6 +200,7 @@ pub struct Config {
204200
pub backtrace_on_ice: bool,
205201

206202
// llvm codegen options
203+
pub llvm_from_ci: bool,
207204
pub llvm: LLVMConfig,
208205

209206
// rust codegen options
@@ -1519,18 +1516,26 @@ impl Config {
15191516
config.llvm.build_config = llvm.build_config.clone().unwrap_or(Default::default());
15201517

15211518
let asserts = llvm_assertions.unwrap_or(false);
1522-
config.llvm.from_ci = match llvm.download_ci_llvm {
1523-
Some(StringOrBool::String(s)) => {
1524-
assert!(s == "if-available", "unknown option `{}` for download-ci-llvm", s);
1525-
crate::llvm::is_ci_llvm_available(&config, asserts)
1526-
}
1519+
let mut downloaded_config = false;
1520+
config.llvm_from_ci = match llvm.download_ci_llvm {
1521+
Some(StringOrBool::String(s)) => match s.as_str() {
1522+
"if-available" => crate::llvm::is_ci_llvm_available(&config, asserts),
1523+
"if-identical" => match crate::llvm::get_llvm_opts_from_ci(&config) {
1524+
Some(config_ci) => {
1525+
downloaded_config = true;
1526+
is_llvm_config_identical(&config_ci, &config.llvm)
1527+
}
1528+
None => false,
1529+
},
1530+
_ => panic!("unknown option `{s}` for download-ci-llvm"),
1531+
},
15271532
Some(StringOrBool::Bool(b)) => b,
15281533
None => {
15291534
config.channel == "dev" && crate::llvm::is_ci_llvm_available(&config, asserts)
15301535
}
15311536
};
15321537

1533-
if config.llvm.from_ci {
1538+
if config.llvm_from_ci && !downloaded_config {
15341539
// None of the LLVM options, except assertions, are supported
15351540
// when using downloaded LLVM. We could just ignore these but
15361541
// that's potentially confusing, so force them to not be
@@ -1561,14 +1566,14 @@ impl Config {
15611566
}
15621567

15631568
// NOTE: can never be hit when downloading from CI, since we call `check_ci_llvm!(thin_lto)` above.
1564-
if config.llvm.thin_lto && llvm.link_shared.is_none() {
1569+
if !downloaded_config && config.llvm.thin_lto && llvm.link_shared.is_none() {
15651570
// If we're building with ThinLTO on, by default we want to link
15661571
// to LLVM shared, to avoid re-doing ThinLTO (which happens in
15671572
// the link step) with each stage.
15681573
config.llvm.link_shared.set(Some(true));
15691574
}
15701575
} else {
1571-
config.llvm.from_ci =
1576+
config.llvm_from_ci =
15721577
config.channel == "dev" && crate::llvm::is_ci_llvm_available(&config, false);
15731578
}
15741579

@@ -1620,7 +1625,7 @@ impl Config {
16201625
}
16211626
}
16221627

1623-
if config.llvm.from_ci {
1628+
if config.llvm_from_ci {
16241629
let triple = &config.build.triple;
16251630
let ci_llvm_bin = config.ci_llvm_root().join("bin");
16261631
let build_target = config
@@ -1860,10 +1865,14 @@ impl Config {
18601865

18611866
/// The absolute path to the downloaded LLVM artifacts.
18621867
pub(crate) fn ci_llvm_root(&self) -> PathBuf {
1863-
assert!(self.llvm.from_ci);
1868+
assert!(self.llvm_from_ci);
18641869
self.out.join(&*self.build.triple).join("ci-llvm")
18651870
}
18661871

1872+
pub(crate) fn ci_llvm_root_opts(&self) -> PathBuf {
1873+
self.out.join(&*self.build.triple).join("ci-llvm-opts")
1874+
}
1875+
18671876
/// Directory where the extracted `rustc-dev` component is stored.
18681877
pub(crate) fn ci_rustc_dir(&self) -> PathBuf {
18691878
assert!(self.download_rustc());
@@ -1882,7 +1891,7 @@ impl Config {
18821891
}
18831892

18841893
let llvm_link_shared = *opt.get_or_insert_with(|| {
1885-
if self.llvm.from_ci {
1894+
if self.llvm_from_ci {
18861895
self.maybe_download_ci_llvm();
18871896
let ci_llvm = self.ci_llvm_root();
18881897
let link_type = t!(
@@ -2089,6 +2098,10 @@ impl Config {
20892098
}
20902099
}
20912100

2101+
fn is_llvm_config_identical(from_ci: &LLVMConfig, current: &LLVMConfig) -> bool {
2102+
from_ci == current
2103+
}
2104+
20922105
fn set<T>(field: &mut T, val: Option<T>) {
20932106
if let Some(v) = val {
20942107
*field = v;

src/bootstrap/dist.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1968,7 +1968,7 @@ fn install_llvm_file(builder: &Builder<'_>, source: &Path, destination: &Path) {
19681968
/// Returns whether the files were actually copied.
19691969
fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir: &Path) -> bool {
19701970
if let Some(config) = builder.config.target_config.get(&target) {
1971-
if config.llvm_config.is_some() && !builder.config.llvm.from_ci {
1971+
if config.llvm_config.is_some() && !builder.config.llvm_from_ci {
19721972
// If the LLVM was externally provided, then we don't currently copy
19731973
// artifacts into the sysroot. This is not necessarily the right
19741974
// choice (in particular, it will require the LLVM dylib to be in
@@ -2090,7 +2090,7 @@ impl Step for BoltInstrument {
20902090
return self.file.clone();
20912091
}
20922092

2093-
if builder.build.config.llvm.from_ci {
2093+
if builder.build.config.llvm_from_ci {
20942094
println!("warning: trying to use BOLT with LLVM from CI, this will probably not work");
20952095
}
20962096

@@ -2142,7 +2142,7 @@ impl Step for BoltOptimize {
21422142
return self.file.clone();
21432143
}
21442144

2145-
if builder.build.config.llvm.from_ci {
2145+
if builder.build.config.llvm_from_ci {
21462146
println!("warning: trying to use BOLT with LLVM from CI, this will probably not work");
21472147
}
21482148

src/bootstrap/download.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -602,7 +602,7 @@ download-rustc = false
602602
}
603603

604604
pub(crate) fn maybe_download_ci_llvm(&self) {
605-
if !self.llvm.from_ci {
605+
if !self.llvm_from_ci {
606606
return;
607607
}
608608
let llvm_root = self.ci_llvm_root();
@@ -674,4 +674,33 @@ download-rustc = false
674674
let llvm_root = self.ci_llvm_root();
675675
self.unpack(&tarball, &llvm_root, "rust-dev");
676676
}
677+
678+
pub(crate) fn download_ci_llvm_opts(&self, llvm_sha: &str) {
679+
let cache_prefix = format!("llvm-opts-{llvm_sha}");
680+
let cache_dst = self.out.join("cache");
681+
let rustc_cache = cache_dst.join(cache_prefix);
682+
t!(fs::create_dir_all(&rustc_cache));
683+
let base = if self.llvm.assertions {
684+
&self.stage0_metadata.config.artifacts_with_llvm_assertions_server
685+
} else {
686+
&self.stage0_metadata.config.artifacts_server
687+
};
688+
let version = self.artifact_version_part(llvm_sha);
689+
let filename = format!("rust-dev-config-{}-{}.tar.xz", version, self.build.triple);
690+
let tarball = rustc_cache.join(&filename);
691+
if !tarball.exists() {
692+
let help_on_error = "error: failed to download llvm config from ci
693+
694+
help: old builds get deleted after a certain time
695+
help: if trying to compile an old commit of rustc, disable `download-ci-llvm` in config.toml:
696+
697+
[llvm]
698+
download-ci-llvm = false
699+
";
700+
self.download_file(&format!("{base}/{llvm_sha}/{filename}"), &tarball, help_on_error);
701+
}
702+
703+
let llvm_root = self.ci_llvm_root_opts();
704+
self.unpack(&tarball, &llvm_root, "rust-dev-config");
705+
}
677706
}

src/bootstrap/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -868,7 +868,7 @@ impl Build {
868868
Some(Target { llvm_config, .. }) => {
869869
// If the user set llvm-config we assume Rust is not patched,
870870
// but first check to see if it was configured by llvm-from-ci.
871-
(self.config.llvm.from_ci && target == self.config.build) || llvm_config.is_none()
871+
(self.config.llvm_from_ci && target == self.config.build) || llvm_config.is_none()
872872
}
873873
None => true,
874874
}

src/bootstrap/llvm.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use std::process::Command;
1818

1919
use crate::builder::{Builder, RunConfig, ShouldRun, Step};
2020
use crate::channel;
21-
use crate::config::{Config, TargetSelection};
21+
use crate::config::{Config, LLVMConfig, TargetSelection};
2222
use crate::util::get_clang_cl_resource_dir;
2323
use crate::util::{self, exe, output, t, up_to_date};
2424
use crate::{CLang, GitRepo, Kind};
@@ -215,6 +215,23 @@ pub(crate) fn is_ci_llvm_available(config: &Config, asserts: bool) -> bool {
215215
true
216216
}
217217

218+
pub(crate) fn get_llvm_opts_from_ci(config: &Config) -> Option<LLVMConfig> {
219+
if config.dry_run() || is_ci_llvm_modified(config) {
220+
return None;
221+
}
222+
223+
let llvm_sha = detect_llvm_sha(config, config.rust_info.is_managed_git_subrepository());
224+
config.download_ci_llvm_opts(&llvm_sha);
225+
226+
let config_path = config.ci_llvm_root_opts().join("llvm-opts.json");
227+
let Ok(config) = serde_json::from_slice::<LLVMConfig>(&t!(std::fs::read(config_path))) else {
228+
// The LLVM config has changed its format or is corrupted in some way
229+
eprintln!("Cannot deserialize LLVM config from llvm-opts.json");
230+
return None;
231+
};
232+
Some(config)
233+
}
234+
218235
/// Returns true if we're running in CI with modified LLVM (and thus can't download it)
219236
pub(crate) fn is_ci_llvm_modified(config: &Config) -> bool {
220237
CiEnv::is_ci() && config.rust_info.is_managed_git_subrepository() && {

0 commit comments

Comments
 (0)