cmake install() 行为?如果给出此指令,为啥二进制会在 PWD 中查找

Posted

技术标签:

【中文标题】cmake install() 行为?如果给出此指令,为啥二进制会在 PWD 中查找【英文标题】:cmake install() behaviour? Why does the binary look in PWD if this directive is givencmake install() 行为?如果给出此指令,为什么二进制会在 PWD 中查找 【发布时间】:2021-12-27 23:40:35 【问题描述】:

我正在寻找关于在 cmake 中使用 install 指令时 linux 二进制文件中库搜索路径行为的说明。

为了上下文和简化,我们有一个二进制文件和一个库,它们位于同一目录中。

我们一直在缩小程序的一些异常行为范围,该程序适用于某些环境,但不适用于其他环境。当我们在 CMAKE 文件中添加以下行时,我们的问题就开始了:

set(CMAKE_SKIP_RPATH TRUE)

添加这一行后,程序不再运行,我们看到了这个错误:

binaryfile: error while loading shared libraries: mylibrary.so: cannot open shared object file: No such file or directory

我们最终将问题缩小到包含安装命令,我假设添加 SKIP_RPATH 有效地撤消了该命令。

经过大量研究以诊断代码在使用和不使用 RPATH 设置的情况下工作的原因后,我们发现了导致问题的原因,但根据二进制文件中的 rpath,我不明白为什么会发生这种情况。

CMakeLists.txt

cmake_minimum_required (VERSION 3.15)
project (binaryfile)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "$PROJECT_BINARY_DIR/runtime")
link_directories ($PROJECT_BINARY_DIR/../mylibrary)
link_libraries(mylibrary)
add_executable(binaryfile program.cpp)
# The following line allows the binary to find mylibrary in the same directory
install (TARGETS binaryfile DESTINATION bin)

构建后,移动 .so 文件从其构建位置到与二进制文件相同的文件夹,这是 ldd 和 readelf 的输出

使用 install 构建二进制文件 ...

readelf -d binaryfile
Dynamic section at offset 0xdc0 contains 30 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libmylibrary.so]
 0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libm.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x000000000000001d (RUNPATH)            Library runpath: [/home/dev/rpath-test/program/../mylibrary:]
 0x000000000000000c (INIT)               0x4004b8
 0x000000000000000d (FINI)               0x400654
 0x0000000000000019 (INIT_ARRAY)         0x600db0
 0x000000000000001b (INIT_ARRAYSZ)       8 (bytes)
 0x000000000000001a (FINI_ARRAY)         0x600db8
 0x000000000000001c (FINI_ARRAYSZ)       8 (bytes)
 0x0000000000000004 (HASH)               0x400298
 0x000000006ffffef5 (GNU_HASH)           0x4002c8
 0x0000000000000005 (STRTAB)             0x400380
 0x0000000000000006 (SYMTAB)             0x4002f0
 0x000000000000000a (STRSZ)              191 (bytes)
 0x000000000000000b (SYMENT)             24 (bytes)
 0x0000000000000015 (DEBUG)              0x0
 0x0000000000000003 (PLTGOT)             0x601000
 0x0000000000000002 (PLTRELSZ)           24 (bytes)
 0x0000000000000014 (PLTREL)             RELA
 0x0000000000000017 (JMPREL)             0x4004a0
 0x0000000000000007 (RELA)               0x400470
 0x0000000000000008 (RELASZ)             48 (bytes)
 0x0000000000000009 (RELAENT)            24 (bytes)
 0x000000006ffffffe (VERNEED)            0x400450
 0x000000006fffffff (VERNEEDNUM)         1
 0x000000006ffffff0 (VERSYM)             0x400440
 0x0000000000000000 (NULL)               0x0


ldd binaryfile
    linux-vdso.so.1 (0x00007fff6099e000)
    libmylibrary.so (0x00007fdff4d91000)
    libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00007fdff4a07000)
    libm.so.6 => /lib64/libm.so.6 (0x00007fdff46cf000)
    libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fdff44b7000)
    libc.so.6 => /lib64/libc.so.6 (0x00007fdff40fd000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fdff4f93000)

