'What is the best way to solve multiple definitions introduced by a 3rd party library? [ELF and Mach-O]
Background
Imagine the situation: static library libR.a is written rust and it depends on libCXX0.a. Binary X depends on both libR.a and libCXX0.a and it is written in C++. Now we want to try something like clang++ X.o libR.a libCXX0.a -o X
. Well, this will result in multiple definitions because rustc is very happy to package the objects referenced in libCXX0.a into libR.a.
Here, libR.a, libCXX0.a, and X can be written in separate projects; therefore, it is not handy for X's maintainers to customize libR.a's linkage. Let us just assume that we do not want to modify the code of libR.a, libCXX0.a.
What I have already known:
I can try letting libR.a provides all the symbols. But there are situations that libR.a's libCXX0 and X's libCXX0 can be compiled with different versions (the case of boringssl and openssl decribed above), where we still want to libR and X to use their own copy separately.
I know that rustc (nightly) can now handle some modifiers like
-bundle,+whole-archive
(with which I can make libR.a not to contain objects from libCXX0.a), but the assumption is that we do not modify libR.Actually, I tried above approaches and it does not solve the problem: for example, X is using boringssl and R is using openssl, the required symbol set is exactly the same. So, discarding symbols from X or R can not finish the linking.I know this indicates a terrible control of the whole project, but this is what I am actually facing now and it may not be reasonable to rewrite the existing codebase
I can let linkers allow multiple definitions. But this may not be safe.
I can weaken symbols with
objcopy
. Again, this is not safe. And I remember that linux and darwin behave quite differently for weak symbols.I can make libR into a shared library with hidden visibility for internal symbols. But my goal is not to use a shared lib.
I can try
ar x
and then package the required objects. Again, this option acutally requires libR.a's libCXX0 and X's libCXX0 should be the same.(llvm-)objcopy
has--redefine-symbol(s)
(or--prefix-symbol
). Therefore, I can explicitly rename duplicated symbols. This is the potential fix; but it seems thatld
on darwin does not have similar functionality (--alias is just to create a new symbol referencing the old one)?(llvm-)objcopy
has--localize-symbol(s)
(andld
on darwin also has something like--unexported-symbols
). But the doc is not quite clear: I just hope to know what is the visbility range of a localized symbol: is it visible within a single object or within the whole archive?
Solution 1:[1]
You shouldn?t specify libraries on the Clang command line the same way you do input object files; you want to use clang++ X.o -l R -l CXX0
, and make sure the libraries are somewhere the compiler will look. That tells Clang that R and CXX0 are libraries and it should take symbols from them only as needed.
This can cause issues if libR.a
was compiled or linked with a different version of libCXX0.a
; there are various ways to deal with that, all of which have problems.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |