如何使用CMake并使用相对路径链接共享库

17

我想链接第三方的libLibrary.so并将其与我的程序一同分发。如果用户解压我的归档文件,他将得到以下文件夹结构:

game
  libLibrary.so
  game_executable
< p > < code > game_executable 依赖于 < code > ./libLibrary.so 。 < p > 我的项目结构:

game
  bin
    libLibrary.so
  lib
    Library.h
  src
    game_executable.cpp
  CMakeLists.txt

我的CMakeLists.txt文件:

cmake_minimum_required(VERSION 3.7)
project(game)

set(CMAKE_CXX_STANDARD 14)

set(CMAKE_BINARY_DIR ${CMAKE_SOURCE_DIR}/bin)
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})
set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR})

set(SOURCE_FILES src/game_executable.cpp)
include_directories(${CMAKE_SOURCE_DIR}/lib)
add_executable(game ${SOURCE_FILES})
target_link_libraries(${PROJECT_NAME} ${CMAKE_BINARY_DIR}/libLibrary.so)

然而,我得到的是我的game_executable依赖于... / game / bin / libLibrary.so ,而不是与 game_executable 在同一文件夹中的 ./libLibrary.so ,这使得它完全不可移植!

我该如何使链接路径变为相对路径而不是绝对路径?

4个回答

22
根据文档所述,如果您没有更改任何RPATH相关设置,默认情况下,CMake将使用完整的RPATH将可执行文件和共享库链接到构建树中使用的所有库。这就是您所看到的行为。
但是,有许多方法可以更改此行为以匹配您需要的行为。上面链接的文档提供了一些示例。
# use, i.e. don't skip the full RPATH for the build tree
SET(CMAKE_SKIP_BUILD_RPATH  FALSE)
    
# when building, don't use the install RPATH already
# (but later on when installing)
SET(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) 
    
# the RPATH to be used when installing
SET(CMAKE_INSTALL_RPATH "")
    
# don't add the automatically determined parts of the RPATH
# which point to directories outside the build tree to the install RPATH
SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)

使用上述方法,您可能需要设置CMAKE_INSTALL_RPATH,然后分发已安装的二进制文件。
如果您想要从构建树中的二进制文件分发,也可以绕过CMake的rpath处理,并使用链接器标志直接修改rpath。
set_target_properties(game PROPERTIES LINK_FLAGS "-Wl,-rpath,./")

4
如果想为单个目标修改运行路径(runpath),可以在set_target_properties中使用与前面相同的变量名,但省略了前缀CMAKE_。例如:set_target_properties(game PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE)set_target_properties(game PROPERTIES INSTALL_RPATH "./")。这将执行与您最后一个示例相同的操作。 - John
1
要将目标可执行文件的路径指定为当前目录,可以参考我的答案 https://dev59.com/jVcQ5IYBdhLWcg3wFf8-#69707790 - CharlesB

10
大多数情况下,您希望将 RPATH 设置为 $ORIGIN 而不是 .,因为它指的是可执行文件的路径,而 . 指的是运行时当前目录(可能是其他任何目录)。
我发现编辑 LINK_FLAGS 而不是 INSTALL_RPATH 目标属性很简单,因为 CMake 已经有一个名为 ORIGIN 的变量(请参见 CMake 文档)。
因此,这归结为以下内容:
# Find shared libraries next to the executable
set_target_properties(target_name PROPERTIES
        BUILD_WITH_INSTALL_RPATH FALSE
        LINK_FLAGS "-Wl,-rpath,$ORIGIN/")

5
谈到使用动态链接库和CMake构建系统分发可执行文件或共享库:
SET(CMAKE_BUILD_RPATH_USE_ORIGIN TRUE)

这个变量强制使用在构建树内的相对路径进行链接,因此构建目录可移动。

如果您在 Linux 机器上使用该命令

find <YOUR_TARGET_NAME> -type f -perm /a+x -exec ldd {} \; | grep so | sed -e '/^[^\t]/ d' | sed -e 's/\t//' | sed -e 's/.*=..//' | sed -e 's/ (0.*)//' | sort | uniq -c | sort -n

在路径中你会看到点号,这代表着相对性,例如:~/project/build/./lib/my_shared_lib.so

更多信息请参见CMake文档


谢谢。以上的解决方案都因某些原因对我无效。但是上述方法完美地适用于移动已编译的构件。 - ipcamit

0
如果您使用target_link_directories,那么cmake会将其添加到链接器命令作为手动rpath。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接