链接同一个库的2个不同版本时,如何选择所需的符号?

时间:2017-03-09 18:18:48

标签: gcc ld elf

背景: 我试图提供一个包含在接口中的库,用于第三方应用程序(MATLAB)。 我的问题是我的库和第三方应用程序都依赖于Boost库。

更糟糕的是,它们不仅依赖于两个不同版本的Boost,而且我的库是针对修补版本的Boost而构建的,它们是静态链接的。相反,第三方库与Boost动态链接。

这是我链接的方式(make -n的简化输出)

g++ -fPIC ${CPPFLAGS} -shared -lc -ldl ... -Wl,-h,mylib.so -o mylib.so \
${MYSTATICLIBS} \
-L${MATLABLIBSPATH} -lmx -lmex \
-L${MYBOOSTVERSIONPATH} -lboost_thread-gcc49-mt-1_52 ...

当我在MATLAB中运行库前,然后从我的内部函数调用错误的boost函数(并且一切都崩溃了)。

我天真的直觉是,因为我静态链接了我的Boost,所以从我的库中调用它们应该指向我的Boost,而来自libmx.so或libmex.so的调用将指向它们动态加载的依赖项。然而,这证明了我天真的直觉是非常错误的。

我在SO和网络上发现了不同的提示,描述了链接顺序如何打破类似情况,但是所有内容都描述了冲突符号的所有静态链接或所有动态链接。

建议的解决方案

  • 使用-Bsymbolic -Bsymbolic-functions
  • 将我的库升级到相同的升级版本
  • 更改链接顺序(首先是boost,然后是-lmx -lmex)
  • 卖掉我所有的世俗财产,在海滩上的某个地方买一个酒吧,试着以此为生。
  • 其他??

有人可以解释这些解决方案是否以及为何有效? (我的另一个问题是,我自己无法使用MATLAB进行测试,因为我无法访问安装它的机器。这就是为什么我也会问“提议的解决方案是否有效”

1 个答案:

答案 0 :(得分:0)

首先,欢迎来到Linux符号插入的精彩世界;)

我认为您的图书馆会导出与其链接的Boost库中的所有符号(可以使用readelf --dyn-syms -W进行验证)。在运行时,动态链接器会注意到这一点,而是将符号重新绑定到不同的版本的Boost(因为它恰好先加载,因此会覆盖库使用的符号)。

你想要做的是告诉gcc你不想导出Boost符号,或者你不希望它们在运行时是可插入的。有几个解决方案,最好是编译和链接-fvisibility=hidden(注意Boost也需要与此标志链接)。这将阻止从库中导出任何函数,除非您使用__attribute__((visibility("hidden")))明确标记它们(当然,您需要注释库接口函数)。

另一个选项是-Bsymbolic - 这不会阻止来自库的虚假Boost导出,但至少会阻止动态链接器用其他库正好加载的随机版本的Boost函数覆盖它们。

现在留下问题。

  

将我的库升级到相同的升级版本

你可以这样做,但如果第三方在某些时候升级他们的Boost,这可能会破裂。

  

更改链接顺序(首先是boost,然后是-lmx -lmex)

没有多大意义......你试过吗?