如何使用Conan打包二进制项目?解决共享库加载失败问题
问题描述
包使用方无法加载该包内二进制文件依赖的共享库。
find_package(MyThirdParty REQUIRED) # MyThirdParty 是通过Conan安装的 find_program(binary_paty MyThirdParty REQUIRED) execute_process(COMMAND ${binary_path} COMMAND_ERROR_IS_FATAL ANY)
上述execute_process命令会执行失败,原因是找不到MyThirdParty依赖的共享库,需要明确第三方二进制项目的正确打包方式。
最小复现示例
第三方项目CMakeLists.txt内容
file(WRITE Library.hh "void Func();") file(WRITE Library.cc "void Func() {}") add_library(Library SHARED Library.hh Library.cc) file(WRITE Main.cc "#include \"Library.hh\"\nint main() { Func(); }") add_executable(MyThirdParty Main.cc) target_link_libraries(MyThirdParty PRIVATE Library) install(TARGETS MyThirdParty Library EXPORT MyThirdPartyConfig) install(EXPORT MyThirdPartyConfig NAMESPACE MyThirdParty:: DESTINATION lib/cmake/MyThirdParty )
Conan打包脚本conanfile.py实现
from conans import ConanFile, CMake, tools class MyThirdPartyConan(ConanFile): name = "MyThirdParty" version = "1.0.0" settings = "os", "compiler", "build_type", "arch" def source(self): tools.download( filename = "CMakeLists.txt", url = "<上游CMakeLists.txt下载地址>") def build(self): cmake = CMake(self) cmake.configure() cmake.build() def package(self): cmake = CMake(self) cmake.install()
使用方CMake代码
find_package(MyThirdParty REQUIRED) find_program(binary_paty MyThirdParty REQUIRED) execute_process(COMMAND ${binary_path} COMMAND_ERROR_IS_FATAL ANY)
使用方conanfile.txt配置
[requires] MyThirdParty/1.0.0@Ghasem/Test [generators] cmake_find_package
使用方通过Conan引入该包后执行CMake流程失败,原因是第三方二进制依赖的共享库无法找到:当CMake尝试执行MyThirdParty二进制文件时,会因找不到libLibrary.so文件报错。
运行环境
- 操作系统:
Fedora 35 - 内核版本:
Linux 5.18.9-100.fc35.x86_64 - 编译器:
GCC 11.3.1 20220421 - CMake版本:
3.22.2 - Conan版本:
1.47.0
解决方案
问题本质是Linux ELF格式可执行文件默认不会自动查找同安装目录下的依赖共享库,当前打包流程没有给可执行文件配置正确的依赖查找路径,运行时自然找不到同包内的libLibrary.so。
优先选择第一种修复方式,对使用方完全无侵入:
- 给安装的可执行文件设置相对RPATH
修改上游CMakeLists.txt,在所有目标定义前添加如下配置:
这两行配置的作用是:可执行文件安装后,会自动从自身所在目录的上级lib目录查找依赖库——Conan安装包默认把可执行文件放在set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib") set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)bin目录、共享库放在lib目录,$ORIGIN是ELF格式内置的变量,代表可执行文件自身的所在路径,配置后无论包被Conan缓存到哪个路径,可执行文件都能准确定位到同包内的依赖库,不需要使用方做任何额外配置。
如果需要兼容macOS,把RPATH值换成@loader_path/../lib即可;Windows默认会查找可执行文件同目录下的DLL,不需要额外配置。
如果没法修改上游CMake代码,可以用第二种兼容方案:
- 通过Conan生成运行时环境配置
让使用方在conanfile.txt的generators里添加VirtualRunEnv,Conan会自动生成环境激活脚本,把所有依赖包的lib目录加入LD_LIBRARY_PATH,使用方执行CMake前先运行source conanrun.sh(Windows下是conanrun.bat)激活环境,再执行构建流程就能正常找到依赖库。这种方案需要使用方额外执行激活步骤,不如第一种方案干净。
额外注意事项:
- 打包时要确认所有依赖的共享库都被正确install到包的lib目录,不要出现漏装
- 不要硬编码绝对路径作为RPATH,否则包迁移路径后会直接失效
- 如果包内的可执行文件是提供给使用方的构建期工具,必须优先用RPATH方案,保证开箱即用,不要给使用方增加额外配置成本。
内容的提问来源于stack exchange,提问作者Ghasem Ramezani
相关产品推荐
相关产品推荐

