Skip to content

Commit b382478

Browse files
Paul Murphypmur
authored andcommitted
Allow linking a prebuilt optimized compiler-rt builtins library
Extend the <target>.optimized-compiler-builtins bootstrap option to accept a path to a prebuilt compiler-rt builtins library, and update compiler-builtins to enable optimized builtins without building compiler-rt builtins.
1 parent d9dba3a commit b382478

File tree

6 files changed

+87
-34
lines changed

6 files changed

+87
-34
lines changed

bootstrap.example.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1046,7 +1046,9 @@
10461046
# sources are available.
10471047
#
10481048
# Setting this to `false` generates slower code, but removes the requirement for a C toolchain in
1049-
# order to run `x check`.
1049+
# order to run `x check`. This may also be given a path to an existing build of the builtins
1050+
# runtime library from LLVM's compiler-rt. This option will override the same option under [build]
1051+
# section.
10501052
#optimized-compiler-builtins = build.optimized-compiler-builtins (bool)
10511053

10521054
# Link the compiler and LLVM against `jemalloc` instead of the default libc allocator.

library/compiler-builtins/compiler-builtins/build.rs

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -540,20 +540,28 @@ mod c {
540540
sources.extend(&[("__emutls_get_address", "emutls.c")]);
541541
}
542542

