如何导出使用 FetchContent 获取的目标

How to exporting targets fetched with FetchContent

我正在尝试使用 FetchContent CMake 帮助程序自动构建所需的依赖项,以防它们不是 installed/available 到 find_package,但在如何处理导出构建目标。

我自己的项目需要 TinyXML2 作为依赖项:

## TinyXML2
find_package(tinyxml2 QUIET)
if (${tinyxml2_FOUND})
    message(STATUS "tinyxml2 FOUND!(${tinyxml2_LIBRARIES})")
    echo_all_cmake_variable_values()
else()
    message(STATUS "tinyxml2 NOT FOUND, fetching from source!")
    FetchContent_Declare(tinyxml2
      GIT_REPOSITORY     https://github.com/leethomason/TinyXML2
      GIT_TAG            9.0.0
    )
    FetchContent_MakeAvailable(tinyxml2)
    set(tinyxml2_LIBRARIES tinyxml2)
endif()

然后用于link项目目标:

# ...
target_link_libraries(${PROJECT_NAME} PUBLIC ${Boost_LIBRARIES}
                                             pthread
                                             ${tinyxml2_LIBRARIES})

然后导出 linked 目标:

# ...
export(EXPORT ${PROJECT_NAME}Targets
       FILE ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake
       NAMESPACE ${PROJECT_NAME}::)

问题是,从源中获取时,导出步骤失败:

CMake Error in src/myproject/CMakeLists.txt:
    export called with target "myproject" which requires target "tinyxml2" that
    is not in any export set.

有没有办法自动导出 tinyxml2 作为必需的依赖项?

Is there a way to also auto-export tinyxml2 as a required dependency?

自 CMake 3.23 起 (pre-release)。

当您使用 FetchContent 时,就好像您自己编写了“third-party”代码。 CMake 不知道它是外部的。这称为“供应商”代码。

因为您没有经历 find_package,您将需要 install()“您的”目标,就像您将导出的任何其他依赖项一样。它也将导出到您的命名空间,以避免与 other 可能浮动的 tinyxml2 副本发生冲突。

我也觉得这很乏味,这就是为什么我回避 FetchContent 任何可能安装或导出的东西,而是使用适当的 source-based 包管理工具,如 vcpkg。这样的工具让您可以使用 find_package 来定位您的依赖项,无论如何,这是(imo)您应该在 100% 的时间里做的事情。


此外,您的代码有误(请参阅我的顶级评论)。这是一个更正确的版本(我个人认为 find_package(tinyxml2 REQUIRED))。

## TinyXML2
find_package(tinyxml2 QUIET)
if (NOT tinyxml2_FOUND)
  message(STATUS "tinyxml2 NOT FOUND, fetching from source!")
  FetchContent_Declare(tinyxml2
    GIT_REPOSITORY     https://github.com/leethomason/TinyXML2
    GIT_TAG            9.0.0
  )
  FetchContent_MakeAvailable(tinyxml2)
  install(
    TARGETS tinyxml2 
    EXPORT ${PROJECT_NAME}Targets
    # More arguments as necessary...
  )
endif ()

# ... usage ...
target_link_libraries(${PROJECT_NAME} PUBLIC ${Boost_LIBRARIES}
                                             pthread
                                             tinyxml2::tinyxml2)

这也比通过变量输入更少。