为什么设计CMake以便在安装时删除运行时路径

Ala*_*aya 13 c++ cmake shared-libraries hyperlink

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

比方说,位于共享库和头文件/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)
Run Code Online (Sandbox Code Playgroud)

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

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 ..
Run Code Online (Sandbox Code Playgroud)

现在,在运行安装脚本之后,我得到了两个可执行文件,一个在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

Ale*_*lex 16

您可能想要查看CMake的RPATH处理设置

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

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

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

SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
Run Code Online (Sandbox Code Playgroud)

并且您还可以在安装期间禁用RPATH剥离:

SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
Run Code Online (Sandbox Code Playgroud)

  • 我发现如果我在`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`中的位置如何工作 (8认同)

Lot*_*har 5

我只想回答问题1。为什么这样做。Alex已经发布了一个解决方案,以更改此行为。

原因是在构建它时,您确实要使用构建脚本在计算机上看到的库。如果为您的应用程序构建了完整的库堆栈,那么您不会误会库没有选择它们。因此,使用完整的rpath到库是有意义的。而且,您永远不会在编译以及调试和运行之间移动应用程序。

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

从我的措辞可以看出,所有这些都是一团糟,因为它包含了许多如何组织构建和部署的隐式决策。这是“ DLL地狱”一词曾经仅在Windows上流行的原因,而当它被更广泛地使用时,它却转移到Unix。没有技术解决方案,因为它不是技术问题(已解决)。这是组织上的问题,默认情况下,CMake必须决定其在平台上支持的一种口味。恕我直言,他们已经明智地选择了。