【问题标题】:Why is CMake designed so that it removes runtime path when installing为什么 CMake 设计为在安装时删除运行时路径
【发布时间】:2015-12-04 20:32:48
【问题描述】:

我自己构建了我的共享库(例如,我使用了一个计算斐波那契数的库)并希望在我由CMake 构建的另一个 c++ 项目中使用它

假设共享库和头文件位于/path/to/my/lib,共享库libfib.so 位于/path/to/my/lib/lib,头文件fib.h 位于/path/to/my/lib/include,而我自己的项目位于/path/to/my/project

这是我原来的CMakeLists.txt

cmake_minimum_required(VERSION 3.2)
project(learn-lib)
set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
set(FIB_INCLUDE "${FIB_PREFIX}/include")
set(FIB_LIB "${FIB_PREFIX}/lib")
set(EXE mybin)
include_directories(${FIB_INCLUDE})
link_directories(${FIB_LIB})
add_executable(${EXE} main.cpp)
target_link_libraries(${EXE} fib)
install(TARGETS ${EXE} RUNTIME DESTINATION bin)

我使用这个脚本来构建和安装我的项目:

mkdir -p build_dir
cd build_dir
cmake -DFIB_PREFIX=/path/to/my/lib \
      -DCMAKE_INSTALL_PREFIX=/path/to/my/project \
      ..
make
make install
cd ..

现在,运行安装脚本后,我得到了两个可执行文件,一个在build_dir,一个在安装位置path/to/my/project/bin,当在build_dir 运行程序时,一切正常,但是运行安装的程序时,我得到:

./bin/mybin:加载共享库时出错:libfib.so:无法打开共享对象文件:没有这样的文件或目录

在 google 和 stackoverflow 上进行一些搜索后,我知道CMake 似乎在构建时删除了与可执行文件相关联的运行时搜索路径。我现在知道了两种解决方法:

  1. libfib.so所在的库路径添加到环境变量LD_LIBRARY_PATH
  2. set_target_properties(${EXE} PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE) 添加到我的CMakeLists.txt

所以,我的问题是:

  1. 为什么CMake会这样设计?安装时,为什么要从可执行文件中删除运行时路径,而不是将构建的可执行文件复制到安装目标或保留已安装程序的链接路径?
  2. 哪种方法是消除此问题的最佳实践(或是否有最佳实践)?设置环境或将set_target_properties(...) 添加到CMakeLists.txt 中?

【问题讨论】:

    标签: c++ hyperlink cmake shared-libraries


    【解决方案1】:

    您可能想查看CMake's RPATH handling settings

    这句话似乎与你的困境特别相关:

    默认情况下,如果您不更改任何与 RPATH 相关的设置,CMake 会将带有完整 RPATH 的可执行文件和共享库链接到构建树中所有使用的库。安装时,它会清除这些目标的 RPATH,因此它们安装时 RPATH 为空。

    您可以使用CMAKE_INSTALL_RPATH 变量设置为已安装的二进制文件设置的 RPATH,例如:

    SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
    

    您还可以在安装过程中禁用 RPATH 剥离:

    SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
    

    【讨论】:

    • 我发现如果我在add_executable(${EXE} main.cpp)之后添加SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE),cmake仍然会剥离运行时路径,而set_target_properties(${EXE} PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE)无论在CMakeLists.txt中的位置都将始终有效
    • 我在 Mac OS 上发现了与 @Alaya 相同的内容。 CMake 中的 RPATH 处理似乎关闭了,文档也不是特别有用。
    • CMAKE_INSTALL_RPATH_USE_LINK_PATH 是全局 cmake 设置,而 INSTALL_RPATH_USE_LINK_PATH 是每个目标。我认为这就是@Alaya 发现的不同之处。
    【解决方案2】:

    我只想回答问题 1。为什么这样做。 Alex 已经发布了如何改变这种行为的解决方案。

    原因是当您构建它时,您真的想使用构建脚本在您的机器上看到的库。如果您为您的应用程序构建了一整套库,那么您肯定不会误以为它们没有被库选中。因此,使用库的完整 rpath 是有意义的。此外,您永远不会在编译和调试和运行之间移动您的应用程序。

    但是在安装时,unix 世界中的常见情况是使用共享的 /usr/lib 和 /usr/local/lib 目录。它们通常被拾取(除非使用 LD_LIBRARY_PATH),这通常是你想要的。

    正如您从我的措辞中看到的那样,这一切都是一团糟,因为它包含了许多隐含的决定,您如何组织构建和部署。这就是为什么曾经只在 Windows 上流行的术语“DLL 地狱”在被更广泛使用时转移到 Unix 的原因之一。没有技术解决方案,因为它不是技术问题(该部分已解决)。这是一个组织问题,CMake 必须决定默认情况下它在平台上支持的一种风格。恕我直言,他们明智地选择了。

    【讨论】:

    • CMake 把它弄得一团糟。请注意,他们关于链接、rpath 等的文档甚至都没有提到 ldconfig,因此 CMake 用户被引导到花园小路上,相信必须将 /usr/local/lib 放入 LD_LIBRARY_PATH :-)跨度>
    • 没有问题,链接在 Unix 上是一团糟,在任何编程课上都没有教过。在部署之前一切正常。现在市场上有一个新的职位描述被定义为“部署工程师”,而不是 DevOps。
    • GNU autoconf、libtool 等。在 Unix 上管理工作足够好,而 cmake 甚至无法获得 cmake --find-package 正确:P
    • 好像在 Windoze 上的链接更好——如果你问我,那就更糟了……
    猜你喜欢
    • 2016-12-19
    • 2020-08-08
    • 1970-01-01
    • 2011-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多