Skip to content

Commit e74143e

Browse files
author
bogon-right
committed
Add LLVM compiler-rt/profile in bootstrap
1 parent 4495cba commit e74143e

File tree

4 files changed

+205
-17
lines changed

4 files changed

+205
-17
lines changed

compiler/rustc_codegen_ssa/src/back/link.rs

+53-17
Original file line numberDiff line numberDiff line change
@@ -1144,23 +1144,46 @@ fn add_sanitizer_libraries(sess: &Session, crate_type: CrateType, linker: &mut d
11441144
}
11451145
}
11461146

1147-
fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
1148-
fn find_sanitizer_runtime(sess: &Session, filename: &str) -> PathBuf {
1149-
let session_tlib =
1150-
filesearch::make_target_lib_path(&sess.sysroot, sess.opts.target_triple.triple());
1151-
let path = session_tlib.join(filename);
1152-
if path.exists() {
1153-
return session_tlib;
1154-
} else {
1155-
let default_sysroot = filesearch::get_or_default_sysroot();
1156-
let default_tlib = filesearch::make_target_lib_path(
1157-
&default_sysroot,
1158-
sess.opts.target_triple.triple(),
1159-
);
1160-
return default_tlib;
1161-
}
1147+
fn add_profiler_libraries(sess: &Session, crate_type: CrateType, linker: &mut dyn Linker) {
1148+
let needs_runtime = match crate_type {
1149+
CrateType::Executable => true,
1150+
CrateType::Dylib
1151+
| CrateType::Cdylib
1152+
| CrateType::ProcMacro
1153+
| CrateType::Rlib
1154+
| CrateType::Staticlib => false,
1155+
};
1156+
1157+
if !needs_runtime {
1158+
return;
1159+
}
1160+
1161+
if !sess.opts.unstable_opts.no_profiler_runtime
1162+
&& (sess.instrument_coverage()
1163+
|| sess.opts.unstable_opts.profile
1164+
|| sess.opts.cg.profile_generate.enabled())
1165+
// If user doesn't provide custom profiler runtime, link default llvm profiler.
1166+
&& sess.opts.unstable_opts.profiler_runtime == "profiler_builtins"
1167+
{
1168+
link_profiler_runtime(sess, linker);
1169+
}
1170+
}
1171+
1172+
fn find_compiler_rt(sess: &Session, filename: &str) -> PathBuf {
1173+
let session_tlib =
1174+
filesearch::make_target_lib_path(&sess.sysroot, sess.opts.target_triple.triple());
1175+
let path = session_tlib.join(filename);
1176+
if path.exists() {
1177+
return session_tlib;
1178+
} else {
1179+
let default_sysroot = filesearch::get_or_default_sysroot();
1180+
let default_tlib =
1181+
filesearch::make_target_lib_path(&default_sysroot, sess.opts.target_triple.triple());
1182+
return default_tlib;
11621183
}
1184+
}
11631185

1186+
fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
11641187
let channel = option_env!("CFG_RELEASE_CHANNEL")
11651188
.map(|channel| format!("-{}", channel))
11661189
.unwrap_or_default();
@@ -1171,17 +1194,27 @@ fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
11711194
// rpath to the library as well (the rpath should be absolute, see
11721195
// PR #41352 for details).
11731196
let filename = format!("rustc{}_rt.{}", channel, name);
1174-
let path = find_sanitizer_runtime(&sess, &filename);
1197+
let path = find_compiler_rt(&sess, &filename);
11751198
let rpath = path.to_str().expect("non-utf8 component in path");
11761199
linker.args(&["-Wl,-rpath", "-Xlinker", rpath]);
11771200
linker.link_dylib(&filename, false, true);
11781201
} else {
11791202
let filename = format!("librustc{}_rt.{}.a", channel, name);
1180-
let path = find_sanitizer_runtime(&sess, &filename).join(&filename);
1203+
let path = find_compiler_rt(&sess, &filename).join(&filename);
11811204
linker.link_whole_rlib(&path);
11821205
}
11831206
}
11841207

1208+
fn link_profiler_runtime(sess: &Session, linker: &mut dyn Linker) {
1209+
let channel = option_env!("CFG_RELEASE_CHANNEL")
1210+
.map(|channel| format!("-{}", channel))
1211+
.unwrap_or_default();
1212+
1213+
let filename = format!("librustc{}_rt.profile.a", channel);
1214+
let path = find_compiler_rt(&sess, &filename).join(&filename);
1215+
linker.link_whole_rlib(&path);
1216+
}
1217+
11851218
/// Returns a boolean indicating whether the specified crate should be ignored
11861219
/// during LTO.
11871220
///
@@ -1997,6 +2030,9 @@ fn linker_with_args<'a>(
19972030
// Sanitizer libraries.
19982031
add_sanitizer_libraries(sess, crate_type, cmd);
19992032

