我正在使用 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。
构建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
。根据需要调整这些。据我了解,安装过程中剥离
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
...
)
install(
FILES
$<TARGET_FILE:target_name>
DESTINATION
...
)
CMAKE_INSTALL_RPATH_USE_LINK_PATH 不适合您的原因可能与排序一样简单。这应该在创建目标之前设置。