Skip to content

Commit ff18038

Browse files
committed
Auto merge of #95170 - jyn514:ci-llvm, r=Mark-Simulacrum
Move `download-ci-llvm` out of bootstrap.py This is ready for review. It has been tested on Windows, Linux, and NixOS. The second commit ports the changes from #95234 to Rust; I can remove it if desired. Helps with #94829. As a follow-up, this makes it possible to avoid downloading llvm until it's needed for building `rustc_llvm`; it would be nice to do that, but it shouldn't go in the first draft. It might also be possible to avoid requiring python until tests run (currently there's a check in `sanity.rs`), but I haven't looked too much into that. `@rustbot` label +A-rustbuild
2 parents 2799141 + 7885ade commit ff18038

File tree

10 files changed

+369
-184
lines changed

10 files changed

+369
-184
lines changed

Cargo.lock

+2
Original file line numberDiff line numberDiff line change
@@ -225,8 +225,10 @@ dependencies = [
225225
"pretty_assertions",
226226
"serde",
227227
"serde_json",
228+
"tar",
228229
"toml",
229230
"winapi",
231+
"xz2",
230232
]
231233

232234
[[package]]

src/bootstrap/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,12 @@ cc = "1.0.69"
4242
libc = "0.2"
4343
serde = { version = "1.0.8", features = ["derive"] }
4444
serde_json = "1.0.2"
45+
tar = "0.4"
4546
toml = "0.5"
4647
ignore = "0.4.10"
4748
opener = "0.5"
4849
once_cell = "1.7.2"
50+
xz2 = "0.1"
4951

5052
[target.'cfg(windows)'.dependencies.winapi]
5153
version = "0.3"

src/bootstrap/bootstrap.py

-149
Original file line numberDiff line numberDiff line change
@@ -500,81 +500,6 @@ def download_toolchain(self, stage0=True, rustc_channel=None):
500500
with output(self.rustfmt_stamp()) as rustfmt_stamp:
501501
rustfmt_stamp.write(self.stage0_rustfmt.channel())
502502

503-
# Avoid downloading LLVM twice (once for stage0 and once for the master rustc)
504-
if self.downloading_llvm() and stage0:
505-
# We want the most recent LLVM submodule update to avoid downloading
506-
# LLVM more often than necessary.
507-
#
508-
# This git command finds that commit SHA, looking for bors-authored
509-
# commits that modified src/llvm-project or other relevant version
510-
# stamp files.
511-
#
512-
# This works even in a repository that has not yet initialized
513-
# submodules.
514-
top_level = subprocess.check_output([
515-
"git", "rev-parse", "--show-toplevel",
516-
]).decode(sys.getdefaultencoding()).strip()
517-
llvm_sha = subprocess.check_output([
518-
"git", "rev-list", "[email protected]", "-n1",
519-
"--first-parent", "HEAD",
520-
"--",
521-
"{}/src/llvm-project".format(top_level),
522-
"{}/src/bootstrap/download-ci-llvm-stamp".format(top_level),
523-
# the LLVM shared object file is named `LLVM-12-rust-{version}-nightly`
524-
"{}/src/version".format(top_level)
525-
]).decode(sys.getdefaultencoding()).strip()
526-
llvm_assertions = self.get_toml('assertions', 'llvm') == 'true'
527-
llvm_root = self.llvm_root()
528-
llvm_lib = os.path.join(llvm_root, "lib")
529-
if self.program_out_of_date(self.llvm_stamp(), llvm_sha + str(llvm_assertions)):
530-
self._download_ci_llvm(llvm_sha, llvm_assertions)
531-
for binary in ["llvm-config", "FileCheck"]:
532-
self.fix_bin_or_dylib(os.path.join(llvm_root, "bin", binary))
533-
for lib in os.listdir(llvm_lib):
534-
if lib.endswith(".so"):
535-
self.fix_bin_or_dylib(os.path.join(llvm_lib, lib))
536-
with output(self.llvm_stamp()) as llvm_stamp:
537-
llvm_stamp.write(llvm_sha + str(llvm_assertions))
538-
539-
def downloading_llvm(self):
540-
opt = self.get_toml('download-ci-llvm', 'llvm')
541-
# This is currently all tier 1 targets and tier 2 targets with host tools
542-
# (since others may not have CI artifacts)
543-
# https://doc.rust-lang.org/rustc/platform-support.html#tier-1
544-
supported_platforms = [
545-
# tier 1
546-
"aarch64-unknown-linux-gnu",
547-
"i686-pc-windows-gnu",
548-
"i686-pc-windows-msvc",
549-
"i686-unknown-linux-gnu",
550-
"x86_64-unknown-linux-gnu",
551-
"x86_64-apple-darwin",
552-
"x86_64-pc-windows-gnu",
553-
"x86_64-pc-windows-msvc",
554-
# tier 2 with host tools
555-
"aarch64-apple-darwin",
556-
"aarch64-pc-windows-msvc",
557-
"aarch64-unknown-linux-musl",
558-
"arm-unknown-linux-gnueabi",
559-
"arm-unknown-linux-gnueabihf",
560-
"armv7-unknown-linux-gnueabihf",
561-
"mips-unknown-linux-gnu",
562-
"mips64-unknown-linux-gnuabi64",
563-
"mips64el-unknown-linux-gnuabi64",
564-
"mipsel-unknown-linux-gnu",
565-
"powerpc-unknown-linux-gnu",
566-
"powerpc64-unknown-linux-gnu",
567-
"powerpc64le-unknown-linux-gnu",
568-
"riscv64gc-unknown-linux-gnu",
569-
"s390x-unknown-linux-gnu",
570-
"x86_64-unknown-freebsd",
571-
"x86_64-unknown-illumos",
572-
"x86_64-unknown-linux-musl",
573-
"x86_64-unknown-netbsd",
574-
]
575-
return opt == "true" \
576-
or (opt == "if-available" and self.build in supported_platforms)
577-
578503
def _download_component_helper(
579504
self, filename, pattern, tarball_suffix, stage0=True, key=None
580505
):
@@ -606,53 +531,6 @@ def _download_component_helper(
606531
)
607532
unpack(tarball, tarball_suffix, self.bin_root(stage0), match=pattern, verbose=self.verbose)
608533

