2011-06-30 84 views
40

我用两个不同的共享库链接。这两个库定义了一些共享名称但具有不同实现的符号。我不能让每个库都使用自己的实现。将两个共享库链接到一些相同的符号

例如,两个库都定义了一个全局函数bar(),它们都在内部调用。图书馆从foo1()调用它,图书馆二从foo2()调用它。

Lib1.so:

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

Lib2.so:

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

如果我对Lib1.so链接到我的应用程序,然后从Lib2.so的Lib1.so落实酒吧甚至被称为当致电foo2()。另一方面,如果我将我的应用程序链接到Lib2.so然后是Lib1.so,那么bar总是从Lib2.so中调用。

有没有办法让图书馆总是比其他图书馆更喜欢自己的实现?

回答

40

有几种方法来解决这个问题:

  • -Bsymbolic-Bsymbolic-functions给链接器。这具有全局影响:每个对可以解析为库中符号的全局符号(-Bsymbolic-functions的函数类型)的引用都解析为该符号。借此,您将失去使用LD_PRELOAD将内部库调用置于这些符号的能力。 这些符号仍然导出,所以它们可以从库外引用。

  • 使用版本脚本标识符号的当地图书馆,例如使用类似于:{local: bar;};并将--version-script=versionfile传递给链接器。 符号是不是已输出。

  • 与approppiate 能见度GCC info page for visibility),这将是马克符号要么隐藏的内部,或保护保护知名度符号导出为.protected隐藏符号不导出,并内部符号不导出,你妥协不是他们在图书馆外通过函数调用,即使是间接的指针。

您可以检查哪些符号与objdump -T出口。

+0

嗨,你能告诉我,这是否也适用于铛? –

3

您将不得不创建两个'包装'共享库,一个用于每个现有的库。每一个都应该建立一个--dynamic-list,它只列出几个定义API的非冲突符号。您还需要-Bsymbolic来避免任何全局组合。

使用合适的选项通过dlopen访问生成的库也可能不那么紧张。

+0

非常感谢!只是-Bsymbolic选项(使用-Wl选项传递给链接器)为两个共享库链接解决了我的问题。 – drewag

0

解决此问题的另一种方法是使用宏来更改名称空间。

先决条件

  • 所有元素(函数,类,全局变量,...)是在一个命名空间。
  • 该库不会严重依赖头中的宏。

解决方案

  • 当编译库,定义宏命名空间名称来定义它不同的东西。例如,如果命名空间是LibNS,则使用-DLibNS=LibNSv1作为一种情况,使用-DLibNS=LibNSv2作为另一种情况。
  • 在代码中使用库时,根据您当前的情况定义宏;

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

原因,而不是使用其他的解决方案

  • 当问题库中的头文件使用(至少部分地)(例如模板,内联,这... );当你将它们包含在可执行文件的代码中时,解析器不知道是否应该从Lib1.so或Lib2.so调用这些函数。您的编译器对其他解决方案的支持很差/不支持(我们的intel/amd 32/64位CPU不应该出现这种情况,但Google搜索似乎发现其他一些平台可能存在问题)。

潜在的问题

  • 这可能是有问题的可执行文件的一个CPP文件中使用这两种版本; #include "my_lib.h"可能使用宏来防止多重包含和定义它们以避免这可能会导致很多不同的问题(库作者可能会在未来更改宏名称,头文件定义一些其他宏等)。

注意