【问题标题】:Finding my Linux shared libraries at runtime在运行时查找我的 Linux 共享库
【发布时间】: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)

目标是“扁平化”“构建”树并将测试、核心等的所有二进制输出放入一个文件夹中。

  1. 我尝试将 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
  1. 我阅读了 LD_LIBRARY_PATH 环境变量,因此尝试将该文件夹 (/usr/local/bin) 添加到其中并运行。我可以看到我已经正确更改了LD_LIBRARY_PATH,但它仍然不起作用。 “测试”仍然找不到libcore.so。我什至也尝试更改 PATH 环境变量。结果一样。

  2. 无奈之下,我尝试将输出二进制文件暴力复制到一个临时子文件夹(/mysdk/build)并从那里运行tests。令我惊讶的是,它跑了。 然后我意识到了原因:它没有加载libcore.so 的本地副本,而是从构建输出文件夹中加载了一个(就好像在构建时将完整路径“烘焙”到应用程序中一样)。随后删除libcore.so 的构建输出副本使“测试”像以前一样完全失败,而不是加载本地副本。所以也许这条路真的融入了。

我很茫然。我已经阅读了 CMake 教程和参考资料。它使这听起来很容易。除了显而易见的(我做错了什么?),如果有人能回答以下任何问题,我将不胜感激:

  1. 控制应用在何处查找共享库的正确方法是什么?
  2. 我的项目构建结构与我的二进制文件在安装时必须如何显示之间是否存在关系?
  3. 我是否接近正确的做法?
  4. 是否有可能我无意中“烘焙”(到我的应用程序中)到我的共享库的完整路径?那是一回事吗?我在我的 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


【解决方案1】:

您可以运行ldd file 来打印file 的共享对象依赖项。它会告诉你从哪里读取它的依赖项。

您可以将环境变量LD_LIBRARY_PATH 与您希望链接器查找的路径一起导出。如果未找到依赖项,请尝试将该依赖项所在的路径添加到LD_LIBRARY_PATH,然后再次运行ldd(确保导出变量)。

另外,请确保依赖项具有正确的权限。

【讨论】:

    【解决方案2】:

    更新 LD_LIBRARY_PATH 是一种选择。另一种选择是使用 RPATH。请检查示例。

    https://github.com/mustafagonul/cmake-examples/blob/master/005-executable-with-shared-library/CMakeLists.txt

    cmake_minimum_required(VERSION 2.8)
    
    # Project
    project(005-executable-with-shared-library)
    
    # Directories
    set(example_BIN_DIR bin)
    set(example_INC_DIR include)
    set(example_LIB_DIR lib)
    set(example_SRC_DIR src)
    
    # Library files
    set(library_SOURCES ${example_SRC_DIR}/library.cpp)
    set(library_HEADERS ${example_INC_DIR}/library.h)
    set(executable_SOURCES ${example_SRC_DIR}/main.cpp)
    
    # Setting RPATH
    # See https://cmake.org/Wiki/CMake_RPATH_handling
    set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/${example_LIB_DIR})
    
    # Add library to project
    add_library(library SHARED ${library_SOURCES})
    
    # Include directories
    target_include_directories(library PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/${example_INC_DIR})
    
    # Add executable to project
    add_executable(executable ${executable_SOURCES})
    
    # Linking
    target_link_libraries(executable PRIVATE library)
    
    # Install
    install(TARGETS executable DESTINATION ${example_BIN_DIR})
    install(TARGETS library DESTINATION ${example_LIB_DIR})
    install(FILES ${library_HEADERS} DESTINATION ${example_INC_DIR})
    

    【讨论】:

      猜你喜欢
      • 2011-06-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多