[PATCH] Allow using external builds of the compiler-rt profile lib
authorJosh Stone <jistone@redhat.com>
Tue, 25 Jul 2023 20:11:50 +0000 (13:11 -0700)
committerFabian Grünbichler <debian@fabian.gruenbichler.email>
Mon, 15 Jan 2024 07:16:35 +0000 (08:16 +0100)
This changes the bootstrap config `target.*.profiler` from a plain bool
to also allow a string, which will be used as a path to the pre-built
profiling runtime for that target. Then `profiler_builtins/build.rs`
reads that in a `LLVM_PROFILER_RT_LIB` environment variable.

Gbp-Pq: Name u-profiler.patch

config.example.toml
library/profiler_builtins/build.rs
src/bootstrap/compile.rs
src/bootstrap/config.rs

index 6d9c762ceca1ef62d3fdef87dedcedd34f457103..c70c574c28e8071ad48d9c98a240bb055bc5bc5d 100644 (file)
@@ -745,8 +745,10 @@ changelog-seen = 2
 # This option will override the same option under [build] section.
 #sanitizers = build.sanitizers (bool)
 
-# Build the profiler runtime for this target(required when compiling with options that depend
-# on this runtime, such as `-C profile-generate` or `-C instrument-coverage`).
+# When true, build the profiler runtime for this target(required when compiling
+# with options that depend on this runtime, such as `-C profile-generate` or
+# `-C instrument-coverage`). This may also be given a path to an existing build
+# of the profiling runtime library from LLVM's compiler-rt.
 # This option will override the same option under [build] section.
 #profiler = build.profiler (bool)
 
index 1b1f11798d74d4648a7539bc1201bb0f746daab3..d14d0b82229a1ef9b386acbf81b70914ff33281c 100644 (file)
@@ -6,6 +6,12 @@ use std::env;
 use std::path::Path;
 
 fn main() {
+    println!("cargo:rerun-if-env-changed=LLVM_PROFILER_RT_LIB");
+    if let Ok(rt) = env::var("LLVM_PROFILER_RT_LIB") {
+        println!("cargo:rustc-link-lib=static:+verbatim={rt}");
+        return;
+    }
+
     let target = env::var("TARGET").expect("TARGET was not set");
     let cfg = &mut cc::Build::new();
 
index 4a4e7adcbf388dcc486c2fce54da081fecc99802..ea6da47ceb52c80e1010e7b103223791d708b106 100644 (file)
@@ -314,6 +314,10 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car
         cargo.env("MACOSX_DEPLOYMENT_TARGET", target);
     }
 
+    if let Some(path) = builder.config.profiler_path(target) {
+        cargo.env("LLVM_PROFILER_RT_LIB", path);
+    }
+
     // Determine if we're going to compile in optimized C intrinsics to
     // the `compiler-builtins` crate. These intrinsics live in LLVM's
     // `compiler-rt` repository, but our `src/llvm-project` submodule isn't
index 3c740de8a7639dcf4b75832d5e948a28dd864a6f..01bef7ce0636e5458ac64a917785271fd01d6397 100644 (file)
@@ -454,7 +454,7 @@ pub struct Target {
     pub linker: Option<PathBuf>,
     pub ndk: Option<PathBuf>,
     pub sanitizers: Option<bool>,
-    pub profiler: Option<bool>,
+    pub profiler: Option<StringOrBool>,
     pub crt_static: Option<bool>,
     pub musl_root: Option<PathBuf>,
     pub musl_libdir: Option<PathBuf>,
@@ -715,9 +715,9 @@ define_config! {
     }
 }
 
-#[derive(Debug, Deserialize)]
+#[derive(Clone, Debug, Deserialize)]
 #[serde(untagged)]
-enum StringOrBool {
+pub enum StringOrBool {
     String(String),
     Bool(bool),
 }
@@ -728,6 +728,12 @@ impl Default for StringOrBool {
     }
 }
 
+impl StringOrBool {
+    fn is_string_or_true(&self) -> bool {
+        matches!(self, Self::String(_) | Self::Bool(true))
+    }
+}
+
 define_config! {
     /// TOML representation of how the Rust build is configured.
     struct Rust {
@@ -799,7 +805,7 @@ define_config! {
         llvm_libunwind: Option<String> = "llvm-libunwind",
         android_ndk: Option<String> = "android-ndk",
         sanitizers: Option<bool> = "sanitizers",
-        profiler: Option<bool> = "profiler",
+        profiler: Option<StringOrBool> = "profiler",
         crt_static: Option<bool> = "crt-static",
         musl_root: Option<String> = "musl-root",
         musl_libdir: Option<String> = "musl-libdir",
@@ -1616,12 +1622,24 @@ impl Config {
         self.target_config.values().any(|t| t.sanitizers == Some(true)) || self.sanitizers
     }
 
+    pub fn profiler_path(&self, target: TargetSelection) -> Option<&str> {
+        match self.target_config.get(&target)?.profiler.as_ref()? {
+            StringOrBool::String(s) => Some(s),
+            StringOrBool::Bool(_) => None,
+        }
+    }
+
     pub fn profiler_enabled(&self, target: TargetSelection) -> bool {
-        self.target_config.get(&target).map(|t| t.profiler).flatten().unwrap_or(self.profiler)
+        self.target_config
+            .get(&target)
+            .and_then(|t| t.profiler.as_ref())
+            .map(StringOrBool::is_string_or_true)
+            .unwrap_or(self.profiler)
     }
 
     pub fn any_profiler_enabled(&self) -> bool {
-        self.target_config.values().any(|t| t.profiler == Some(true)) || self.profiler
+        self.target_config.values().any(|t| matches!(&t.profiler, Some(p) if p.is_string_or_true()))
+            || self.profiler
     }
 
     pub fn llvm_enabled(&self) -> bool {