609-
def _download_ci_llvm(self, llvm_sha, llvm_assertions):
610-
if not llvm_sha:
611-
print("error: could not find commit hash for downloading LLVM")
612-
print("help: maybe your repository history is too shallow?")
613-
print("help: consider disabling `download-ci-llvm`")
614-
print("help: or fetch enough history to include one upstream commit")
615-
exit(1)
616-
cache_prefix = "llvm-{}-{}".format(llvm_sha, llvm_assertions)
617-
cache_dst = os.path.join(self.build_dir, "cache")
618-
rustc_cache = os.path.join(cache_dst, cache_prefix)
619-
if not os.path.exists(rustc_cache):
620-
os.makedirs(rustc_cache)
621-
622-
base = "https://ci-artifacts.rust-lang.org"
623-
url = "rustc-builds/{}".format(llvm_sha)
624-
if llvm_assertions:
625-
url = url.replace('rustc-builds', 'rustc-builds-alt')
626-
# ci-artifacts are only stored as .xz, not .gz
627-
if not support_xz():
628-
print("error: XZ support is required to download LLVM")
629-
print("help: consider disabling `download-ci-llvm` or using python3")
630-
exit(1)
631-
tarball_suffix = '.tar.xz'
632-
filename = "rust-dev-nightly-" + self.build + tarball_suffix
633-
tarball = os.path.join(rustc_cache, filename)
634-
if not os.path.exists(tarball):
635-
help_on_error = "error: failed to download llvm from ci"
636-
help_on_error += "\nhelp: old builds get deleted after a certain time"
637-
help_on_error += "\nhelp: if trying to compile an old commit of rustc,"
638-
help_on_error += " disable `download-ci-llvm` in config.toml:"
639-
help_on_error += "\n"
640-
help_on_error += "\n[llvm]"
641-
help_on_error += "\ndownload-ci-llvm = false"
642-
help_on_error += "\n"
643-
get(
644-
base,
645-
"{}/{}".format(url, filename),
646-
tarball,
647-
self.checksums_sha256,
648-
verbose=self.verbose,
649-
do_verify=False,
650-
help_on_error=help_on_error,
651-
)
652-
unpack(tarball, tarball_suffix, self.llvm_root(),
653-
match="rust-dev",
654-
verbose=self.verbose)
655-
656534
def fix_bin_or_dylib(self, fname):
657535
"""Modifies the interpreter section of 'fname' to fix the dynamic linker,
658536
or the RPATH section, to fix the dynamic library search path
@@ -816,17 +694,6 @@ def rustfmt_stamp(self):
816694
"""
817695
return os.path.join(self.bin_root(True), '.rustfmt-stamp')
818696

819-
def llvm_stamp(self):
820-
"""Return the path for .llvm-stamp
821-
822-
>>> rb = RustBuild()
823-
>>> rb.build_dir = "build"
824-
>>> rb.llvm_stamp() == os.path.join("build", "ci-llvm", ".llvm-stamp")
825-
True
826-
"""
827-
return os.path.join(self.llvm_root(), '.llvm-stamp')
828-
829-
830697
def program_out_of_date(self, stamp_path, key):
831698
"""Check if the given program stamp is out of date"""
832699
if not os.path.exists(stamp_path) or self.clean:
@@ -856,22 +723,6 @@ def bin_root(self, stage0):
856723
subdir = "ci-rustc"
857724
return os.path.join(self.build_dir, self.build, subdir)
858725