关于没有安装的二进制构建...

readelf -d binaryfile
Dynamic section at offset 0xdc0 contains 30 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libmylibrary.so]
 0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libm.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x000000000000001d (RUNPATH)            Library runpath: [/home/dev/rpath-test/program/../mylibrary]
 0x000000000000000c (INIT)               0x4004b8
 0x000000000000000d (FINI)               0x400654
 0x0000000000000019 (INIT_ARRAY)         0x600db0
 0x000000000000001b (INIT_ARRAYSZ)       8 (bytes)
 0x000000000000001a (FINI_ARRAY)         0x600db8
 0x000000000000001c (FINI_ARRAYSZ)       8 (bytes)
 0x0000000000000004 (HASH)               0x400298
 0x000000006ffffef5 (GNU_HASH)           0x4002c8
 0x0000000000000005 (STRTAB)             0x400380
 0x0000000000000006 (SYMTAB)             0x4002f0
 0x000000000000000a (STRSZ)              190 (bytes)
 0x000000000000000b (SYMENT)             24 (bytes)
 0x0000000000000015 (DEBUG)              0x0
 0x0000000000000003 (PLTGOT)             0x601000
 0x0000000000000002 (PLTRELSZ)           24 (bytes)
 0x0000000000000014 (PLTREL)             RELA
 0x0000000000000017 (JMPREL)             0x4004a0
 0x0000000000000007 (RELA)               0x400470
 0x0000000000000008 (RELASZ)             48 (bytes)
 0x0000000000000009 (RELAENT)            24 (bytes)
 0x000000006ffffffe (VERNEED)            0x400450
 0x000000006fffffff (VERNEEDNUM)         1
 0x000000006ffffff0 (VERSYM)             0x40043e
 0x0000000000000000 (NULL)               0x0

ldd binaryfile
        linux-vdso.so.1 (0x00007ffecd3b5000)
        libmylibrary.so => not found
        libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00007f7d9179f000)
        libm.so.6 => /lib64/libm.so.6 (0x00007f7d91467000)
        libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f7d9124f000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f7d90e95000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f7d91b29000)

如果 mylibrary.so 存在于 /home/dev/rpath-test/mylibrary 中,那么两个二进制文件都可以正常工作,并且还报告 libmylibrary.so 位于该目录中。我想了解的是允许“安装”版本在密码中找到库的关键是什么。

readelf 显示运行路径末尾有一个冒号。我猜这很重要 - 这是否意味着空字符串是运行路径的一部分,并且它推断 pwd?

期待对此的任何见解。

【问题讨论】:

请显示来自ldd实际输出,而不是它的简化版本。 深入挖掘,对问题的根源有了新的认识。我现在似乎对问题的实际根源有了清晰的认识,但仍在努力寻找行为的解释 【参考方案1】:

我猜这很重要

是的。

这是否意味着空字符串是运行路径的一部分

是的。

它推断密码?

种类:ld-linux 将使用库名称路径连接 RPATH 的每个 : 分隔组件,并尝试打开生成的路径。

对于/home/dev/rpath-test/program/../mylibrary:RPATHld-linux 将尝试打开/home/dev/rpath-test/program/../mylibrary/libmylibrary.so,如果失败则libmylibrary.so

如果libmylibrary.so存在于当前工作目录中,那么ld-linux会找到它。

【讨论】:

以上是关于cmake install() 行为?如果给出此指令,为啥二进制会在 PWD 中查找的主要内容,如果未能解决你的问题,请参考以下文章

[7] CMake总结 - 4 INSTALL

linux 怎么查看是不是安装cmake

CMAKE_INSTALL_PREFIX 的介子等价物是啥?

CMAKE_INSTALL_PREFIX如何设置默认值,并且保留从命令行覆盖的能力?

CMake + GoogleTest在小型库的集合中给出重新定义错误[重复]

cmake基础教程(13)cmake安装位置前缀CMAKE_INSTALL_PREFIX