1

我不会直接提出问题,而是公开我的用例以及我尝试(但失败)解决它的方式。

说我有:

  • 3 个共享库 A、B 和 C
  • A 要求 B 和 C
  • A 自带一组表头

就是这样,没有额外的信息,它是由供应商提供的,不可能有任何变化(现代化/cmake 包等)。A 应始终与 B 和 C 打包。我只需要与 A 链接,cmake 应与 B 和 C 传递链接。

现在,我想让它更“现代 cmake”友好,并且能够:

  1. 第一个用例:创建一个包含这些库并从父项目调用 add_subdirectory() 的存储库。
  2. 第一个用例:创建一个包含相关 AConfig.cmake AConfigVersion.cmake 和 ATargets.cmake 的包(比如 debian pkg .deb)。然后一个简单的 pkg 系统安装和一个 find_package() 应该可以解决问题。

做了什么:

我尝试使用 INTERFACE IMPORTED 库和 INTERFACE。

因为我想支持打包libs INTERFACE IMPORTED 不能使用(据我所知/测试你不能安装它)。

INTERFACE 在第一个用例中运行良好,使用 add_subdirectory(),找到标头,所有链接,但由于用户此时可能没有,共享库是路径,例如,他无法运行测试。

然后是使共享库可用并使 find_package() 工作所需的导出部分。我成功导出/打包了 libs ABC、A 的标头和 find_package() 所需的文件。

但是,当在客户端库 D 中,find_package(A REQUIRED) 找到 lib(没有消息,例如“找不到由“A”提供的包配置文件”)它不会创建任何我可以链接的目标。我查看了生成的 ATargets.cmake:

# generated stuff before

add_library(A::A INTERFACE IMPORTED) # This is cannot be used at all, does not create a target I can link on unless I remove IMPORTED

set_target_properties(A::A PROPERTIES
  INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include" # that's fine
  INTERFACE_LINK_LIBRARIES "A.so;B.so.1.0;C.so.1.0" # that's not fine I need ${_IMPORT_PREFIX}/${CMAKE_INSTALL_LIBDIR}/ before each libs like it did for the headers
)

# generated stuff after

请注意,如果我删除 ATargets.cmake 的 add_library 中的 IMPORTED 并删除命名空间的东西,目标 A 可以在任何客户端 cmake 项目中使用 find_package 正确访问,但它可能无法正确链接,因为 A.so (和 B 和C) 未使用${_IMPORT_PREFIX}/lib/A.so. 我尝试${_IMPORT_PREFIX}/lib/在 INTERFACE_LINK_LIBRARIES 中的所有库之前添加,删除 IMPORTED 关键字和命名空间的东西,猜猜是什么,它完美地工作......现在,我该如何做到这一点而没有技巧。

AConfig.cmake.in 的内容是:

@PACKAGE_INIT@
include(CMakeFindDependencyMacro)

# Add the targets file
include("${CMAKE_CURRENT_LIST_DIR}/ATargets.cmake")

# check_required_components(@PROJECT_NAME@) # It is commented because unless I apply the fix specified earlier (IMPORTED and namespace removed), during the find_package call I get:
#################
# CMake Error at /usr/lib/cmake/A/AConfig.cmake:8 # (check_required_components):
#   Unknown CMake command "check_required_components".
#################

差不多就是这样,这篇文章的其余部分是实现细节。以下代码可用于解决用例 1,但导出包和 cmake 配置/目标文件不正确。

add_library(A
            INTERFACE)

add_library(A::A ALIAS A)


target_include_directories(A
                           INTERFACE "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
                                     "$<INSTALL_INTERFACE:include>")

target_link_libraries(A
                      INTERFACE "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/lib/A.so>"
                                "$<INSTALL_INTERFACE:A.so>"
                                "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/lib/B.so>"
                                "$<INSTALL_INTERFACE:B.so>"
                                "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/lib/C.so>"
                                "$<INSTALL_INTERFACE:C.so>")

#### install

install(TARGETS  A
            EXPORT   ATargets
            RUNTIME  DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT A_Runtime
            LIBRARY  DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT A_Runtime NAMELINK_COMPONENT A_Development
            ARCHIVE  DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT A_Development)

    install(DIRECTORY   "lib/"
            DESTINATION ${CMAKE_INSTALL_LIBDIR})

    install(DIRECTORY   "${CMAKE_CURRENT_SOURCE_DIR}/include"
            DESTINATION "include")

    write_basic_package_version_file(AConfigVersion.cmake
                                    VERSION "${PACKAGE_VERSION}"
                                    COMPATIBILITY SameMajorVersion)

    install(EXPORT      ATargets
            FILE        ATargets.cmake
            NAMESPACE   A::
            DESTINATION "lib/cmake/A")

    configure_file(AConfig.cmake.in AConfig.cmake @ONLY)
    install(FILES       "${CMAKE_CURRENT_BINARY_DIR}/AConfig.cmake"
                        "${CMAKE_CURRENT_BINARY_DIR}/AConfigVersion.cmake"
            DESTINATION "lib/cmake/A")

# Then some cpack stuff that is not affecting the work done earlier

在安装生成包(由cpack生成)后的客户端lib/cmake项目中:

find_package(A)

target_link_libraries(my_project PUBLIC/PRIVATE A::A) # Should bring in the headers and link with A B and C

文档:

cmake:创建一个包含预构建库的新库目标

https://gitlab.kitware.com/cmake/community/-/wikis/doc/tutorials/Exporting-and-Importing-Targets

是否可以将导入的库添加到 target_link_libraries 来处理包含目录?

导出导入的库

https://discourse.cmake.org/t/how-to-control-import-prefix-in-exported-targets-cmake-list-file-generated-by-cmake/2291

使用正确的自动生成配置 cmake 创建可重定位包

https://discourse.cmake.org/t/exporting-packages-with-a-custom-find-module/3820/2

感谢阅读/帮助

4

0 回答 0