859-
def llvm_root(self):
860-
"""Return the CI LLVM root directory
861-
862-
>>> rb = RustBuild()
863-
>>> rb.build_dir = "build"
864-
>>> rb.llvm_root() == os.path.join("build", "ci-llvm")
865-
True
866-
867-
When the 'build' property is given should be a nested directory:
868-
869-
>>> rb.build = "devel"
870-
>>> rb.llvm_root() == os.path.join("build", "devel", "ci-llvm")
871-
True
872-
"""
873-
return os.path.join(self.build_dir, self.build, "ci-llvm")
874-
875726
def get_toml(self, key, section=None):
876727
"""Returns the value of the given key in config.toml, otherwise returns None
877728

src/bootstrap/builder.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ use std::process::Command;
1212
use std::time::{Duration, Instant};
1313

1414
use crate::cache::{Cache, Interned, INTERNER};
15-
use crate::check;
1615
use crate::compile;
1716
use crate::config::{SplitDebuginfo, TargetSelection};
1817
use crate::dist;
@@ -25,6 +24,7 @@ use crate::test;
2524
use crate::tool::{self, SourceType};
2625
use crate::util::{self, add_dylib_path, add_link_lib_path, exe, libdir, output, t};
2726
use crate::EXTRA_CHECK_CFGS;
27+
use crate::{check, Config};
2828
use crate::{Build, CLang, DocTests, GitRepo, Mode};
2929

3030
pub use crate::Compiler;
@@ -960,6 +960,11 @@ impl<'a> Builder<'a> {
960960
None
961961
}
962962

963+
/// Convenience wrapper to allow `builder.llvm_link_shared()` instead of `builder.config.llvm_link_shared(&builder)`.
964+
pub(crate) fn llvm_link_shared(&self) -> bool {
965+
Config::llvm_link_shared(self)
966+
}
967+
963968
/// Prepares an invocation of `cargo` to be run.
964969
///
965970
/// This will create a `Command` that represents a pending execution of

src/bootstrap/compile.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -737,7 +737,7 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS
737737
);
738738
cargo.env("LLVM_STATIC_STDCPP", file);
739739
}
740-
if builder.config.llvm_link_shared {
740+
if builder.llvm_link_shared() {
741741
cargo.env("LLVM_LINK_SHARED", "1");
742742
}
743743
if builder.config.llvm_use_libcxx {

src/bootstrap/config.rs

+52-18
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
//! This module implements parsing `config.toml` configuration files to tweak
44
//! how the build runs.
55
6+
use std::cell::Cell;
67
use std::cmp;
78
use std::collections::{HashMap, HashSet};
89
use std::env;
@@ -11,7 +12,7 @@ use std::fs;
1112
use std::path::{Path, PathBuf};
1213
use std::str::FromStr;
1314

14-
use crate::builder::TaskPath;
15+
use crate::builder::{Builder, TaskPath};
1516
use crate::cache::{Interned, INTERNER};
1617
use crate::channel::GitInfo;
1718
pub use crate::flags::Subcommand;
@@ -69,13 +70,14 @@ pub struct Config {
6970
pub test_compare_mode: bool,
7071
pub llvm_libunwind: LlvmLibunwind,
7172
pub color: Color,
73+
pub patch_binaries_for_nix: bool,
7274

7375
pub on_fail: Option<String>,
7476
pub stage: u32,
7577
pub keep_stage: Vec<u32>,
7678
pub keep_stage_std: Vec<u32>,
7779
pub src: PathBuf,
78-
// defaults to `config.toml`
80+
/// defaults to `config.toml`
7981
pub config: PathBuf,
8082
pub jobs: Option<u32>,
8183
pub cmd: Subcommand,
@@ -96,7 +98,11 @@ pub struct Config {
9698
pub llvm_release_debuginfo: bool,
9799
pub llvm_version_check: bool,
98100
pub llvm_static_stdcpp: bool,
99-
pub llvm_link_shared: bool,
101+
/// `None` if `llvm_from_ci` is true and we haven't yet downloaded llvm.
102+
#[cfg(not(test))]
103+
llvm_link_shared: Cell<Option<bool>>,
104+
#[cfg(test)]
105+
pub llvm_link_shared: Cell<Option<bool>>,
100106
pub llvm_clang_cl: Option<String>,
101107
pub llvm_targets: Option<String>,
102108
pub llvm_experimental_targets: Option<String>,
@@ -858,6 +864,7 @@ impl Config {
858864
set(&mut config.local_rebuild, build.local_rebuild);
859865
set(&mut config.print_step_timings, build.print_step_timings);
860866
set(&mut config.print_step_rusage, build.print_step_rusage);
867+
set(&mut config.patch_binaries_for_nix, build.patch_binaries_for_nix);
861868

862869
config.verbose = cmp::max(config.verbose, flags.verbose);
863870

@@ -913,7 +920,9 @@ impl Config {
913920
set(&mut config.llvm_release_debuginfo, llvm.release_debuginfo);
914921
set(&mut config.llvm_version_check, llvm.version_check);
915922
set(&mut config.llvm_static_stdcpp, llvm.static_libstdcpp);
916-
set(&mut config.llvm_link_shared, llvm.link_shared);
923+
if let Some(v) = llvm.link_shared {
924+
config.llvm_link_shared.set(Some(v));
925+
}
917926
config.llvm_targets = llvm.targets.clone();
918927
config.llvm_experimental_targets = llvm.experimental_targets.clone();
919928
config.llvm_link_jobs = llvm.link_jobs;
@@ -983,6 +992,7 @@ impl Config {
983992
check_ci_llvm!(llvm.optimize);
984993
check_ci_llvm!(llvm.thin_lto);
985994
check_ci_llvm!(llvm.release_debuginfo);
995+
// CI-built LLVM can be either dynamic or static. We won't know until we download it.
986996
check_ci_llvm!(llvm.link_shared);
987997
check_ci_llvm!(llvm.static_libstdcpp);
988998
check_ci_llvm!(llvm.targets);
@@ -1000,26 +1010,14 @@ impl Config {
10001010
check_ci_llvm!(llvm.clang);
10011011
check_ci_llvm!(llvm.build_config);
10021012
check_ci_llvm!(llvm.plugins);
1003-
1004-
// CI-built LLVM can be either dynamic or static.
1005-
let ci_llvm = config.out.join(&*config.build.triple).join("ci-llvm");
1006-
config.llvm_link_shared = if config.dry_run {
1007-
// just assume dynamic for now
1008-
true
1009-
} else {
1010-
let link_type = t!(
1011-
std::fs::read_to_string(ci_llvm.join("link-type.txt")),
1012-
format!("CI llvm missing: {}", ci_llvm.display())
1013-
);
1014-
link_type == "dynamic"
1015-
};
10161013
}
10171014

1015+
// NOTE: can never be hit when downloading from CI, since we call `check_ci_llvm!(thin_lto)` above.
10181016
if config.llvm_thin_lto && llvm.link_shared.is_none() {
10191017
// If we're building with ThinLTO on, by default we want to link
10201018
// to LLVM shared, to avoid re-doing ThinLTO (which happens in
10211019
// the link step) with each stage.
1022-
config.llvm_link_shared = true;
1020+
config.llvm_link_shared.set(Some(true));
10231021
}
10241022
}
10251023

@@ -1274,6 +1272,42 @@ impl Config {
12741272
}
12751273
}
12761274

1275+
/// The absolute path to the downloaded LLVM artifacts.
1276+
pub(crate) fn ci_llvm_root(&self) -> PathBuf {
1277+
assert!(self.llvm_from_ci);
1278+
self.out.join(&*self.build.triple).join("ci-llvm")
1279+
}
1280+
1281+
/// Determine whether llvm should be linked dynamically.
1282+
///
1283+
/// If `false`, llvm should be linked statically.
1284+
/// This is computed on demand since LLVM might have to first be downloaded from CI.
1285+
pub(crate) fn llvm_link_shared(builder: &Builder<'_>) -> bool {
1286+
let mut opt = builder.config.llvm_link_shared.get();
1287+
if opt.is_none() && builder.config.dry_run {
1288+
// just assume static for now - dynamic linking isn't supported on all platforms
1289+
return false;
1290+
}
1291+
1292+
let llvm_link_shared = *opt.get_or_insert_with(|| {
1293+
if builder.config.llvm_from_ci {
1294+
crate::native::maybe_download_ci_llvm(builder);
1295+
let ci_llvm = builder.config.ci_llvm_root();
1296+
let link_type = t!(
1297+
std::fs::read_to_string(ci_llvm.join("link-type.txt")),
1298+
format!("CI llvm missing: {}", ci_llvm.display())
1299+
);
1300+
link_type == "dynamic"
1301+
} else {
1302+
// unclear how thought-through this default is, but it maintains compatibility with
1303+
// previous behavior
1304+
false
1305+
}
1306+
});
1307+
builder.config.llvm_link_shared.set(opt);
1308+
llvm_link_shared
1309+
}
1310+
12771311
pub fn verbose(&self) -> bool {
12781312
self.verbose > 0
12791313
}

0 commit comments

Comments
 (0)