将两个共享库与一些相同的符号链接在一起

时间:2011-06-30 17:11:11

标签: c unix gcc shared-libraries dynamic-linking

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

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

Lib1.so:

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

Lib2.so:

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

如果我将我的应用程序链接到Lib1.so然后链接到Lib2.so即使调用foo2(),也会调用Lib1.so中的bar实现。另一方面,如果我将我的应用程序链接到Lib2.so然后链接到Lib1.so,那么总是从Lib2.so调用bar。

有没有办法让库总是更喜欢自己的实现,而不是任何其他库?

3 个答案:

答案 0 :(得分:44)

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

  • -Bsymbolic -Bsymbolic-functions 传递给链接器。这具有全局效果:对可以解析为库中符号的全局符号(-Bsymbolic-functions的函数类型)的每个引用都将解析为该符号。这样就无法使用LD_PRELOAD将内部库调用插入到这些符号中。 符号仍然会导出,因此可以从库外引用它们。

  • 使用版本脚本将符号标记为 local 到库中,例如使用类似{local: bar;};的内容并将--version-script=versionfile传递给链接器。 符号导出。

  • 使用适当的可见性GCC info page for visibility)标记符号,该符号将隐藏内部,或者保护 受保护 可见性符号导出为.protected 隐藏符号不会导出,并且 内部符号不会被导出,并且您不应该从库外部调用它们,甚至是通过函数指针间接调用它们。

您可以使用objdump -T检查导出的符号。

答案 1 :(得分:3)

您必须为每个现有的库创建两个“包装器”共享库。每个应该使用--dynamic-list构建,该列表仅列出一些定义API的非冲突符号。您还需要-Bsymbolic以避免任何全局组合。

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

答案 2 :(得分: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"可能使用宏来防止多重包含并取消定义它们以避免这可能导致许多不同的问题(库作者将来可能会更改宏名称,标题定义其他一些宏等等。)。 LI>

备注

  • 这并不意味着取代目前接受的答案(来自ninjalj;随意复制粘贴),但可以采用其他方法进行扩展。
  • 我发布此答案的主要原因是我今天遇到了这个问题,但由于代码存在于头文件中,答案没有帮助。
  • 我的来源:https://spin.atomicobject.com/2014/06/03/static-linking-c-plus-plus/