我链接了两个不同的共享库。两个库都定义了一些共享名称但具有不同实现的符号。我不能让每个库使用自己的实现而不是另一个。
例如,两个库都定义了一个内部调用的全局函数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。
有没有办法让库总是更喜欢自己的实现,而不是任何其他库?
答案 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)
解决此问题的另一种方法是使用宏来更改名称空间。
<强>先决条件强>
<强>解决方案强>
-DLibNS=LibNSv1
,为另一个案例使用-DLibNS=LibNSv2
。在代码中使用库时,请根据当前情况定义宏;
#define LibNS LibNSv1
#include "my_lib.h"
#undef LibNS
使用此代替其他解决方案的原因
潜在问题
#include "my_lib.h"
可能使用宏来防止多重包含并取消定义它们以避免这可能导致许多不同的问题(库作者将来可能会更改宏名称,标题定义其他一些宏等等。)。 LI>
备注强>