【问题标题】:CMake: Two libraries, same location of shared objects, one is not found at runtimeCMake:两个库,共享对象的相同位置,在运行时找不到一个
【发布时间】:2020-07-14 14:52:46
【问题描述】:

我正在尝试构建一个依赖于外部库 libext 的 C 库 libmylibmylibext 都使用 CMake。此外,libext 实际上产生了两个共享对象,libext1.solibext2.so,这两个共享对象都是 libmy 所需要的。

首先,我在${CMAKE_BINARY_DIR}/ext 下安装带有自定义CMake 模块的libext。这个过程是成功的,我最终得到了以下树:

${CMAKE_BINARY_DIR}
└── ext
    └── lib
        ├── libext1.so
        └── libext2.so

为了测试libmy,我在目标mytest下构建了一些测试用例,它们链接到共享对象libmy.solibext1.solibext2.so

所有目标的构建过程成功结束。但是当我尝试运行mytest 时,我得到了著名的无法打开共享对象文件:没有这样的文件或目录,但仅适用于libext1.so,而libext2.so 被正确找到。然而,非常好奇的是,libext1.solibext2.so 都位于同一路径中,而libext2.so 确实在运行时链接成功。这是LD_DEBUG=libs mytest 打印的内容:

10703:  find library=libext2.so [0]; searching
10703:   search path=/usr/local/lib:/home/user/mylib/build/ext/lib:x86_64:      (RUNPATH from file src/test/mytest)
10703:    trying file=/usr/local/lib/libext2.so
10703:    trying file=/home/user/mylib/build/ext/lib/libext2.so
10703:      
10703:  find library=libext1.so [0]; searching
10703:   search cache=/etc/ld.so.cache
10703:    trying file=/usr/local/lib/libext1.so
10703:   search path=/lib/x86_64-linux-gnu/tls/haswell/x86_64:[...truncated long search path (/home/user/mylib/build/ext/lib is not here)...]:/usr/lib      (system search path)
10703:    trying file=/lib/x86_64-linux-gnu/tls/haswell/x86_64/libext1.so
          ...
10703:    trying file=/usr/lib/haswell/libext1.so
10703:    trying file=/usr/lib/x86_64/libext1.so
10703:    trying file=/usr/lib/libext1.so
10703:  
src/test/myest: error while loading shared libraries: libext1.so: cannot open shared object file: No such file or directory

因此,出于某种原因,要查找 libext1.so,使用系统搜索路径(不包括外部库的路径),而对于 libext2.so,使用 RUNPATH(它确实有正确的路径)。

我构建外部库的 CMake 模块基本上是这样做的:

include(ExternalProject)
set(EXTERNAL_INSTALL_LOCATION ${CMAKE_BINARY_DIR}/ext)

ExternalProject_Add(extproject
  GIT_REPOSITORY https://github.com/ext/ext.git
  CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${EXTERNAL_INSTALL_LOCATION})

include_directories(${EXTERNAL_INSTALL_LOCATION}/include)
link_directories(${EXTERNAL_INSTALL_LOCATION}/lib)

set(EXT_INCLUDE_DIR ${EXTERNAL_INSTALL_LOCATION}/include)
set(EXT1_LIBRARY ext1)
set(EXT2_LIBRARY ext2)

而构建mytest 的CMakeLists.txt 文件包含:

add_executable(mytest mytest.cpp)
target_include_directories (mytest
  PUBLIC
  ${EXT_INCLUDE_DIR})
target_link_libraries(mytest
  my
  ${EXT1_LIBRARY}  
  ${EXT2_LIBRARY})
add_test(NAME mytest COMMAND mytest)

免责声明:我对场景进行了简化,因为库相当大,并且构建过程包含其他几个组件。但希望这已经足够了。

【问题讨论】:

    标签: cmake


    【解决方案1】:

    这个问题有点微妙。

    原来libext2.so 在内部也依赖于libext1.soLD_LEBUG=libs mytest没有显示这些信息,所以我以为libext1.so的依赖直接来自libmy.so,确实也需要它。但是,运行 LD_DEBUG=all mytest 输出:

    11540:  file=libext1.so [0];  needed by /home/user/mylib/build/external/lib/libext2.so [0]
    

    这就是为什么为libmy 的所有目标设置 RPATH 或 RUNPATH 没有任何效果,我猜是因为libext 的 RPATH/RUNPATH 是由该项目的 CMake 在内部设置的,因此独立于我构建libmy的方式。

    由于我不想修改 libext 的 CMake 脚本(我想使用该项目的默认脚本),我所能做的(afaik)就是将额外的参数传递给 ExternalProject_Add 命令。以下作品:

    include(ExternalProject)
    set(EXTERNAL_INSTALL_LOCATION ${CMAKE_BINARY_DIR}/ext)
    
    ExternalProject_Add(extproject
      GIT_REPOSITORY https://github.com/ext/ext.git
      CMAKE_ARGS 
      -DCMAKE_INSTALL_PREFIX=${EXTERNAL_INSTALL_LOCATION}
      -DCMAKE_INSTALL_RPATH=${EXTERNAL_INSTALL_LOCATION}/lib)
    
    include_directories(${EXTERNAL_INSTALL_LOCATION}/include)
    link_directories(${EXTERNAL_INSTALL_RPATH}/lib)
    
    set(EXT_INCLUDE_DIR ${EXTERNAL_INSTALL_LOCATION}/include)
    set(EXT1_LIBRARY ext1)
    set(EXT2_LIBRARY ext2)
    

    (请注意 ExternalProject_Add 指令的额外 -DCMAKE_INSTALL_RPATH=${EXTERNAL_INSTALL_LOCATION}/lib 参数。)

    设置 RPATH 以便 libext2.so 可以在运行时找到 libext1.so

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-02
      • 1970-01-01
      • 1970-01-01
      • 2018-11-09
      • 2019-04-02
      • 2021-08-19
      • 1970-01-01
      • 2015-10-03
      相关资源
      最近更新 更多