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

cmake install() behaviour? Why does the binary look in PWD if this directive is given

我正在寻找有关在 cmake 中使用安装指令时 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

的输出

在二进制构建中安装...

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 位于该目录中。我想了解的是允许 'install' 版本在密码中找到库的关键是什么。

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

期待对此有任何见解。

I'm guessing that this is significant

是的。

does it mean that an empty string is part of the runpath

是的。

and that it infers pwd?

种类: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会找到它。