543+
// Optionally, link against a prebuilt llvm compiler-rt containing the builtins
544+
// library. Only the builtins library is required. On many platforms, this is
545+
// available as a library named libclang_rt.builtins.a.
546+
let link_against_prebuilt_rt = env::var_os("LLVM_COMPILER_RT_LIB").is_some();
547+
543548
// When compiling the C code we require the user to tell us where the
544549
// source code is, and this is largely done so when we're compiling as
545550
// part of rust-lang/rust we can use the same llvm-project repository as
546551
// rust-lang/rust.
547552
let root = match env::var_os("RUST_COMPILER_RT_ROOT") {
548553
Some(s) => PathBuf::from(s),
554+
// If a prebuild libcompiler-rt is provided, set a valid
555+
// path to simplify later logic. Nothing should be compiled.
556+
None if link_against_prebuilt_rt => PathBuf::new(),
549557
None => {
550558
panic!(
551559
"RUST_COMPILER_RT_ROOT is not set. You may need to run \
552560
`ci/download-compiler-rt.sh`."
553561
);
554562
}
555563
};
556-
if !root.exists() {
564+
if !link_against_prebuilt_rt && !root.exists() {
557565
panic!("RUST_COMPILER_RT_ROOT={} does not exist", root.display());
558566
}
559567

@@ -569,7 +577,7 @@ mod c {
569577
let src_dir = root.join("lib/builtins");
570578
if target.arch == "aarch64" && target.env != "msvc" && target.os != "uefi" {
571579
// See below for why we're building these as separate libraries.
572-
build_aarch64_out_of_line_atomics_libraries(&src_dir, cfg);
580+
build_aarch64_out_of_line_atomics_libraries(&src_dir, cfg, link_against_prebuilt_rt);
573581

574582
// Some run-time CPU feature detection is necessary, as well.
575583
let cpu_model_src = if src_dir.join("cpu_model.c").exists() {
@@ -583,20 +591,45 @@ mod c {
583591
let mut added_sources = HashSet::new();
584592
for (sym, src) in sources.map.iter() {
585593
let src = src_dir.join(src);
586-
if added_sources.insert(src.clone()) {
594+
if !link_against_prebuilt_rt && added_sources.insert(src.clone()) {
587595
cfg.file(&src);
588596
println!("cargo:rerun-if-changed={}", src.display());
589597
}
590598
println!("cargo:rustc-cfg={}=\"optimized-c\"", sym);
591599
}
592600

593-
cfg.compile("libcompiler-rt.a");
601+
if link_against_prebuilt_rt {
602+
let rt_builtins_ext = PathBuf::from(env::var_os("LLVM_COMPILER_RT_LIB").unwrap());
603+
if !rt_builtins_ext.exists() {
604+
panic!(
605+
"LLVM_COMPILER_RT_LIB={} does not exist",
606+
rt_builtins_ext.display()
607+
);
608+
}
609+
if let Some(dir) = rt_builtins_ext.parent() {
610+
println!("cargo::rustc-link-search=native={}", dir.display());
611+
}
612+
if let Some(lib) = rt_builtins_ext.file_name() {
613+
println!(
614+
"cargo::rustc-link-lib=static:+verbatim={}",
615+
lib.to_str().unwrap()
616+
);
617+
}
618+
} else {
619+
cfg.compile("libcompiler-rt.a");
620+
}
594621
}
595622

596-
fn build_aarch64_out_of_line_atomics_libraries(builtins_dir: &Path, cfg: &mut cc::Build) {
623+
fn build_aarch64_out_of_line_atomics_libraries(
624+
builtins_dir: &Path,
625+
cfg: &mut cc::Build,
626+
link_against_prebuilt_rt: bool,
627+
) {
597628
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
598629
let outlined_atomics_file = builtins_dir.join("aarch64").join("lse.S");
599-
println!("cargo:rerun-if-changed={}", outlined_atomics_file.display());
630+
if !link_against_prebuilt_rt {
631+
println!("cargo:rerun-if-changed={}", outlined_atomics_file.display());
632+
}
600633

601634
cfg.include(&builtins_dir);
602635

@@ -609,6 +642,13 @@ mod c {
609642
for (model_number, model_name) in
610643
&[(1, "relax"), (2, "acq"), (3, "rel"), (4, "acq_rel")]
611644
{
645+
let sym = format!("__aarch64_{}{}_{}", instruction_type, size, model_name);
646+
println!("cargo:rustc-cfg={}=\"optimized-c\"", sym);
647+
648+
if link_against_prebuilt_rt {
649+
continue;
650+
}
651+
612652
// The original compiler-rt build system compiles the same
613653
// source file multiple times with different compiler
614654
// options. Here we do something slightly different: we
@@ -632,9 +672,6 @@ mod c {
632672
.unwrap();
633673
drop(file);
634674
cfg.file(path);
635-
636-
let sym = format!("__aarch64_{}{}_{}", instruction_type, size, model_name);
637-
println!("cargo:rustc-cfg={}=\"optimized-c\"", sym);
638675
}
639676
}
640677
}

src/bootstrap/src/core/build_steps/compile.rs

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -567,25 +567,31 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, cargo: &mut Car
567567
// `compiler-builtins` crate is enabled and it's configured to learn where
568568
// `compiler-rt` is located.
569569
let compiler_builtins_c_feature = if builder.config.optimized_compiler_builtins(target) {
570-
// NOTE: this interacts strangely with `llvm-has-rust-patches`. In that case, we enforce `submodules = false`, so this is a no-op.
571-
// But, the user could still decide to manually use an in-tree submodule.
572-
//
573-
// NOTE: if we're using system llvm, we'll end up building a version of `compiler-rt` that doesn't match the LLVM we're linking to.
574-
// That's probably ok? At least, the difference wasn't enforced before. There's a comment in
575-
// the compiler_builtins build script that makes me nervous, though:
576-
// https://github.com/rust-lang/compiler-builtins/blob/31ee4544dbe47903ce771270d6e3bea8654e9e50/build.rs#L575-L579
577-
builder.require_submodule(
578-
"src/llvm-project",
579-
Some(
580-
"The `build.optimized-compiler-builtins` config option \
581-
requires `compiler-rt` sources from LLVM.",
582-
),
583-
);
584-
let compiler_builtins_root = builder.src.join("src/llvm-project/compiler-rt");
585-
assert!(compiler_builtins_root.exists());
586-
// The path to `compiler-rt` is also used by `profiler_builtins` (above),
587-
// so if you're changing something here please also change that as appropriate.
588-
cargo.env("RUST_COMPILER_RT_ROOT", &compiler_builtins_root);
570+
if let Some(path) = builder.config.optimized_compiler_builtins_path(target) {
571+
cargo.env("LLVM_COMPILER_RT_LIB", path);
572+
} else {
573+
// NOTE: this interacts strangely with `llvm-has-rust-patches`. In that case, we enforce
574+
// `submodules = false`, so this is a no-op. But, the user could still decide to
575+
// manually use an in-tree submodule.
576+
//
577+
// NOTE: if we're using system llvm, we'll end up building a version of `compiler-rt`
578+
// that doesn't match the LLVM we're linking to. That's probably ok? At least, the
579+
// difference wasn't enforced before. There's a comment in the compiler_builtins build
580+
// script that makes me nervous, though:
581+
// https://github.com/rust-lang/compiler-builtins/blob/31ee4544dbe47903ce771270d6e3bea8654e9e50/build.rs#L575-L579
582+
builder.require_submodule(
583+
"src/llvm-project",
584+
Some(
585+
"The `build.optimized-compiler-builtins` config option \
586+
requires `compiler-rt` sources from LLVM.",
587+
),
588+
);
589+
let compiler_builtins_root = builder.src.join("src/llvm-project/compiler-rt");
590+
assert!(compiler_builtins_root.exists());
591+
// The path to `compiler-rt` is also used by `profiler_builtins` (above),
592+
// so if you're changing something here please also change that as appropriate.
593+
cargo.env("RUST_COMPILER_RT_ROOT", &compiler_builtins_root);
594+
}
589595
" compiler-builtins-c"
590596
} else {
591597
""

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1766,10 +1766,18 @@ impl Config {
17661766
pub fn optimized_compiler_builtins(&self, target: TargetSelection) -> bool {
17671767
self.target_config
17681768
.get(&target)
1769-
.and_then(|t| t.optimized_compiler_builtins)
1769+
.and_then(|t| t.optimized_compiler_builtins.as_ref())
1770+
.map(StringOrBool::is_string_or_true)
17701771
.unwrap_or(self.optimized_compiler_builtins)
17711772
}
17721773

1774+
pub fn optimized_compiler_builtins_path(&self, target: TargetSelection) -> Option<&str> {
1775+
match self.target_config.get(&target)?.optimized_compiler_builtins.as_ref()? {
1776+
StringOrBool::String(s) => Some(s),
1777+
StringOrBool::Bool(_) => None,
1778+
}
1779+
}
1780+
17731781
pub fn llvm_enabled(&self, target: TargetSelection) -> bool {
17741782
self.enabled_codegen_backends(target).contains(&CodegenBackendKind::Llvm)
17751783
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use crate::core::build_steps::clippy::{LintConfig, get_clippy_rules_in_order};
1717
use crate::core::build_steps::llvm;
1818
use crate::core::build_steps::llvm::LLVM_INVALIDATION_PATHS;
1919
use crate::core::config::toml::TomlConfig;
20-
use crate::core::config::{LldMode, Target, TargetSelection};
20+
use crate::core::config::{LldMode, StringOrBool, Target, TargetSelection};
2121
use crate::utils::tests::git::git_test;
2222

2323
pub(crate) fn parse(config: &str) -> Config {
@@ -212,7 +212,7 @@ runner = "x86_64-runner"
212212
let darwin = TargetSelection::from_user("aarch64-apple-darwin");
213213
let darwin_values = Target {
214214
runner: Some("apple".into()),
215-
optimized_compiler_builtins: Some(false),
215+
optimized_compiler_builtins: Some(StringOrBool::Bool(false)),
216216
..Default::default()
217217
};
218218
assert_eq!(

src/bootstrap/src/core/config/toml/target.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ define_config! {
3939
no_std: Option<bool> = "no-std",
4040
codegen_backends: Option<Vec<String>> = "codegen-backends",
4141
runner: Option<String> = "runner",
42-
optimized_compiler_builtins: Option<bool> = "optimized-compiler-builtins",
42+
optimized_compiler_builtins: Option<StringOrBool> = "optimized-compiler-builtins",
4343
jemalloc: Option<bool> = "jemalloc",
4444
}
4545
}
@@ -71,7 +71,7 @@ pub struct Target {
7171
pub runner: Option<String>,
7272
pub no_std: bool,
7373
pub codegen_backends: Option<Vec<CodegenBackendKind>>,
74-
pub optimized_compiler_builtins: Option<bool>,
74+
pub optimized_compiler_builtins: Option<StringOrBool>,
7575
pub jemalloc: Option<bool>,
7676
}
7777

0 commit comments

Comments
 (0)