2033+
// Profiler libraries.
2034+
add_profiler_libraries(sess, crate_type, cmd);
2035+
20002036
// Object code from the current crate.
20012037
// Take careful note of the ordering of the arguments we pass to the linker
20022038
// here. Linkers will assume that things on the left depend on things to the

src/bootstrap/builder.rs

+1
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,7 @@ impl<'a> Builder<'a> {
608608
tool::CargoClippy,
609609
native::Llvm,
610610
native::Sanitizers,
611+
native::Profiler,
611612
tool::Rustfmt,
612613
tool::Miri,
613614
tool::CargoMiri,

src/bootstrap/compile.rs

+26
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,14 @@ fn copy_third_party_objects(
205205
);
206206
}
207207

208+
if builder.config.profiler_enabled(target) && compiler.stage != 0 {
209+
// The profiler are only copied in stage1 or above,
210+
// to avoid creating dependency on LLVM.
211+
if let Some(profiler_path) = copy_profiler(builder, &compiler, target) {
212+
target_deps.push((profiler_path, DependencyType::Target));
213+
}
214+
}
215+
208216
if target == "x86_64-fortanix-unknown-sgx"
209217
|| target.contains("pc-windows-gnullvm")
210218
|| builder.config.llvm_libunwind(target) == LlvmLibunwind::InTree
@@ -444,6 +452,24 @@ impl Step for StdLink {
444452
}
445453
}
446454

455+
/// Copies profiler runtime library into target libdir.
456+
fn copy_profiler(
457+
builder: &Builder<'_>,
458+
compiler: &Compiler,
459+
target: TargetSelection,
460+
) -> Option<PathBuf> {
461+
let runtime: native::ProfilerRuntime = builder.ensure(native::Profiler { target })?;
462+
463+
if builder.config.dry_run {
464+
return None;
465+
}
466+
467+
let destination = builder.sysroot_libdir(*compiler, target).join(&runtime.name);
468+
builder.copy(&runtime.path, &destination);
469+
470+
Some(destination)
471+
}
472+
447473
/// Copies sanitizer runtime libraries into target libdir.
448474
fn copy_sanitizers(
449475
builder: &Builder<'_>,

src/bootstrap/native.rs

+125
Original file line numberDiff line numberDiff line change
@@ -1182,6 +1182,131 @@ fn supported_sanitizers(
11821182
}
11831183
}
11841184

