cmake:将 FetchContent 与 find_package() 集成

2024-03-14

我试图理解以下文档:

  • https://cmake.org/cmake/help/latest/module/FetchContent.html#integrating-with-find-package https://cmake.org/cmake/help/latest/module/FetchContent.html#integrating-with-find-package

所以我尝试了一个简单的 cmakelists.txt 文件,例如:

% cat CMakeLists.txt
cmake_minimum_required(VERSION 3.24)
project(p)

include(FetchContent)
FetchContent_Declare(
  googletest
  GIT_REPOSITORY https://github.com/google/googletest.git
  GIT_TAG        703bd9caab50b139428cea1aaff9974ebee5742e # release-1.10.0
  FIND_PACKAGE_ARGS NAMES gtest
)

# This will try calling find_package()
FetchContent_MakeAvailable(googletest)
find_package(GTest)
message(${GTest_DIR})

如果我运行它,我会得到以下结果:

$ cmake ..
[...]
/usr/lib/x86_64-linux-gnu/cmake/GTest

因为某些原因find_package(GTest)仍然尝试检查系统中的 GTest,而不是 FetchContent 代码块中声明的 GTest。

我从 cmake 文档中误解了什么?我假设了这个功能FetchContent正是针对用户无法使用的情况ExternalProject自从它does not https://stackoverflow.com/questions/66372317/use-find-package-on-external-project与整合find_package.

以供参考:

% cmake --version
cmake version 3.24.1

以非常简单的形式:选项FIND_PACKAGE_ARGS makes FetchContent使用结果find_package。但对于制作find_package使用结果FetchContent,你需要传递另一个选项:OVERRIDE_FIND_PACKAGE.


Both FetchContent and find_package旨在引入一个 3d 方项目,以便在主项目的构建过程中使用它。然而,这两种方法使用不同的机制:

  1. FetchContent从源代码构建 3d 方项目以及主项目,但是
  2. find_package适用于已安装的 3d 方项目。

CMake 提供了两个集成的“方向”FetchContent and find_package;每个“方向”都有其自己独立的目的。

1. 编写一个新项目,在源和安装中均消耗 3d 方项目。

假设您编写一个项目,该项目使用一些 3d 方项目。假设您想支持两种变体:

  1. 使用已安装的 3d 方项目变体(如果已可用),或者
  2. 从源代码中与主项目一起构建 3d 方项目。

范围FIND_PACKAGE_ARGS for FetchContent_Declare告诉 CMake 使用find_package用于查找已安装的 3D 方项目,如果可用,请勿从源构建它。

仅当主项目通过接口使用 3d 方项目时,此类集成才会起作用,前提是both通过 3d 方项目的来源和find_package.

例如。 GTest 的来源create https://github.com/google/googletest/blob/main/googletest/cmake/internal_utils.cmake#L155命名空间中的 ALIAS 目标GTest (like GTest::gtest_main) and find_package(GTest) creates https://github.com/google/googletest/blob/main/googletest/CMakeLists.txt#L103具有相同命名空间的导入目标。因此,外部项目可以安全地链接GTest::gtest_main只要 GTest 已经安装或正在从源代码构建,这就会起作用。

2. 使现有项目能够与从源代码构建的 3d 方项目一起使用

假设您正在创建一个超级项目,它结合了多个已经存在的子项目。该子项目之一执行find_package用于 3d 方项目并使用其结果。假设您希望从源代码构建 3d 方项目。

大多数特定于项目的脚本,由find_package,仅与已安装的软件包并且不适用于当前正在构建的版本。需要一些特殊的力量..

忽略“find_package”

范围OVERRIDE_FIND_PACKAGE for FetchContent_Declareignore更远find_package之所以会调用,是因为 3d 方项目是从源代码构建的。

如果子项目仅使用以下结果,则此方法有效find_package,也可以从 3d 方项目的来源获得。 例如。如果子项目使用目标,它将起作用GTest::gtest_main用于链接。但如果子项目使用它就不起作用GTEST_MAIN_LIBRARIES变量,未在 GTest 源中设置。

更改“find_package”执行的脚本

