【问题标题】:What is the idiomatic way to export a 3rd party static library dependency in CMake?在 CMake 中导出 3rd 方静态库依赖项的惯用方法是什么?
【发布时间】:2021-12-19 04:28:42
【问题描述】:

我有以下简化的 CMake 代码,用于在库中使用 Abseil(minimal repository to reproduce)

cmake_minimum_required(VERSION 3.20)

project(MyProject)

set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")

set(ABSL_PROPAGATE_CXX_STD ON)
find_package(absl REQUIRED)

add_library(MyStaticLibTarget STATIC MyStaticLib.cpp)
target_link_libraries(MyStaticLibTarget absl::strings)

install(TARGETS MyStaticLibTarget EXPORT MyProjectTargets)
install(TARGETS strings EXPORT MyProjectTargets)

if(EXPORT_MYSTATICLIB)
  export(TARGETS MyStaticLibTarget FILE lib/cmake/MyProject/MyProjectTargets.cmake)
endif()

# Setup for downstream clients of MyProject?
install(EXPORT MyProjectTargets DESTINATION lib/cmake/MyProject COMPONENT cmake-exports)

但是,如果我在运行 CMake 时尝试使用 export 代码路径,则会遇到如下所示的错误:

cmake -G Ninja -S . -B build -DABSL_ENABLE_INSTALL=ON -DEXPORT_MYSTATICLIB=ON

# CMake Error in CMakeLists.txt:
# export called with target "MyStaticLibTarget" which requires target
#   "strings" that is not in any export set.

我不明白错误信息;在我看来strings 已经是MyProjectTargets 的一部分(我认为这是一个导出集?),所以应该没有任何错误。

也就是说,根据错误消息,我尝试为strings 添加一个export 行,并暂时修复了所有错误,我最终得到了

export(TARGETS
  strings
  strings_internal
  type_traits
  base
  config
  throw_delegate
  dynamic_annotations
  log_severity
  base_internal
  raw_logging_internal
  atomic_hook
  core_headers
  spinlock_wait
  endian
  bits
  int128
  memory
  errno_saver
  meta
  APPEND FILE lib/cmake/MyProject/MyProjectTargets.cmake)

这确实解决了所有错误!在实践中,对于较大的库,手动执行此操作将非常痛苦。这似乎也是一个“错误”的解决方案,因为我手动命名了 Abseil 的许多内部细节。

  1. 手动添加上述目标是“正确”的解决方案吗?
  2. 有没有更好的方法来实现与上述相同的结果?

我有以下限制:

  • 我需要导出MyStaticLibTarget,以便下游客户端使用。
  • 我很确定依赖项(在 target_link_libraries 中)需要公开,因为在实际情况下(这是一个最小的示例),Abseil 标头将包含在库的公共标头中。

【问题讨论】:

  • "在我看来 strings 已经是 MyProjectTargets 的一部分" - strings 链接MyStaticLibTarget 但它不是部分。“......因为我手动命名了 Abseil 的许多内部细节。” - 因为您通过add_subdirectory 包含 Abseil,所以 Abseil 内部成为项目的内部。不要与使用find_package(absl) 混淆:它执行您的脚本 Findabsl.cmake,它在内部通过FetchContent_Add/add_subdirectory 包含Abseil。
  • 如果你想真正从 Abseil 内部抽象出来,那么首先安装 Abseil。之后find_package(absl) 无需手写脚本即可找到 Abseil。导出项目时,您只需将find_dependency(absl) 调用添加到导出脚本中即可。

标签: c++ cmake abseil


【解决方案1】:

TLDR:关注柯南文档,尤其是cmake_find_package 文档并浏览cheatsheet

按照 @Tsyvarev 在 cmets 中的建议,我使用了不同的设置并完成了这项工作,您可以在 conan 分支中看到最终结果。

步骤如下:

  1. 使用 Conan 下载并安装 Abseil,使用项目本地 conanfile.txt。现在,“安装”是一个可怕的词(我不想修改全局状态),但柯南本质上只是缓存源和构建工件,这意味着您可以在不同目录中拥有相同库的多个版本,不同项目可以使用这些不同的版本,它应该“正常工作”。 (至少,到目前为止,这是我的基本理解。)
    [requires]         # Which 3rd party conan packages we are using
    abseil/20210324.2
    
    [generators]       # How to create build system files that capture the dependency information
    cmake_find_package
    cmake_paths
    
    通过上面的配置,柯南就可以运行了:
    conan install . --install-folder build/conan
    # Bunch of CMake files will be available under build/conan
    
  2. 通过在CMakeLists.txt 中添加一行,将 CMake 指向柯南生成的文件。
    include("${CMAKE_BINARY_DIR}/conan/conan_paths.cmake")
    
  3. 使用 CMake 正常配置。
    cmake -G Ninja -S . -B build -DEXPORT_MYSTATICLIB=ON
    
    ABSL_ENABLE_INSTALL option is handled by Conan 不再需要。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-04-13
    • 2012-12-21
    • 1970-01-01
    • 2023-03-18
    • 2017-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多