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

C++ 为什么CMake设计为在安装时删除运行时路径,c++,hyperlink,cmake,shared-libraries,C++,Hyperlink,Cmake,Shared Libraries,我建立了我的共享库(我用自己的一个LIB计算Fibonacci数),并想用它在我的另一个C++项目中使用 CMake < /Calp> 假设共享库和头位于/path/to/my/lib中,共享库libfib。因此位于/path/to/my/lib/lib中,头fib.h位于/path/to/my/lib/include中,我自己的项目位于/path/to/my/project 这是我的原件CMakeLists.txt: cmake_minimum_required(VERSION 3.2) p

我建立了我的共享库(我用自己的一个LIB计算Fibonacci数),并想用它在我的另一个C++项目中使用<代码> CMake < /Calp>

假设共享库和头位于
/path/to/my/lib
中,共享库
libfib。因此
位于
/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\u dir
中,一个在安装位置
path/to/my/project/bin
,当在
build\u dir
中运行程序时,一切正常,但在运行已安装程序时,我得到:

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

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

  • libfib.so
    所在的库路径添加到环境变量
    LD\u library\u path
  • set\u target\u属性(${EXE}properties INSTALL\u RPATH\u USE\u LINK\u PATH TRUE)
    添加到my
    CMakeLists.txt
  • 因此,我的问题是:

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

  • 你可能想调查一下

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

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

    可以使用
    CMAKE\u INSTALL\u RPATH
    变量设置为已安装二进制文件设置的RPATH,例如:

    SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
    
    您还可以在安装过程中禁用RPATH剥离:

    SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
    

    你可能想调查一下

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

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

    可以使用
    CMAKE\u INSTALL\u RPATH
    变量设置为已安装二进制文件设置的RPATH,例如:

    SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
    
    您还可以在安装过程中禁用RPATH剥离:

    SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
    

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

    原因是,当您构建它时,您确实希望使用构建脚本在您的机器上看到的库。如果你为你的应用程序构建了一个完整的库堆栈,你不希望错误地发现它们不是由库选择的。因此,使用库的完整rpath是有意义的。此外,您永远不会在编译和调试运行应用程序之间移动应用程序

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


    正如您从我的措辞中看到的,所有这些都是一团混乱,因为它包含了太多关于如何组织构建和部署的隐含决策。这就是为什么术语“DLL地狱”曾经只在Windows上流行的原因之一,当它得到更广泛的使用时,它会转移到Unix上。没有技术解决方案,因为这不是技术问题(该部分已解决)。这是一个组织问题,CMake必须决定默认情况下在平台上支持哪种口味。我知道他们的选择很明智。

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

    原因是,当您构建它时,您确实希望使用构建脚本在您的机器上看到的库。如果你为你的应用程序构建了一个完整的库堆栈,你不希望错误地发现它们不是由库选择的。因此,使用库的完整rpath是有意义的。此外,您永远不会在编译和调试运行应用程序之间移动应用程序

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


    正如您从我的措辞中看到的,所有这些都是一团混乱,因为它包含了太多关于如何组织构建和部署的隐含决策。这就是为什么术语“DLL地狱”曾经只在Windows上流行的原因之一,当它得到更广泛的使用时,它会转移到Unix上。没有技术解决方案,因为这不是技术问题(该部分已解决)。这是一个组织问题,CMake必须决定默认情况下在平台上支持哪种口味。我发现,如果我在
    add\u executable(${EXE}main.cpp)
    之后添加
    SET(CMAKE\u INSTALL\u RPATH\u USE\u LINK\u PATH TRUE)
    ,CMAKE仍然会删除运行时路径,而
    设置目标属性(${EXE}properties INSTALL\u RPATH\u USE\u LINK PATH TRUE)
    无论其性能如何,都能正常工作