1185+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1186+
pub struct Profiler {
1187+
pub target: TargetSelection,
1188+
}
1189+
1190+
impl Step for Profiler {
1191+
type Output = Option<ProfilerRuntime>;
1192+
1193+
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1194+
run.alias("profiler")
1195+
}
1196+
1197+
fn make_run(run: RunConfig<'_>) {
1198+
run.builder.ensure(Profiler { target: run.target });
1199+
}
1200+
1201+
/// Builds sanitizer runtime libraries.
1202+
fn run(self, builder: &Builder<'_>) -> Self::Output {
1203+
let compiler_rt_dir = builder.src.join("src/llvm-project/compiler-rt");
1204+
if !compiler_rt_dir.exists() {
1205+
return None;
1206+
}
1207+
1208+
let out_dir = builder.native_dir(self.target).join("profiler");
1209+
let runtime = supported_profilers(&out_dir, self.target, &builder.config.channel)?;
1210+
1211+
let llvm_config = builder.ensure(Llvm { target: builder.config.build });
1212+
if builder.config.dry_run {
1213+
return Some(runtime);
1214+
}
1215+
1216+
let stamp = out_dir.join("profiler-finished-building");
1217+
let stamp = HashStamp::new(stamp, builder.in_tree_llvm_info.sha());
1218+
1219+
if stamp.is_done() {
1220+
if stamp.hash.is_none() {
1221+
builder.info(&format!(
1222+
"Rebuild profiler by removing the file `{}`",
1223+
stamp.path.display()
1224+
));
1225+
}
1226+
return Some(runtime);
1227+
}
1228+
1229+
builder.info(&format!("Building profiler for {}", self.target));
1230+
t!(stamp.remove());
1231+
let _time = util::timeit(&builder);
1232+
1233+
let mut cfg = cmake::Config::new(&compiler_rt_dir);
1234+
cfg.profile("Release");
1235+
cfg.define("CMAKE_C_COMPILER_TARGET", self.target.triple);
1236+
cfg.define("COMPILER_RT_BUILD_BUILTINS", "OFF");
1237+
cfg.define("COMPILER_RT_BUILD_CRT", "OFF");
1238+
cfg.define("COMPILER_RT_BUILD_LIBFUZZER", "OFF");
1239+
cfg.define("COMPILER_RT_BUILD_PROFILE", "ON");
1240+
cfg.define("COMPILER_RT_BUILD_SANITIZERS", "OFF");
1241+
cfg.define("COMPILER_RT_BUILD_XRAY", "OFF");
1242+
cfg.define("COMPILER_RT_DEFAULT_TARGET_ONLY", "ON");
1243+
cfg.define("COMPILER_RT_USE_LIBCXX", "OFF");
1244+
cfg.define("LLVM_CONFIG_PATH", &llvm_config);
1245+
1246+
configure_cmake(builder, self.target, &mut cfg, true, LdFlags::default());
1247+
1248+
t!(fs::create_dir_all(&out_dir));
1249+
cfg.out_dir(out_dir);
1250+
cfg.build_target(&runtime.cmake_target);
1251+
cfg.build();
1252+
t!(stamp.write());
1253+
1254+
Some(runtime)
1255+
}
1256+
}
1257+
1258+
#[derive(Clone, Debug)]
1259+
pub struct ProfilerRuntime {
1260+
/// CMake target used to build the runtime.
1261+
pub cmake_target: String,
1262+
/// Path to the built runtime library.
1263+
pub path: PathBuf,
1264+
/// Library filename that will be used rustc.
1265+
pub name: String,
1266+
}
1267+
1268+
/// Returns sanitizers available on a given target.
1269+
fn supported_profilers(
1270+
out_dir: &Path,
1271+
target: TargetSelection,
1272+
channel: &str,
1273+
) -> Option<ProfilerRuntime> {
1274+
// LLVM's compile-rt has a special taste on target naming. :D
1275+
//
1276+
// compiler runtime's name seems to be a chaos:
1277+
// <https://chromium.googlesource.com/chromium/src/tools/clang/+/refs/heads/main/scripts/package.py>
1278+
let darwin_libs = || -> Option<ProfilerRuntime> {
1279+
Some(ProfilerRuntime {
1280+
cmake_target: format!("clang_rt.profile_osx"),
1281+
path: out_dir.join(&format!("build/lib/darwin/libclang_rt.profile_osx.a")),
1282+
name: format!("librustc-{}_rt.profile.a", channel),
1283+
})
1284+
};
1285+
1286+
let common_libs = |os: &str, arch: &str| -> Option<ProfilerRuntime> {
1287+
Some(ProfilerRuntime {
1288+
cmake_target: format!("clang_rt.profile-{}", arch),
1289+
path: out_dir.join(&format!("build/lib/{}/libclang_rt.profile-{}.a", os, arch)),
1290+
name: format!("librustc-{}_rt.profile.a", channel),
1291+
})
1292+
};
1293+
1294+
match &*target.triple {
1295+
"aarch64-apple-darwin" => darwin_libs(),
1296+
"aarch64-fuchsia" => common_libs("fuchsia", "aarch64"),
1297+
"aarch64-unknown-linux-gnu" => common_libs("linux", "aarch64"),
1298+
"x86_64-apple-darwin" => darwin_libs(),
1299+
"x86_64-fuchsia" => common_libs("fuchsia", "x86_64"),
1300+
"x86_64-unknown-freebsd" => common_libs("freebsd", "x86_64"),
1301+
"x86_64-unknown-netbsd" => common_libs("netbsd", "x86_64"),
1302+
"x86_64-unknown-illumos" => common_libs("illumos", "x86_64"),
1303+
"x86_64-pc-solaris" => common_libs("solaris", "x86_64"),
1304+
"x86_64-unknown-linux-gnu" => common_libs("linux", "x86_64"),
1305+
"x86_64-unknown-linux-musl" => common_libs("linux", "x86_64"),
1306+
_ => None,
1307+
}
1308+
}
1309+
11851310
struct HashStamp {
11861311
path: PathBuf,
11871312
hash: Option<Vec<u8>>,

0 commit comments

Comments
 (0)