Conan包共享库查找异常:libDependent无法自动定位问题咨询
- 项目包含两个目标(子目录):共享库
libMain.so依赖另一个共享库libDependent.so,CMake配置如下:
add_library( Main SHARED ${cpp} ) target_link_libraries(Main Dependent )
- 将这两个库打包为Conan包,存放在
/package/CONANPACKAGEID/lib目录下,包内包含FindMainPackage.cmake,核心代码如下:
find_library (Main_LIBRARIES Main Main_d HINTS ${Main_ROOT_DIR} ${CMAKE_INSTALL_PREFIX} PATH_SUFFIXES lib )
- 在主项目中通过
find_package(Main)链接第三方库General,两种写法均生效:
写法1:
target_link_libraries(General ${Main_LIBRARIES} )
写法2:
target_link_libraries(General Main )
- 将General库链接到Google Test测试二进制:
target_link_libraries( Test GTest::GTest General )
- 当设置
LD_LIBRARY_PATH为${CONAN_LIB_DIRS_MAIN}(即/package/CONANPACKAGEID/lib)并从构建目录运行二进制时,所有库均可正常找到; - 若不设置上述环境变量,运行时会报错:
error while loading shared libraries: libDependent.so: cannot open shared object file: No such file or directory
使用ld命令检查二进制,结果显示:
libMain.so /.conan/data/package/CONANPACKAGEID/lib/libMain.so (0x00007c815718f000) libDependent.so => **not found**
若手动将General库与Dependent库链接:
target_link_libraries(General Main Dependent )
则运行正常,ld命令显示libDependent.so位于Conan包的lib目录下。
问题1:为何二进制能识别libMain.so在Conan包目录中(该目录不在ldconfig的系统库路径中)?
因为链接General库时,CMake使用find_library找到的libMain.so绝对路径直接写入了测试二进制的动态链接表(DT_NEEDED)。从ld的输出也能看到,libMain.so后面跟着完整的Conan包路径,而非仅库名,所以运行时无需依赖系统路径或LD_LIBRARY_PATH就能定位到它。
问题2:为何无法自动找到libDependent.so?
一是libMain.so自身的动态链接信息里只记录了libDependent.so的库名,没有写入绝对路径。当加载libMain.so时,动态链接器会按默认规则(系统库路径、LD_LIBRARY_PATH)查找,但该库不在系统路径且未设置环境变量,因此找不到。
二是FindMainPackage.cmake仅导出了Main_LIBRARIES(指向libMain.so的绝对路径),未将libDependent.so的依赖关系传递给主项目。主项目只链接Main时,CMake不知道它还依赖Dependent,也就不会把libDependent.so的路径信息写入测试二进制的链接表。
问题3:如何正确解决该问题?
有三种可靠的解决方式:
方式1:修复Conan包的CMake配置,传递完整依赖链
修改FindMainPackage.cmake,不仅导出Main的库路径,还要导出其依赖Dependent,用CMake导入目标规范传递依赖:
find_library(Main_LIBRARIES Main Main_d HINTS ${Main_ROOT_DIR} ${CMAKE_INSTALL_PREFIX} PATH_SUFFIXES lib ) find_library(Dependent_LIBRARIES Dependent Dependent_d HINTS ${Main_ROOT_DIR} ${CMAKE_INSTALL_PREFIX} PATH_SUFFIXES lib ) add_library(Main::Main UNKNOWN IMPORTED) set_target_properties(Main::Main PROPERTIES IMPORTED_LOCATION ${Main_LIBRARIES} ) add_library(Main::Dependent UNKNOWN IMPORTED) set_target_properties(Main::Dependent PROPERTIES IMPORTED_LOCATION ${Dependent_LIBRARIES} ) # 让Main目标自动携带Dependent依赖 target_link_libraries(Main::Main INTERFACE Main::Dependent)
主项目中使用target_link_libraries(General Main::Main),CMake会自动添加Dependent的依赖,并将绝对路径写入二进制。
方式2:给libMain.so设置RPATH
在构建libMain.so的CMake配置中添加RPATH,让它自动从自身所在目录查找依赖:
add_library(Main SHARED ${cpp}) target_link_libraries(Main Dependent) # 设置RPATH为当前库所在目录(两个库在同一目录时生效) set_target_properties(Main PROPERTIES INSTALL_RPATH "$ORIGIN" )
这样libMain.so被加载时,会自动从自身所在的Conan包lib目录查找libDependent.so,无需依赖环境变量或主项目的额外配置。
方式3:使用Conan的自动依赖管理
如果使用Conan 2.x,在Conan recipe中正确声明依赖,让Conan自动生成CMake导入目标传递完整依赖链。示例conanfile.py:
class MainRecipe(ConanFile): name = "Main" version = "1.0.0" settings = "os", "compiler", "build_type", "arch" exports_sources = "src/*" def build(self): cmake = CMake(self) cmake.configure(source_folder="src") cmake.build() def package(self): self.copy("*.so", dst="lib", keep_path=False) self.copy("FindMainPackage.cmake", dst="lib/cmake/Main") def package_info(self): self.cpp_info.libs = ["Main", "Dependent"] self.cpp_info.set_property("cmake_file_name", "Main") self.cpp_info.set_property("cmake_target_name", "Main::Main")
主项目通过find_package(Main)后,Main::Main目标会自动包含Dependent的依赖,链接时CMake会处理好所有路径。
内容的提问来源于stack exchange,提问作者Ieshir

