CMake 项目找不到共享库

CMake project fails to find shared library

我正在使用 CMake 构建跨平台项目。目前,我正在尝试 运行 它 Linux。我最近为 运行ning 测试添加了一个项目,但它不会 运行 因为它找不到共享库之一,特别是 libtbbmalloc.so.2:

/tests: error while loading shared libraries: libtbbmalloc.so.2: cannot open shared object file: No such file or directory`

当我在可执行文件上 运行 ldd 时,我得到以下信息:

linux-vdso.so.1 (0x00007fffeb572000)
libtbbmalloc_proxy.so.2 => /home/username/dev/tbb/libtbbmalloc_proxy.so.2 (0x00007f50afe00000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f50afa70000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f50af6d0000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f50af4b0000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f50af0a0000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f50aee90000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f50aec70000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f50aea60000)
/lib64/ld-linux-x86-64.so.2 (0x00007f50b0400000)
libtbbmalloc.so.2 => not found

我的测试项目的 CMakeLists.txt 如下所示:

set(test_sourcefiles main_tests.cpp)

add_executable(tests ${test_sourcefiles})

target_link_libraries(tests Catch2::Catch2 MyLib)

MyLib 使用 tbb,我想这就是我的可执行文件 (tests) 搜索它的原因。当在 MyLib 上使用 运行ning ldd 时,它会找到库 (libtbbmalloc.so.2):

(removed some output for readability)
libtbbmalloc_proxy.so.2 => /home/username/dev/tbb/libtbbmalloc_proxy.so.2 (0x00007f9af8110000)
libtbbmalloc.so.2 => /home/username/dev/tbb/libtbbmalloc.so.2 (0x00007f9ac4eb0000)

我已经尝试在我的 tests/CMakeLists.txt target_link_libraries(${project} /home/username/dev/tbb/libtbbmalloc.so.2) 中专门添加 libttbbmalloc.so.2,但没有任何区别。

如果我将 /home/username/dev/tbb/ 添加到 LD_LIBRARY_PATH,程序 运行s 和 ldd 报告找到 libtbbmalloc.so.2。

关于我可能做错了什么的任何想法,以及如何在不设置 LD_LIBRARY_PATH 的情况下让我的程序达到 运行?

更新:我发现使用 chrpath -l name-of-executable 可以打印 runpath/rpath。在我的可执行文件上使用此工具时,看起来带有 libtbbmalloc.so.2 的文件夹已添加到 运行path,但程序仍然不会 运行:

larjr@DESKTOP:~/dev/project/build/tests$ chrpath -l tests
tests: RUNPATH=/home/larsjr/dev/project/build/MyLib:/home/username/dev/tbb

我相信您要在可执行文件上设置运行时路径:

set_target_properties(tests PROPERTIES
    INSTALL_RPATH "<your path to libs>"
    BUILD_WITH_INSTALL_RPATH 1
)

INSTALL_RPATH

Normally CMake uses the build tree for the RPATH when building executables etc on systems that use RPATH. When the software is installed the executables etc are relinked by CMake to have the install RPATH. If this variable is set to true then the software is always built with the install path for the RPATH and does not need to be relinked when installed.

BUILD_WITH_INSTALL_RPATH

Normally CMake uses the build tree for the RPATH when building executables etc on systems that use RPATH. When the software is installed the executables etc are relinked by CMake to have the install RPATH. If this variable is set to true then the software is always built with the install path for the RPATH and does not need to be relinked when installed.

您遇到的问题听起来与共享库直接和间接链接的搜索路径有关。 CMake 可能会使用新的 ld RUNPATH 变量构建,该变量仅适用于直接依赖项,其中 RPATH 将递归地适用于所有间接依赖项。如 post 底部的代码片段所示,这可能取决于您的 GCC 版本。要检查您的可执行文件是否使用 RPATH 或 RUNPATH,运行:

$ readelf -d ./executable

并在依赖项之后找到库 rpath / 运行path 行。 ie/eg:可能显示以下任一情况:

a) 0x000000000000001d (RUNPATH)            Library runpath: [/some/dir/lib]
b) 0x000000000000001d (RPATH)              Library rpath:   [/some/dir/lib]

你展示了你使用了命令 chrpath -l ./executable,它实际上吐出:

larjr@DESKTOP:~/dev/project/build/tests$ chrpath -l tests

tests: RUNPATH=/home/larsjr/dev/project/build/MyLib:/home/username/dev/tbb

这里说 "RUNPATH" 是非递归的 - 那是你的错误。

请参阅这个优秀的 github 问题,其中成员正在讨论与 CMake 的间接链接问题,强烈建议阅读所有内容。它有一个关于依赖关系及其搜索路径的很好的例子。 https://github.com/conan-io/conan/issues/2660

有关可能导致此问题的新旧链接器行为的片段 'issue':

The problem you are experiencing in conan-deptest (excellent isolated case, by the way!) is the behaviour that you are documenting, between DT_RPATH and DT_RUNPATH. It is CMake (and not conan), that passes the -rpath flag with the correct paths to the dependent libraries, when building the executable. The problem is that newer versions of the linker in some platforms, emit DT_RUNPATH where they used to emit DT_RPATH. Indeed this is the case as readelf -d is listing the RUNPATH tag.

还有另一个 Whosebug post,其中用户询问 LD/GCC 中的这种行为变化:

柯南成员进一步阐述了如何改变这种行为:

The way to replicate this behaviour on versions of the linker that emit RUNPATH instead, is to pass the --disable-new-dtags flag to the linker.

以及生成的 cmake:

target_link_libraries(target "-Wl,--disable-new-dtags")

现在,如果您重建并检查可执行文件上的 readelf -d,您应该会看到 RPATH 标记。你可以 运行:

env LD_DEBUG=files,libs ./executable

查看 RPATH 被传递到每个依赖项的搜索路径中:

31658:  file=libbar.so.1 [0];  needed by /home/user/projectA/lib/libfoo.so.2.5 [0]
31658:  find library=libbar.so.1 [0]; searching
31658:   search path=/home/user/projectA/lib        (RPATH from file ./executable)
31658:    trying file=/home/user/projectA/lib/libbar.so.1

希望这能解决您的问题!

奖金: Link 转到有关共享库的教程。在文章的底部显示 运行path vs rpath + origin! https://amir.rachum.com/blog/2016/09/17/shared-libraries/