【发布时间】:2021-09-09 12:27:03
【问题描述】:
我正在寻找有关正确 CMake 依赖项管理的一些见解。我遇到过ExternalProject 和FetchContent,两者都不能完全满足我的需求。让我详细解释一下:
我的项目结构如下:
main_project/
├── CMakeLists.txt
├── external/
│ ├── submodule1/
│ ├── submodule2/
│ ├── submodule3/
│ .
│ .
│ .
每个submoduleN 都是一个 git 子模块,其中包含一个完整的 CMake 项目和自己的安装目标。我可以完全控制这些子模块(我编写它们)。我想使用 install targets 因为它们为子模块提供了外部接口(具有适当的命名空间等)。我do not want to use the internal build targets。我想使用find_package 来解决依赖关系。
其次,我不想使用一些下载机制来获取和部署依赖项。我想为此使用 git 子模块,因为
- 我可以在主项目中冻结子模块版本(依赖版本管理)。
- 我可以轻松签出任何其他版本以进行调试(无需编辑文件,只需使用 git 并准备好完整的提交消息以供参考)。
假设每个submoduleN 都有自己相似的子结构,并且它们可能在内部相互依赖。如果他们碰巧有共享依赖项,我希望他们使用单一的通用版本。主项目中的层次结构优先于版本选择。例如,类似于FetchContent 的填充习语:
FetchContent_GetProperties(mylib)
if(NOT mylib_POPULATED)
FetchContent_Populate(mylib)
# do build, install and other stuff
endif()
我希望安装目标在配置步骤中可用(即find_package),并且我希望在我编辑它们时重新构建它们(即在一个submoduleN 中应用一些调试更改)。
问题:
- 我不能使用
ExternalProject_Add,因为它只在构建阶段可用。 - 我不能使用
FetchContent,因为它会忽略安装目标(甚至不构建它们)。 - 我不能使用
FetchContent,因为会有重复的目标名称(doc、main、tests 等)。
我知道Hunter++,它几乎解决了我的问题,除了 gitsubmodule 和 no-download 部分。我用ExternalProject 做了一个部分工作的例子,但我发现它很乱,并且不能解决常见的版本问题:
https://github.com/image357/cmake_tutorial_external
有什么想法吗?
编辑:
我刚刚在 CMake 上发现了一个类似的提案:
https://gitlab.kitware.com/cmake/cmake/-/issues/21687
【问题讨论】:
-
FWIW,在这些情况下,我所做的是将带有
CMAKE_INSTALL_PREFIX的依赖项构建到本地目录,并在构建根项目时将该目录添加到CMAKE_PREFIX_PATH。这确实意味着构建是一个两阶段的过程,但它最终要干净得多。 -
这是一个很棒的问题,它指出了 CMake 中的依赖管理故事中的一些严重问题。我对此有一些想法,我会尝试将它们组合成一个答案。
-
您绝对需要阅读原始问题 #17735(参考问题 21687)
标签: c++ c git cmake dependency-management