如何编译链接版本无关Boost共享库的共享库?
问题场景
我要编译一个链接Boost共享库的共享库,当前CMakeLists.txt关键代码如下:
find_package(Boost REQUIRED COMPONENTS serialization) ... target_link_libraries(_omplpy PRIVATE ${Boost_LIBRARIES} ${otherdeps})
编译完成后用ldd命令检查依赖,发现Boost库被绑定到了具体版本(比如1.71.0),而其他系统库仅关联主版本:
h-ishida@stone-jsk:~/python/ompl-python-thin$ ldd build/_omplpy.cpython-38-x86_64-linux-gnu.so linux-vdso.so.1 (0x00007ffd34ca9000) libboost_serialization.so.1.71.0 => /lib/x86_64-linux-gnu/libboost_serialization.so.1.71.0 (0x00007f208012f000) libboost_filesystem.so.1.71.0 => /lib/x86_64-linux-gnu/libboost_filesystem.so.1.71.0 (0x00007f2080111000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f20800ee000) libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f207ff0c000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f207fdbd000) libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f207fda0000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f207fbae000) /lib64/ld-linux-x86-64.so.2 (0x00007f20812a6000)
不同Ubuntu发行版自带的Boost版本不同,导致编译出的_omplpy共享库无法跨发行版使用。我正尝试分发包含该共享库的Python Wheel包,但Wheel仅区分Python版本、操作系统和架构,无法适配特定Ubuntu发行版,因此碰到这个问题。
解决方案
方法1:使用CMake现代目标链接方式
CMake的find_package(Boost)会自动生成Boost::serialization这类目标,直接使用它们链接即可,CMake会自动处理依赖传递,且默认关联无版本的Boost库:
find_package(Boost REQUIRED COMPONENTS serialization) ... target_link_libraries(_omplpy PRIVATE Boost::serialization ${otherdeps})
这是最推荐的做法,能自动处理Boost组件的隐式依赖(比如serialization依赖的filesystem会被自动链接)。
方法2:手动构造无版本库名列表
如果要沿用旧的变量链接方式,可以手动生成无版本的Boost库名:
find_package(Boost REQUIRED COMPONENTS serialization) set(BOOST_LIBS_NO_VERSION "") foreach(COMPONENT ${Boost_FIND_COMPONENTS}) list(APPEND BOOST_LIBS_NO_VERSION "boost_${COMPONENT}") endforeach() ... target_link_libraries(_omplpy PRIVATE ${BOOST_LIBS_NO_VERSION} ${otherdeps})
这种方式会直接链接libboost_serialization.so,而非带版本后缀的.so.1.71.0文件。
方法3:通过链接器选项强制使用无版本库
如果前两种方法不生效,可以添加链接器选项,指定链接无版本的Boost库文件:
target_link_libraries(_omplpy PRIVATE ${Boost_LIBRARY_DIRS}/libboost_serialization.so ${Boost_LIBRARY_DIRS}/libboost_filesystem.so ${otherdeps} )
需要确保Boost_LIBRARY_DIRS正确指向Boost库所在目录。
方法4:静态编译Boost(彻底隔离版本)
如果允许静态链接,可以让Boost代码直接打包到你的共享库中,不再依赖系统的Boost动态库:
set(Boost_USE_STATIC_LIBS ON) find_package(Boost REQUIRED COMPONENTS serialization) ... target_link_libraries(_omplpy PRIVATE ${Boost_LIBRARIES} ${otherdeps})
此方法能彻底解决版本兼容问题,但会增加共享库体积,且需要确保系统中存在Boost静态库。
验证
修改CMakeLists.txt后重新编译,再次用ldd检查依赖,Boost库的关联应该变为无版本形式:
libboost_serialization.so => /lib/x86_64-linux-gnu/libboost_serialization.so (0x00007f208012f000)
内容的提问来源于stack exchange,提问作者HiroIshida

