We are distributing four different static libraries to customers:
- Library A: contains some common functions but also some embedded common libraries from linux which are not intended to be exposed to the customer, but to other of our libraries (so we need to export the symbols)
- Library B: has some unresolved symbols, to be found on library A
- Library C: has some unresolved symbols, to be found on library A
- Library D: has some unresolved symbols, to be found on library A
The issue is that some customers are also using other libraries in their projects (let's call it X) that include duplicated symbols from A, leading to unexpected crashes (but those may be a different version, so they cannot use A). We do not control these libraries (X), as they are prebuilt open source projects.
We cannot distribute all our libraries linked together (stripping the common libraries symbols) as this would be a waste of resources. Some customers only need C or B or D (together with A).
We cannot distribute B/C/D with locally static linked A because some customers may be using C and B. This would lead again to wasted resources as when they link their project they will end up with two copies of A.
Is there any way for our customers to tell the linker that when they are linking against X, A and B, the symbols in A should only be used when resolving undefined symbols in B? E.g.
lld -o myprogram main.o helper1.o -L. -lX -lA -lB
should use A only for the unresolved symbols in B, but never for the unresolved symbols in helper1.o. Is there any combination of flags to achieve so?
We already considered renaming or prefixing symbols in A, but all the libraries are huge and the process is not trivial. Also refactoring the code in A to include namespaces is far from trivial.
Tried different compiler flags, but none of them helped. I went through linker documentation and found nothing.
No.
A common solution to the problem you have is to prefix all non-static symbols in
libA.awith a unique prefix (e.g.your_company_A_foo()instead offoo()). This makes symbol collisions with other libraries exceedingly unlikely.And a common way to do that is to define your functions using a macro, e.g.
Above code defines
my_prefix_a_foo()andmy_prefix_a_bar()when compiled:During local testing / development you could even remove the prefix completely if desired.
This also makes it easy to ship "version 2" of
libA.aand guarantee that old (version 1)libB.awill never be linked with newlibA.a-- just change the prefix to include "v2" in it.Update:
libA.ato have a unique prefix. You just do that usingobjcopy --prefix-symbol=your_company_Ainstead of doing it at the source level.Example:
P.S.
You should never link any user-level code with
ld(orlld) on UNIX -- always use appropriate compiler driver (gccorg++orclang). The link command usinglddirectly is almost never correct (above link line certainly isn't), as you'll discover when some common feature (likeC++destructors or thread-local storage) mysteriously doesn't work.