但是,如果子项目使用了部分接口,而该接口只能从find_package(及其特定于项目的脚本),但无法从 3d 方项目的源中获得?在这种情况下,可以创建一个假剧本,这将由执行find_package而不是普通的。

file(WRITE ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/gtest-extra.cmake
[=[
  set(GTEST_MAIN_LIBRARIES GTest::gtest_main)
]=])

之间的线[=[ and ]=]成为创建的脚本的一部分,该脚本定义GTEST_MAIN_LIBRARIES适合子项目中链接的变量。

(注意,该文件gtest-extra.cmake只有当OVERRIDE_FIND_PACKAGE参数已指定为FetchContent_Declare.)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

cmake:将 FetchContent 与 find_package() 集成 的相关文章

  • wasm-ld:错误:初始内存太小,需要 18317952 字节

    我想将 ffmpeg 编译为 wasm 下载 FFMPEG 和 emsdk 源代码后 我使用下面的命令进行构建 emconfigure configure cc emcc enable cross compile target os non
  • doxygen INSTALL 无法将文件“.../doxygen/build/bin/doxygen”复制到“/usr/local/bin/doxygen”

    解决了一些之后最初的问题 https stackoverflow com q 50986047 4120196在尝试让 doxygen 工作时 我在遵循以下步骤时偶然发现了下一个错误doxygen安装教程 http www doxygen
  • target_link_libraries 和 INCLUDE_DIRECTORIES 属性

    在这个片段中 cmake minimum required VERSION 3 0 project hello LANGUAGES C VERSION 0 0 1 add library a INTERFACE target include
  • 如何在使用cmake完成make后打印消息?

    我正在尝试使用 CMake 完成构建过程后打印消息 我只是想在之后通知用户make命令已完成 没有任何错误 我该怎么做 我试过add custom target 但我无法选择何时跑步 另外 我尝试过add custom command 它再
  • 是否可以使用 gold 链接器编译和链接 Clang/LLVM?

    我正在为 LLVM Clang 编写自定义通道 重新编译往往需要一段时间并使用大量内存 我听说 gold 链接器 1 比标准 ld 链接器花费更少的时间并且 2 使用更少的内存 有没有办法将标志传递到 LLVM Clang 构建过程并更改为
  • CMake“项目”指令的正确用法是什么

    我有一个很大的代码库 它构建了几十个库和几个可执行文件 代码库按层次结构进行分解 并且几乎在每个级别都构建了库 我已经仔细检查并在每个目录中放置了一个 CMakeLists txt 文件来构建每个库 在每个 CMakeLists txt 中
  • CMake:如何最好地构建多个(可选)子项目?

    想象一个包含多个组件的整体项目 basic io web app a app b app c 现在 假设 web 依赖于 io 而 io 又依赖于 basic 所有这些东西都在一个存储库中 并且有一个 CMakeLists txt 将它们构
  • 用于区分调试和发布版本的 CMake 变量或属性

    我想为调试和发布版本设置不同的 CMake 变量 我尝试像这样使用 CMAKE CFG INTDIR IF CMAKE CFG INTDIR STREQUAL Debug SET TESTRUNNER DllPlugInTesterd dl
  • CLion - 命令行程序参数

    当我分配给 运行 调试配置 程序参数 之类的 aaa bbb 然后打印它时 任何人都可以告诉我 JetBrains CLion 有什么问题吗 printf s n argv 1 我刚刚得到 aaa 而它必须是 aaa bbb 因为它们用双引
  • Haskell 项目可以使用 cmake 吗?

    我正在计划一个用 Haskell 编写的项目 也许也有一些部分是用 C 编写的 对于构建系统 我决定不选择 Haskell 程序 cabal 的常见选择 主要是因为我想了解其他语言的构建程序是如何工作的 我听说过 CMake 我认为这是一个
  • CMake - 将预构建库链接到 C# 项目

    我正在使用 CMake 构建 C 库 该库依赖于已构建的库 dll 我似乎无法让图书馆链接到我的图书馆 我尝试过使用target link libraries mylib external lib 我也尝试过暴力破解 reference e
  • CMake:连续编译程序两次

    为了能够进行许多自动优化 我希望能够使用标志编译我的程序 fprofile generate首先 然后运行它生成配置文件 然后使用以下命令重新编译程序 fprofile use反而 这意味着我想连续编译我的程序两次 使用两个不同的CMAKE
  • 如何使用 --build 选项查看 cmake 发出的命令

    当我运行 cmake build target INSTALL 命令时 如何查看发出的命令 似乎没有像 versbose之类的选项 cmake 帮助说 cmake build 是底层构建工具的接口 但没有说明有关发出的命令转储的任何内容 我
  • 安装 EXPORT 需要子项目中的目标

    我正在尝试编写一个 cmake 脚本来安装我正在处理的项目 其中一部分是必要的install EXPORT LIB EXPORTS where LIB EXPORTS是我在各种项目中一直使用的 EXPORT 属性install TARGET
  • cmake 包括其他目录中的 h 文件

    我在 cmake 项目下进行测试时遇到问题 我的项目是这样安排的 TerrainMap PointAccumulator heightQuadGrid Test 在 TerrainMap 目录中 CMakeLists txt 文件简单地概述
  • 如何使用 CMake 安装文件层次结构?

    我使用以下方法创建了文件列表 file GLOB RECURSE DEPLOY FILES PROJECT SOURCE DIR install 我想将所有这些文件安装在 usr myproject 但我想维护已安装文件夹上的文件树 ins
  • 使用 CMake 对 SDL 的未定义引用

    我正在使用 SDL v1 2 15 7 和 CMake 3 2 1 开发一个项目 在 h 文件中我添加了 include
  • Clang 与 CLion:无法获取编译器信息

    我尝试通过更改在 CLion 中从 gcc 切换到 clang工具链偏爱 但现在 cmake 失败并显示以下内容 Cannot get compiler information Compiler exited with error code
  • 将 dll/lib 链接到 cmake 项目

    我试图将库链接到我的 cmake 项目 但遇到链接器错误 我花了 2 个小时尝试解决这个问题 并创建了一个简单的项目 在其中对所有路径进行了硬编码 CMAKE MINIMUM REQUIRED VERSION 3 0 PROJECT Tes
  • CMake 找不到请求的 Boost 库

    既然我已经浏览了其他人的解决方案几个小时 但找不到适合我的问题的正确答案 我想将我的具体问题带给您 我正在尝试使用 CMake 构建 vsomeip 为此 我之前构建了 boost 1 55 但是 我在 CMake 中收到以下错误 The

