From 642f34880532ff758be2fab9cae7dd6d0681ef2a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 5 Apr 2026 20:07:50 +0200 Subject: [PATCH] Fix linking two dylibs together when both depend on profiler_builtins See the comment inside this commit for why. --- compiler/rustc_codegen_ssa/src/back/link.rs | 4 ++- compiler/rustc_metadata/src/creader.rs | 9 +++++- .../duplicate-profiler-builtins/dylib_a.rs | 1 + .../duplicate-profiler-builtins/dylib_b.rs | 1 + .../duplicate-profiler-builtins/main.rs | 4 +++ .../duplicate-profiler-builtins/rmake.rs | 29 +++++++++++++++++++ 6 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 tests/run-make/duplicate-profiler-builtins/dylib_a.rs create mode 100644 tests/run-make/duplicate-profiler-builtins/dylib_b.rs create mode 100644 tests/run-make/duplicate-profiler-builtins/main.rs create mode 100644 tests/run-make/duplicate-profiler-builtins/rmake.rs diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 20e75f0fdfd2..cb22aac4e952 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2972,9 +2972,11 @@ fn add_upstream_rust_crates( // We must always link crates `compiler_builtins` and `profiler_builtins` statically. // Even if they were already included into a dylib // (e.g. `libstd` when `-C prefer-dynamic` is used). + // HACK: `dependency_formats` can report `profiler_builtins` as `NotLinked`. + // See the comment in inject_profiler_runtime for why this is the case. let linkage = data[cnum]; let link_static_crate = linkage == Linkage::Static - || linkage == Linkage::IncludedFromDylib + || (linkage == Linkage::IncludedFromDylib || linkage == Linkage::NotLinked) && (crate_info.compiler_builtins == Some(cnum) || crate_info.profiler_runtime == Some(cnum)); diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 3c8ea1a9f43d..f36485cf0338 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -1024,12 +1024,19 @@ fn inject_profiler_runtime(&mut self, tcx: TyCtxt<'_>) { info!("loading profiler"); + // HACK: This uses conditional despite actually being unconditional to ensure that + // there is no error emitted when two dylibs independently depend on profiler_builtins. + // This is fine as profiler_builtins is always statically linked into the dylib just + // like compiler_builtins. Unlike compiler_builtins however there is no guaranteed + // common dylib that the duplicate crate check believes the crate to be included in. + // add_upstream_rust_crates has a corresponding check that forces profiler_builtins + // to be statically linked in even when marked as NotLinked. let name = Symbol::intern(&tcx.sess.opts.unstable_opts.profiler_runtime); let Some(cnum) = self.resolve_crate( tcx, name, DUMMY_SP, - CrateDepKind::Unconditional, + CrateDepKind::Conditional, CrateOrigin::Injected, ) else { return; diff --git a/tests/run-make/duplicate-profiler-builtins/dylib_a.rs b/tests/run-make/duplicate-profiler-builtins/dylib_a.rs new file mode 100644 index 000000000000..6833f3919994 --- /dev/null +++ b/tests/run-make/duplicate-profiler-builtins/dylib_a.rs @@ -0,0 +1 @@ +pub fn something() {} diff --git a/tests/run-make/duplicate-profiler-builtins/dylib_b.rs b/tests/run-make/duplicate-profiler-builtins/dylib_b.rs new file mode 100644 index 000000000000..b56f00f19d58 --- /dev/null +++ b/tests/run-make/duplicate-profiler-builtins/dylib_b.rs @@ -0,0 +1 @@ +pub fn something_else() {} diff --git a/tests/run-make/duplicate-profiler-builtins/main.rs b/tests/run-make/duplicate-profiler-builtins/main.rs new file mode 100644 index 000000000000..78677b37b5f7 --- /dev/null +++ b/tests/run-make/duplicate-profiler-builtins/main.rs @@ -0,0 +1,4 @@ +fn main() { + dylib_a::something(); + dylib_b::something_else(); +} diff --git a/tests/run-make/duplicate-profiler-builtins/rmake.rs b/tests/run-make/duplicate-profiler-builtins/rmake.rs new file mode 100644 index 000000000000..2dc53d0ee59d --- /dev/null +++ b/tests/run-make/duplicate-profiler-builtins/rmake.rs @@ -0,0 +1,29 @@ +// Checks that two dylibs compiled with code coverage enabled can be linked +// together without getting an error about duplicate profiler_builtins. + +//@ needs-profiler-runtime + +use run_make_support::{dynamic_lib_name, rustc}; + +fn main() { + rustc() + .crate_name("dylib_a") + .crate_type("dylib") + .arg("-Cinstrument-coverage") + .arg("-Cprefer-dynamic") + .input("dylib_a.rs") + .run(); + rustc() + .crate_name("dylib_b") + .crate_type("dylib") + .arg("-Cinstrument-coverage") + .arg("-Cprefer-dynamic") + .input("dylib_b.rs") + .run(); + rustc() + .crate_type("bin") + .extern_("dylib_a", dynamic_lib_name("dylib_a")) + .extern_("dylib_b", dynamic_lib_name("dylib_b")) + .input("main.rs") + .run(); +}