You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 18:25:39