随机推荐

  • 将我的日历应用程序与其他日历同步

    我希望我的日历应用程序与其他日历应用程序 雅虎日历 Google 日历 iCloud 日历 Microsoft Exchange 和 Microsoft Outlook 实时同步 有什么办法可以做到吗 我知道我们可以为谷歌日历做到这一点 但
  • 创建 C++ 枚举和依赖数据结构时如何避免重复? [复制]

    这个问题在这里已经有答案了 可能的重复 枚举到字符串 如果无效 未找到 则返回枚举整数值 https stackoverflow com questions 10175260 enum to string return the enum i
  • 如何对数组进行分组

    我正在尝试使用相同的标签对相似的对象进行分组 目前 这是我收到的 JSON const sizes id value 2496 label XS value 2499 label S type First Size id value 286
  • 如何通过后台服务在android中每天的特定时间重复通知

    您好 我正在开发应用程序 我通过后台服务设置了用户输入日期和时间的通知 现在我想设置每天下午 6 点的通知 闹钟 询问用户是否要添加另一个条目 我怎样才能实现这个目标 我应该使用相同的后台服务还是广播接收器 请给我更好的解决方案 教程将是个
  • 如何在不配置浏览器的情况下构建本地 Web 代理

    Netnanny 或 k9 Web Protection 如何在不配置浏览器的情况下设置 Web 代理 如何做呢 直接使用WinSock 或者在NDIS http en wikipedia org wiki Network Driver I
  • ARM 模板数组参数

    我有一个带有 Web 应用程序警报规则的 ARM 模板 我希望能够在其中配置哪些电子邮件收到警报 电子邮件警报操作的片段如下 action odata type Microsoft Azure Management Insights Mod
  • 检测到可能存在 DNS 欺骗。远程主机标识已更改

    我最近更换了服务器 因此我有了一个新的 IP 地址 当我尝试使用时git fetch remote repository 我明白了 gt C Users path app gt git fetch remote repository gt
  • Java RMI 和 RPC 有什么区别?

    Java RMI 和 RPC 之间的实际区别是什么 我在一些地方读到 RMI 使用对象 RPC是基于C的 因此它具有结构化编程语义 另一方面 RMI是基于Java的技术 并且是面向对象的 通过 RPC 您可以调用导出到服务器中的远程函数 在
  • 检测麦克风是否打开

    有没有办法以编程方式检测 Windows 上的麦克风是否打开 不 麦克风不会告诉您它们是否 打开 或者特定的声道是否已连接到麦克风设备 您能做的最好的事情就是从您怀疑是麦克风的输入通道 例如Windows默认输入设备 通道 读取音频数据 并
  • 如何获取数据列表的更改事件?

    我正在使用数据列表 需要检测用户何时从下拉列表中选择某些内容 类似的问题已被问到 https stackoverflow com questions 16027746 jquery event when html5 datalist opt
  • 将 SVG 图像转换为 png 以供不支持的浏览器使用 - 后备 - Modernizer.js(?) [重复]

    这个问题在这里已经有答案了 我正在考虑转几个SVG我的网站上的图像PNG对于不支持的浏览器SVG适当地 我主要对显示的基于文本的问题有疑问IE 显示的字体完全错误 所以我想我应该创建一个后备PNG 我已经尝试为此寻找一个很好的演练 我自认是
  • 使用函数式编程有效地计算素数

    通过回顾 Project Euler 并解决一些问题 我逐渐熟悉了 F 许多早期问题都由素数组成 环顾四周后 我想出了以下解决方案 let primesL let rec prim n sofar seq if sofar gt List
  • 如何在拖动 UICollectionViewCell 时实现透明背景或圆角

    我确定有must这是一种简单的方法 但我已经花了很长时间在各种兔子洞里 到目前为止还没有成功 我有一个支持拖放的集合视图 被拖动的单元格有一个UIImageView in the contentView 并且图像视图的背衬层应用了角半径 单
  • 如果其中一个进程意外终止,进程间内存会发生什么情况?

    如果您对动机感兴趣 我将在接下来的几句话中详细说明 如果不是 请跳至问题 我正在考虑制作快速记录器 但当程序崩溃时不受影响 又名最后一些日志消息不会丢失 所以我的想法是写入共享内存 ringbuffer 并让另一个低优先级进程从中读取并进行
  • 如何在jsf中启用浏览器缓存

    我使用 JSF 2 0 创建了一个 Web 应用程序 我收到朋友的反馈说我应该执行 浏览器缓存 因为我有很多图像 但是我不知道如何在 JSF 中做同样的事情 任何想法 提示将不胜感激 关于要做什么的概念也会起作用 只需使用
  • 继承和多态性的低级细节

    这个问题是我心中的一大疑惑 也很难用语言来形容 有时它看起来很明显 有时却很难破解 所以问题是这样的 class Base public int a number Base virtual void function1 virtual vo
  • 如何通过 Java High Level Rest Client 实现安全弹性搜索

    我是弹性搜索新手 通过将我的 Spring boot 应用程序与 Elastic 搜索集成Java High Level Rest Client 我已经配置了 JHLRC bean 如下所示 它工作正常 Bean destroyMethod
  • 调试时如何直接在IDE中查看其他对象的私有字段?

    C 是我最熟悉的语言 但工作时使用 Java 我想你可以说我对使用 Visual Studio IDE 非常满意 我喜欢它的调试器的一件事是我可以将监视变量 Eclipse 中的 表达式 any表达 因此 我可以在调试时毫无问题地查看特定字
  • 如何在Python中将集合转换为列表?

    我正在尝试将 Python 2 6 中的集合转换为列表 我正在使用这个语法 first list 1 2 3 4 my set set first list my list list my set 但是 我得到以下堆栈跟踪 Tracebac
  • cmake:将 FetchContent 与 find_package() 集成

    我试图理解以下文档 https cmake org cmake help latest module FetchContent html integrating with find package https cmake org cmake