Steinar H. Gunderson

Thu, 08 May 2014 - Static library linking behavior

A static library (an .a file) is, at its heart, nothing special—it's just a bunch of object files (.o files) in an archive, with an optional index. Thus, I've always treated them mentally the same to a bunch of object files, but it turns out there's an edge case where there is a difference between linking to an .a file and a bunch of .o files (even if you discount the fact that the .a file is a linker group and the .o files would need -( and -) around it to get the same effect).

The difference manifests itself when you are building a shared library (a .so file). For an .o file, the linker does what you'd expect; any symbol that has global linkage (ie., for C or C++: it's not marked as static or in an anonymous namespace) and has default visibility (which, unfortunately, means almost all symbols unless you're clever enough to use -fvisibility=hidden and explicitly mark your exports with __attribute__((visibility("default"))) or similar), will be exported in your shared library to external clients. This means, among others, that it will take up space because the name and a few other things need to be stored.

However, for an .a file, things are different! If you have a symbol in an .a file, and it's not used by anything from an .o file (directly or indirectly), the linker will silently just discard it as unused. It doesn't matter what visibility it has; it will just not be there. (To be honest, I haven't checked if this is on the level of a symbol, a section, an .o file within the library, or the entire .a file.)

The workaround for this is to add --whole-archive before the .a file in question (and presumably --no-whole-archive after it to negate the effect for the following ones), which will negate this behavior. However, I am unsure if it also has other effects, like messing with visibility, so beware.

To be honest, I think this is insane behavior, but given that so few people set visibility explicitly, I guess there would never be any pruning if the behavior were different (and ELF symbol visibility is a relatively new invention anyway), so I can understand why it is like that.

Of course, I figured this out the hard way. Poof, there goes a few hours of my life.

[05:40] | | Static library linking behavior

Steinar H. Gunderson <sgunderson@bigfoot.com>