Open nvzqz opened 6 hours ago
hey @madsmtm What do you think we have wrought upon ourselves today?
Fair chance this is because of linkers only pulling in object files from archives when a symbol in them is referenced unless --whole-archive
is used. In principle we should be generating a symbols.o
to ensure that all symbols are actually referenced, but maybe something is going wrong with that? Can you try adding #[no_mangle]
to CONSTRUCTOR
and/or constructor
just to see if that makes any difference?
I'd be surprised if no_mangle
worked but used(linker)
didn't?
It appears that #[no_mangle]
does not fix this.
Does -Clink-dead-code=yes
work? That disables --gc-sections
(as well as a couple of other things)
RUSTFLAGS='-Clink-dead-code=yes' cargo bench
also does not make the benchmark appear. Nor does it make the symbol in the __DATA,__my_values,regular,no_dead_strip
section appear in the final binary.
I think the issue is that the symbols.o
trick introduced in https://github.com/rust-lang/rust/pull/95604 just doesn't works at all with ld64
.
If I use RUSTFLAGS="-Clinker=rust-lld" cargo bench
, the code works as expected.
And RUSTFLAGS=-Clink-arg=-all_load cargo bench
does also work.
I'll see if I can figure out a way to make the symbols.o
trick work.
I tried this code:
Within the base crate, the [`#[divan::bench]`](https://docs.rs/divan/latest/divan/attr.bench.html) macro is used for benchmarking crate internals. Its generated code translates to something similar to: ```rs #[used] #[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func,mod_init_funcs")] #[cfg_attr(target_os = "linux", link_section = ".init_array")] #[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")] static CONSTRUCTOR: extern "C" fn() = constructor; extern "C" fn constructor() { // Register benchmark... } ``` This crate has a benchmark executable with only: ```rs fn main() { divan::main(); } ```I expected to see this happen: run the
add
benchmark and output the results. This runs correctly on Linux and Windows, but not macOS.Instead, this happened:
divan::main()
cannot find the benchmark because the pre-main
constructor function never ran.In order to make the benchmarks visible to the executable, the base crate needs to have one of its items appear to be used, such as
black_box
-ing any item from the crate.Note that this also happens with code like:
This issue occurs even when doing
extern crate my_crate
oruse my_crate as _
, which is a known workaround for similar issues.Meta
rustc --version --verbose
: