【发布时间】:2018-03-15 23:08:19
【问题描述】:
我正在将用 C++ 编写的 SDK 从 Windows 移植到 Linux。还有其他二进制文件,但最简单的,我们的 SDK 是这样的:
- core.dll - 隐式加载的 DLL(Linux 上的“libcore.so”共享库)
- tests.exe - 用于测试 DLL 的应用(使用 google 测试)
我的所有二进制文件都必须位于 一个 文件夹中,应用程序可以找到该文件夹。我已经在 Windows 上实现了这一点。我想在 Linux 中实现同样的目标。我失败得很惨
为了说明,这是基本的项目树。我们使用 CMake。在我建立之后,我得到了
mysdk
|---CMakeLists.txt (has add_subdirectory() statements for "tests" and "core")
|---/tests (source code + CMakeLists.txt)
|---/core (source code + CMakeLists.txt)
|---/build (all build ouput, CMake output, etc)
|---tests (build output)
|---core (build output)
目标是“扁平化”“构建”树并将测试、核心等的所有二进制输出放入一个文件夹中。
- 我尝试将 CMake 的“安装”命令添加到我的每个
CMakeLists.txt文件(例如install(TARGETS core DESTINATION bin)中。然后我在正常构建后执行sudo make install。这将我所有的二进制文件放在/usr/local/bin中,没有错误。但是当我从那里运行tests时,它找不到libcore.so,即使它就在同一个文件夹中
tests: error while loading shared libraries: libcore.so: Cannot open shared object file: No such file or directory
我阅读了
LD_LIBRARY_PATH环境变量,因此尝试将该文件夹 (/usr/local/bin) 添加到其中并运行。我可以看到我已经正确更改了LD_LIBRARY_PATH,但它仍然不起作用。 “测试”仍然找不到libcore.so。我什至也尝试更改 PATH 环境变量。结果一样。无奈之下,我尝试将输出二进制文件暴力复制到一个临时子文件夹(
/mysdk/build)并从那里运行tests。令我惊讶的是,它跑了。 然后我意识到了原因:它没有加载libcore.so的本地副本,而是从构建输出文件夹中加载了一个(就好像在构建时将完整路径“烘焙”到应用程序中一样)。随后删除libcore.so的构建输出副本使“测试”像以前一样完全失败,而不是加载本地副本。所以也许这条路真的被融入了。
我很茫然。我已经阅读了 CMake 教程和参考资料。它使这听起来很容易。除了显而易见的(我做错了什么?),如果有人能回答以下任何问题,我将不胜感激:
- 控制应用在何处查找共享库的正确方法是什么?
- 我的项目构建结构与我的二进制文件在安装时必须如何显示之间是否存在关系?
- 我是否接近正确的做法?
- 是否有可能我无意中“烘焙”(到我的应用程序中)到我的共享库的完整路径?那是一回事吗?我在我的 CMakeLists 文件中使用所有 CMAKE 变量。
【问题讨论】:
-
objdump -p /usr/local/bin/tests | grep RPATH的输出是什么? (对于内置可执行文件来说,将RPATH设置为包含指向它所链接的本地库的路径是正常的;但对于已安装的可执行文件,除非您设置了一些与RPATH相关的CMake 变量,否则它不应该有RPATH设置。)通常,您应该将本地共享库安装到CMAKE_INSTALL_PREFIX/lib,因此在这种情况下为/usr/local/lib。 -
哦,或者库应该进入
/usr/local/lib64或/usr/local/lib/x86_64-linux-gnu- 后者用于 Debian、Ubuntu 或 Mint 等,前者用于大多数其他发行版。如果你include(GNUInstallDirs)然后install(TARGET core DESTINATION ${CMAKE_INSTALL_LIBDIR})那应该照顾这些变化,我想。 -
“我可以看到我已经正确更改了
LD_LIBRARY_PATH,但它仍然不起作用。” 你怎么能看到呢?你有没有做过export LD_LIBRARY_PATH让它在子进程中可见,而不仅仅是当前的shell?如果你做得正确,它会起作用。 -
阅读
man ld.so了解查找共享库的其他方法,与LD_LIBRARY_PATH相比具有各种优缺点。 gcc.gnu.org/onlinedocs/libstdc++/manual/… 有一些文档描述了查找 GCC 的库,但适用于任何共享库。 -
好的,命令返回空输出的事实只是意味着可执行文件没有设置 RPATH,这与预期的一样。所以剩下的就是确保将共享库安装到默认情况下由动态加载器搜索的目录中 - 与 Windows 不同,它不包括
/usr/local/bin(绝对是,作为PATH变量的一部分,或者作为包含可执行文件的目录)。
标签: linux gcc cmake shared-libraries