Linking two shared libraries with some of the same symbols

28,272

Solution 1

There are several ways to solve this:

  • Pass -Bsymbolic or -Bsymbolic-functions to the linker. This has a global effect: every reference to a global symbol (of function type for -Bsymbolic-functions) that can be resolved to a symbol in the library is resolved to that symbol. With this you lose the ability to interpose internal library calls to those symbols using LD_PRELOAD. The symbols are still exported, so they can be referenced from outside the library.

  • Use a version script to mark symbols as local to the library, e.g. use something like: {local: bar;}; and pass --version-script=versionfile to the linker. The symbols are not exported.

  • Mark symbols with an approppiate visibility (GCC info page for visibility), which will be either hidden, internal, or protected. protected visibility symbols are exported as .protected, hidden symbols are not exported, and internal symbols are not exported and you compromise not to call them from outside the library, even indirectly through function pointers.

You can check which symbols are exported with objdump -T.

Solution 2

You will have to create two 'wrapper' shared libs, one for each of your existing libs. Each one should be built with a --dynamic-list that lists only a few non-conflicting symbols that define an API. You will also need -Bsymbolic to avoid any global combination.

It might be less stressful to access the resulting libs via dlopen with suitable options, as well.

Solution 3

Another way to solve this problem is using macro to change namespace.

Prerequisites

  • All elements (functions, classes, global variables, ...) are in a namespace.
  • The library doesn't heavily depend on macros in headers.

Solution

  • When compiling the library, define macro with namespace name to define it to something different. For example if the namespace is LibNS, use -DLibNS=LibNSv1 for one case and -DLibNS=LibNSv2 for the other.
  • When using libraries in the code, define macro according your current situation;

    #define LibNS LibNSv1
    #include "my_lib.h"
    #undef LibNS
    

Reasons why use this instead of other solutions

  • When the problematic library is used (at least partially) in header files (for example templates, inlines, ...); when you include them in your executable's code, resolver doesn't have idea whether these functions should be called from Lib1.so or Lib2.so.
  • Your compiler has poor/none support for other solutions (shouldn't happen with our intel/amd 32/64 bit CPUs, but it seems from Google search that some other platforms might have the problem).

Potential problems

  • It might be problematic to use both version in one cpp file of your executable; #include "my_lib.h" probably uses macro to protect against multiple-inclusion and undefining them to avoid this might cause lots of different problems (library author might change the macro name in the future, header defines some other macros, etc.).
  • The name LibNS might be used for something else in the library (variable, function, etc.); in that case, this name will be also changed to LibNSv1 or LibNSv2. This might lead to other problems depending on the library and how it's used.

Notes

  • This isn't meant to replace currently accepted answer (from ninjalj; feel free to copy-paste it), but extend it with another approach.
  • Main reason why I posted this answer is that I encountered this problem today, but answer didn't help due to problematic code being in header files.
  • My source: https://spin.atomicobject.com/2014/06/03/static-linking-c-plus-plus/
Share:
28,272

Related videos on Youtube

drewag
Author by

drewag

I am on this forum to learn, and to help others! I thrive on collaboration and sharing of ideas! I am passionate about design, interface, and coding. Interface for me includes the obvious things like user interface and graphics, but also design patterns, API's and on occasion documentation and coding standards :). I work for a dev shop based in Denver, CO called Chronos Interactive as well as on my own app business called Learn Brigade. Check out my Blog Check out my Stack Overflow Career Page Follow me on Drewag

Updated on July 14, 2020

Comments

  • drewag
    drewag almost 4 years

    I link with two different shared libraries. Both libraries define some symbols that share a name but have different implementations. I can't make each library use its own implementation over the other.

    For example, both libraries define a global function bar() that each calls internally. Library one calls it from foo1() and library two calls it from foo2().

    Lib1.so:

    T bar
    T foo1()     // calls bar()
    

    Lib2.so:

    T bar
    T foo2()     // calls bar()
    

    If I link my application against Lib1.so and then Lib2.so the bar implementation from Lib1.so is called even when calling foo2(). If on the other hand, I link my application against Lib2.so and then Lib1.so, then bar is always called from Lib2.so.

    Is there a way to make a library always prefer its own implementation above any other library?

  • drewag
    drewag almost 13 years
    Thanks so much! Just the -Bsymbolic option (passed to the linker using the -Wl option) for both shared library linkings solved the problem for me.
  • Max Raskin
    Max Raskin almost 7 years
    Hi, can you tell me please whether this applies to clang as well?