【问题标题】:Executable built using cmake cannot find shared library使用 cmake 构建的可执行文件找不到共享库
【发布时间】:2021-07-17 13:02:58
【问题描述】:

我一直在开发一个 Visual Studio 2019 项目,目的是将应用程序移植到 Centos 8。我在 VS2019 中使用 CMake 项目,并在我的 Centos 机器上进行远程构建。基本上,所有文件都被传输到远程机器上,项目就建好了。我的项目目录看起来像

Child
|  CMakeLists.txt
|  source
|__public
   |  headers
   |  libs  

Parent
|  CMakeLists.txt
|  source

Child 生成一个共享库 (.so) 和一些要在 Parent 中链接的公共头文件。 so 文件和公共头文件存在于 Child 的公共目录中。两个文件的CMake文件如下

Child/CMakeLists.txt

set(PROJECT_NAME "Child")

set(Header_Files
    #set of public headers and source headers
)

set(Source_Files
    #set of source files
)

set(ALL_FILES
    ${Header_Files}
    ${Source_Files}
)

if (UNIX)
    #Target is an SO
    add_library(${PROJECT_NAME} SHARED ${ALL_FILES})
    
    set(BOOST_INCLUDEDIR "${CMAKE_HOME_DIRECTORY}/Boost")    
    set(BOOST_LIBRARYDIR "${CMAKE_HOME_DIRECTORY}/Boost/libs/linux64-clang-9.0.0/static/release")

    find_package(Boost REQUIRED)
    if (Boost_FOUND)
        target_include_directories(${PROJECT_NAME} PRIVATE ${Boost_INCLUDE_DIRS})
        target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES})
    endif()

    set(XercesC_INCLUDE_DIR "${CMAKE_HOME_DIRECTORY}/Xercesc/Linux-Clang-Release/include")
    set(XercesC_LIBRARY "${CMAKE_HOME_DIRECTORY}/Xercesc/Linux-Clang-Release/lib64")

    find_package(XercesC REQUIRED)
    if (XercesC_FOUND)
        target_include_directories(${PROJECT_NAME} PRIVATE ${XercesC_INCLUDE_DIR})
        target_link_libraries(${PROJECT_NAME} "${CMAKE_HOME_DIRECTORY}/Xercesc/Linux-Clang-Release/lib64/libxerces-c.so")
    endif()
endif()

父/CMakeLists.txt

set(PROJECT_NAME "Parent")

set(Header_Files
    #set of headers
)

set(Source_Files
    #set of source files
)

set(ALL_FILES
    ${Header_Files}
    ${Source_Files}
)

if (UNIX)
    set(CHILD_HEADERS "${CMAKE_HOME_DIRECTORY}/Child/public/headers")
    set(CHILD_LIB_DIR "${CMAKE_BINARY_DIR}/Child/libs")

    link_directories(${CHILD_LIB_DIR})

    add_executable(${PROJECT_NAME} ${ALL_FILES})

    target_include_directories(${PROJECT_NAME} PRIVATE ${CHILD_HEADERS})
    target_link_libraries(${PROJECT_NAME} PRIVATE Child)

    #Copy libChild.so to Parent executable directory
    add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND 
                        cp "${CHILD_LIB_DIR}/libChild.so" 
                            "${CMAKE_CURRENT_BINARY_DIR}/libChild.so"
                       )
endif()

问题

我的目标是为我的客户构建一个版本。因此,我需要将所有可执行文件和库打包在一个 zip 文件夹下。但是,这样做后,我发现链接器路径采用了绝对路径值的排序

$ldd Parent
libChild.so => /root/.vs/Project/829a6827-2641-4552-a2fb-abec91ed47a2/out/build/Linux-Clang-Release/Child/libChild.so (0x00007f6934908000)

但是,关于我的最终构建文件夹将是这样的

Parent (executable)
libChild.so
libboost_regex...
libxerces... etc. etc.

我有点想要一个指向同一目录的相对路径链接

libChild.so => ./libChild.so

因此,当我以 zip 格式导出到另一台机器时,它无法找到共享库。我已经尝试了几件事(使用其他 CMake 函数)以及首先将库复制到可执行目录然后链接。但是,它仍然将其链接为绝对路径,这可能会再次导致相同的问题。我浏览了 CMake 文档并仔细阅读了 cmake-packagesrelocatable packages 但无法解决问题。

【问题讨论】:

  • "我需要将所有可执行文件和库打包到一个 zip 文件夹下。" - 不要从 构建树 打包文件。而是打包安装树。对于已安装的库,CMake 为您提供了调整 RPATH 的全部功能,请参阅CMake RPATH Handling wiki。此外,CMake 具有 CPack 组件,可用于为 CMake 包创建不同类型的存档。

标签: visual-studio cmake


【解决方案1】:

可以通过将这两个语句放在 Project Child 和 Project Parent 的 CMake 文件中来解决此问题。

set(CMAKE_INSTALL_RPATH ".")
set(CMAKE_BUILD_WITH_INSTALL_RPATH true)

可以在 CMake 文档中找到有关这些变量含义的详细信息。 尽管这解决了目前的问题,但正如 here 指出的那样,这不是为客户创建构建的正确方法。

【讨论】:

    猜你喜欢
    • 2014-06-12
    • 2021-06-16
    • 2012-08-13
    • 2011-12-14
    • 2021-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-25
    相关资源
    最近更新 更多