如何避免在 CMake 安装步骤中删除 RPATH?

问题描述 投票:0回答:3

我正在使用 CMake 开发一个 C++ 项目,在该项目中我构建了一个可执行文件

foo
,它使用共享库
libbar
(通过
ExternalProject_add
添加)。

构建目录中的可执行文件

build/src/foo
工作得很好。但是,如果我运行
make install
,安装的可执行文件
/bin/foo
会给出以下错误。

./foo: error while loading shared libraries: libbar.so.11: cannot open shared object file: No such file or directory

我知道我不是唯一一个遇到这个问题的人(例如参见这里),而且我也知道CMake对

rpath
的处理,参见这里。据我了解,
install
步骤删除了
rpath
变量,这说明找不到库文件。

我通过在目录

ldd foo
中运行
/build/src/
来检查这一点,结果是

libbar.so => /PATH/TO/LIBBAR/libbar.so

当我在目录中运行相同的命令时

/build/bin/
,我得到

libbar.so => not found

现在是我的问题。 一般情况下,如何避免可执行文件在安装过程中“忘记”共享库的位置?我基本上希望安装的可执行文件在

rpath
中具有与
build
目录中相同的路径。

到目前为止我所尝试过的

我读到你可以避免通过

剥离路径
SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)

然而,这根本不起作用。我不知道为什么不,因为这是此处文档中建议的精确解决方案。

我当然可以通过手动设置路径

SET(CMAKE_INSTALL_RPATH "$LIBBAR_PATH}/lib")

这确实有效,但是这个解决方案对于

libbar
来说太具体了,例如如果我在另一个也通过我的项目使用
libbar
的代码中导入此项目,则不起作用。

编辑

我要补充一点,这个问题并不是在所有机器上都会出现。我在 Linux 机器上得到它,它也说

-- Set runtime path of "/PATH/TO/foo" to ""

安装过程中。我在我的 Mac 上没有看到这条线,我根本没有这个问题。

编辑2

我刚刚看到我的问题甚至在常见问题下的文档中明确提到。他们还说添加

set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
就是解决方案。但这对我来说根本不起作用,我在这里做错了什么?

编辑3

难道

CMAKE_INSTALL_RPATH_USE_LINK_PATH = True
解决方案在这里不起作用,因为我是通过
libbar
添加
ExternalProject
?文档指出

CMAKE_INSTALL_RPATH_USE_LINK_PATH 是一个布尔值,如果设置为 true,则会将链接器搜索路径中的目录以及项目外部的目录附加到 INSTALL_RPATH。这用于初始化所有目标的目标属性 INSTALL_RPATH_USE_LINK_PATH。

c++ cmake shared-libraries rpath
3个回答
3
投票

构建RPATH被删除。这些

RPATH
是构建目录的绝对路径,一旦离开你的机器就不起作用。无论如何,你不希望他们在那里。问题是您没有正确设置
install
RPATH
在创建任何目标之前,将以下代码放入项目的早期。

include(GNUInstallDirs) if (APPLE) set(rbase "@loader_path") else () set(rbase "$ORIGIN") endif () file(RELATIVE_PATH lib_dir "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}" "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") # Honor user overrides, whether at the command line or FetchContent set(CMAKE_INSTALL_RPATH "${rbase};${rbase}/${libdir}" CACHE STRING "Install RPATH")

这会导致可重定位的安装树,并且对使用不同符号作为相对 RPATH 的 GNU 和 Apple 加载器实现都很敏感。

这还假设您的安装规则是标准的,并将运行时对象安装到

CMAKE_INSTALL_BINDIR

并将库安装到

CMAKE_INSTALL_LIBDIR
。根据需要调整这些。
    


1
投票

据我了解,安装过程中剥离

RPATH

是理想的行为,请参阅

文档
。一般来说,清除RPATH不能简单地停用。从 stackoverflow 上的其他问题来看,我发现在某些情况下可以设置
SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)

但这对我不起作用。我相信这是因为在我的特定设置中,共享库是通过 
ExternalProject_add

下载和构建的。因此,在这种情况下,共享库不是来自“项目外部”,请参阅“此处”。 (如果我的理解有误,请指正。)

最后,我没有看到比手动设置安装RPATH更好的方法via

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

如果我想将使用
libbar(我们称之为

Project_A
)的代码导入到另一个项目
Project_B

中,我还必须在

INSTALL_RPATH
CMakeLists.txt
中设置
Project_B
。类似于
的东西
SET(CMAKE_INSTALL_RPATH "${EXTERNAL_DIR}/Project_A/external/libbar/lib")
我认为这不是一个完全令人满意的解决方案,但这是我能想到的最好的解决方案。如果有人知道更好的方法,例如如何使用适用于共享库构建的 
CMAKE_INSTALL_RPATH_USE_LINK_PATH
选项作为同一构建树中的

ExternalProject
,请随时展示更好的方法。

CMake 删除已安装目标的 rpath,如下所示:
    install(
        TARGETS
            target_name
        DESTINATION
            ...
    )


0
投票

install( FILES $<TARGET_FILE:target_name> DESTINATION ... )


CMAKE_INSTALL_RPATH_USE_LINK_PATH 不适合您的原因可能与排序一样简单。这应该在创建目标之前设置。

© www.soinside.com 2019 - 2024. All rights reserved.