为啥 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_TESTS
、BUILD_STATIC_LIB
- 它必须是:WITH_PROJ_A_TESTS
和 BUILD_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 更喜欢子目录包含而不是安装依赖项?的主要内容,如果未能解决你的问题,请参考以下文章
为啥我应该更喜欢单个'await Task.WhenAll'而不是多个等待?
为啥 Clojure 成语更喜欢返回 nil 而不是像 Scheme 这样的空列表?