Search code examples
c++cbuildunix-ar

Combining two static libraries into one dynamic library whilst avoiding multiple definitions


Note: This is not a duplicate question, because no other answer considers multiple definition challenges.

I am trying to combine two static libraries into one. (This works).

Then convert that static library into a dynamic library. (This does not work due to multiple definition error).

I have made a public repo with example sources.

Here are the key components:

return_zero.cpp

int return_zero() { return 0; }
int version() { return 0; }

return_one.cpp

int return_one() { return 1; }
int version() { return 1; }

Note how each library has it's own version function.

I can build each of these into their own static libraries. libreturn_zero.a and libreturn_one.a.

I can combine them into libreturn.a with the ar utility.

When I dump the symbols using nm utility:

$ nm -C libreturn.a 

return_one.cpp.o:
0000000000000000 T return_one()
000000000000000b T version()

return_zero.cpp.o:
0000000000000000 T return_zero()
000000000000000b T version()

Next, I try to convert this aggregate static library into a shared library.

I use a dummy source file, and link libreturn.a using the --whole-archive linker flag.

Here is what the link command looks like:

g++ -fPIC -shared -Wl,-soname,libreturn.so -o libreturn.so "dummy.cpp.o" -Wl,--push-state,--whole-archive libreturn.a -Wl,--pop-state

The above looks like what I want, but it fails because there are two definitions of version.

libreturn.a(return_zero.cpp.o): In function `version()':
return_zero.cpp:(.text+0xb): multiple definition of `version()'
libreturn.a(return_one.cpp.o):return_one.cpp:(.text+0xb): first defined here
collect2: error: ld returned 1 exit status
CMakeFiles/return-shared.dir/build.make:97: recipe for target 'libreturn.so' failed
make[2]: *** [libreturn.so] Error 1

I thought that by merging the two static libraries into one static library, the archiver would remove redundant symbols.

How do I go about merging static libraries into one shared library when there is a chance of symbol name conflicts?


Solution

  • You can't use the aggregate static library if you have code that calls both return_one() and return_zero() because you will get duplicate symbol problems with the version() functions.

    How will you decide which version() function you want to call if you link with the aggregate library?

    You're going to have to resolve that issue — and that probably means something like prefixing all the functions from return_zero.cpp with a prefix such as r0_ (or, in C++, placing them in namespace return_zero { … }), and — for symmetry, if for no better reason — prefixing all the functions from return_one.cpp with a prefix such as r1_ (or placing them in namespace return_one { … }). Your calling code would then use the prefixed names (or prefix the functions with the appropriate namespace name).