LD: does --export-dynamic imply --whole-archive for a static lib if any of it's symbols are referenced?

Viewed 70

My main executable links with a static library whose symbols need to be available for dynamic libraries loaded through dlopen(). I understand that I need to use -Wl,--export-dynamic,--whole-archive flags to make it work. However there are many libraries specified on the link command, some maybe unused, and I'm having difficulties applying --whole-archive selectively to the needed library through cmake within the current build infrastructure. What I'm seeing is that if only -Wl,--export-dynamic is used and the executable calls a function in the static library of interest, then the whole library gets included to the same effect of specifying --whole-archive for it, which is exactly what I need. Can I rely on this behavior to implicitly impose --whole-archive on libs whose symbols are referenced by the executable?

1 Answers

What I'm seeing is that if only -Wl,--export-dynamic is used and the executable calls a function in the static library of interest, then the whole library gets included to the same effect of specifying --whole-archive for it, which is exactly what I need.

This isn't supposed to happen, and it is very likely that you are mis-interpreting what you see.

Example:

// foo.c
int foo() { return 42; }

// bar.c
int bar() { return 24; }

// main.c
int main() { return foo() - 42; }

gcc -w -c foo.c bar.c main.c
ar ruv libfoobar.a foo.o bar.o

gcc -Wl,--export-dynamic main.o -L. -lfoobar

nm a.out | egrep ' (foo|bar)'
000000000000113c T foo

As you can see, the whole libfoobar.a was not included in the executable. Contrast with:

gcc -Wl,--export-dynamic main.o -L. -Wl,--whole-archive -lfoobar -Wl,--no-whole-archive

nm a.out | egrep ' (foo|bar)'
0000000000001147 T bar
000000000000113c T foo

Update:

if I add a function foo1() to foo.c it is pulled in, but it also happens regardless if --export-dynamic is supplied.

That is expected: the linker doesn't "split" a single .o file -- you get all or nothing.

You can change this behavior by using -ffunction-sections (and -fdata-sections for a good measure) at compile time and -Wl,--gc-sections at link time.

The cost is increased .o size and longer link time. The benefit is smaller executable.

Related