为啥 FetchContent 更喜欢子目录包含而不是安装依赖项?

Posted

技术标签:

【中文标题】为啥 FetchContent 更喜欢子目录包含而不是安装依赖项?【英文标题】:Why does FetchContent prefer subdirectory-subsumption vs installation of dependencies?为什么 FetchContent 更喜欢子目录包含而不是安装依赖项? 【发布时间】:2021-12-24 15:59:15 【问题描述】:

假设有两个软件项目proj_a和proj_b,后者依赖于前者;并且他们都使用 CMake。

在阅读有关现代 CMake 的信息时,人们会得到这样的信息:表达依赖关系的“适当”方式是通过目标依赖关系;并且应该安排它,以便将依赖项目表示为您可以依赖的(导入的)目标。更具体地说,在我们的示例中,proj_b 惯用地具有:

find_package(proj_a)

# etc etc.

target_link_library(bar proj_a::foo)

并且 proj_a 需要已经安装,使用 CMake 安装和导出相关命令,proj_b 的 CMake 调用将搜索 proja-config.cmake 的某个位置。

我喜欢这种方法并鼓励其他人适应它。它可以灵活地选择您自己的 proj_a 版本与系统版本;并且还允许通过 Findproja.cmake 脚本(同样可以是系统级或 proj_b 的一部分)使用非 CMake proj_a。

到目前为止一切都很好,对吧?但是,有些人希望在依赖关系方面“自己动手”——CMake 官方允许这样做,使用诸如 ExternalProject 之类的命令以及最近的FetchContent:这允许 proj_b 的配置阶段实际下载一个 ( proj_a 的构建版本,或者在我们的例子中是 source-form 版本。

令我困惑的是,在 proj_a 下载后,对external/proj_a 目录说,CMake 的默认行为将是

add_subdirectory(external/proj_a)

即把proj_a作为proj_b的子项目,一起构建。这一点,虽然上面的惯用用法允许 proj_a 的维护者在我的 CMakeFile 中“做他们自己的事情”,并且只通过我导出/安装的内容为他人保持整洁。

我的问题:

    为什么add_subdirectory() 有意义,而不是构建、安装和执行find_package() 的等效项来满足依赖关系?或者更确切地说,为什么前者而不是后者应该成为默认值? 我真的应该写我的项目级 CMakeLists.txt 以兼容 add_subdirectory()'ed 吗?

注意:只是给出一些具体的例子来说明这种用法如何约束 proj_a:

必须使用不可能与超级项目名称冲突的唯一选项名称。所以不要再有WITH_TESTSBUILD_STATIC_LIB - 它必须是:WITH_PROJ_A_TESTSBUILD_PROJ_A_STATIC_LIB。 您必须考虑到父项目已经搜索了其他依赖项,并且可能与您希望搜索它们的方式不同。

【问题讨论】:

“为什么add_subdirectory() 有意义,而不是构建、安装和执行find_package() 的等效项” - 这取决于您的具体情况。通常你选择前者,但后者也可用。但是,我发现在配置另一个项目期间安装 一个项目有些奇怪。例如。配置通常不需要root权限,但系统安装需要它们。 “我真的应该编写我的项目级 CMakeLists.txt 以兼容被 ​​add_subdirectory()'ed 吗?” - 它是由你决定。我看到越来越多的人期望其他项目可以通过add_subdirectory 使用。 (你不是在这些人中吗?) @Tsyvarev:“取决于您的用例”听起来很合理,但 CMake 默认为 add_subdirectory();它不会让 proj_a 作者说“请使用我的安装结果版本,而不是我的来源”。至于在配置期间安装 - 我同意这有点奇怪,但是,原则上,您甚至无法知道 proj_a 是如何使用,直到 after 构建完成并安装。另外,在项目配置期间通过 Internet 下载东西已经有点怪异恕我直言。 "但 CMake 默认为 add_subdirectory()" - 不太正确。 FetchContent 模块中唯一能做到这一点的函数是FetchContent_MakeAvailable。但是通过使用FetchContent_Populate 可以实现任何其他的填充逻辑。另请注意,FetchContent 的文档明确指出,获取的项目根本不需要 CMakeLists.txt @Tsyvarev:我没有说“不允许”,我说的是“默认值”......通常可以自己实现其他事情。问题是,为什么这个默认值? 【参考方案1】:

根据 cmets 中的讨论,我决定发布一个关于此的错误报告:

#22904: Support FetchContent_MakeAvailable performing build+install+find_package rather than add_subdirectory

所以也许这会改变,问题变得没有实际意义。

【讨论】:

查看我在链接的 CMake 问题中的回复,希望能对这个领域的大局有所了解(我是 FetchContent 的作者)。

以上是关于为啥 FetchContent 更喜欢子目录包含而不是安装依赖项?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 JSLint 更喜欢点符号而不是方括号?

为啥clang++更喜欢adcx而不是adc

为啥我应该更喜欢单个'await Task.WhenAll'而不是多个等待?

为啥 Clojure 成语更喜欢返回 nil 而不是像 Scheme 这样的空列表?

为啥我们更喜欢在角度中使用 $q 而不是 $http [重复]

为啥在 C++ 中更喜欢 char* 而不是字符串?