背景: 我试图提供一个包含在接口中的库,用于第三方应用程序(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和网络上发现了不同的提示,描述了链接顺序如何打破类似情况,但是所有内容都描述了冲突符号的所有静态链接或所有动态链接。
建议的解决方案
有人可以解释这些解决方案是否以及为何有效? (我的另一个问题是,我自己无法使用MATLAB进行测试,因为我无法访问安装它的机器。这就是为什么我也会问“提议的解决方案是否有效”
答案 0 :(得分:0)
首先,欢迎来到Linux符号插入的精彩世界;)
我认为您的图书馆会导出与其链接的Boost库中的所有符号(可以使用readelf --dyn-syms -W
进行验证)。在运行时,动态链接器会注意到这一点,而是将符号重新绑定到不同的版本的Boost(因为它恰好先加载,因此会覆盖库使用的符号)。
你想要做的是告诉gcc你不想导出Boost符号,或者你不希望它们在运行时是可插入的。有几个解决方案,最好是编译和链接-fvisibility=hidden
(注意Boost也需要与此标志链接)。这将阻止从库中导出任何函数,除非您使用__attribute__((visibility("hidden")))
明确标记它们(当然,您需要注释库接口函数)。
另一个选项是-Bsymbolic
- 这不会阻止来自库的虚假Boost导出,但至少会阻止动态链接器用其他库正好加载的随机版本的Boost函数覆盖它们。
现在留下问题。
将我的库升级到相同的升级版本
你可以这样做,但如果第三方在某些时候升级他们的Boost,这可能会破裂。
更改链接顺序(首先是boost,然后是-lmx -lmex)
没有多大意义......你试过吗?