【问题标题】:cmake: add_subdirectory() vs include()cmake: add_subdirectory() 与 include()
【发布时间】:2018-07-08 15:49:14
【问题描述】:

假设我有一个使用 cmake 的 C++ 单元测试项目,如下所示:

$ tree
.
├── C-API-ConditionVariable-unit-test
│   ├── C-API-ConditionVariable-compile-link-test.c
│   ├── C-API-ConditionVariable-unit-test-0.cpp
│   └── C-API-ConditionVariable-unit-test-1.cpp
├── C-API-Mutex-unit-test
│   ├── C-API-Mutex-compile-link-test.c
│   ├── C-API-Mutex-unit-test-0.cpp
│   └── C-API-Mutex-unit-test-1.cpp
├── some
│   └── deeply
│       └── nested
│           └── path
│               └── SomeFeature-unit-test
│                   ├── SomeFeature-compile-link-test.c
│                   ├── SomeFeature-unit-test-0.cpp
│                   └── SomeFeature-unit-test-1.cpp
└── CMakeLists.txt

子文件夹中的每个源文件都会创建一个单独的可执行文件。我想让项目中的每个子文件夹成为一个非独立模块 - 也就是说,每个子文件夹(或多或少)是自包含的,但不是可以单独编译的独立 cmake 项目。我希望能够只建造一切或什么都不建造。例如,我不想给人留下只能从 some/deeply/nested/path/SomeFeature-unit-test 运行 cmake 来构建的印象。

我应该选择哪个选项?

  1. CMakeLists.txt 每个子文件夹中的文件 + add_subdirectory() 在顶级 CmakeLists.txt 中;
  2. some-random-name.cmake 在每个子文件夹中 + include() 在顶级 CmakeLists.txt 中;
  3. 忽略我的想法,即每个子文件夹都是独立的,并将所有相关的构建信息放在顶级 CMakeLists.txt 中,其他 cmake 文件仅作为帮助程序(宏、函数等);

第一个选项最方便,但它表明每个子文件夹实际上是一个独立的项目,可以单独编译。

第二个选项似乎清楚地表明这里只有一个 cmake 项目。但是随后在子文件夹中的每个some-random-name.cmake 中,我必须使用源文件的完整路径,这违背了我希望它们中的每一个都是独立的。如果只有一层嵌套(例如前两个示例子文件夹),那没关系,但对于some/deeply/nested/path/SomeFeature-unit-test,这不是很好。我还必须为输出文件的名称加上前缀。

第三个选项似乎是一种快速创建具有意大利面条长度的CMakeLists.txt 文件的简单方法,所以我可能更喜欢其他东西。

我想知道在“现代”cmake 项目中哪种是“首选”方式。我可以为多目录项目找到的所有教程都涉及以下情况:一个文件夹中有一个独立库,独立应用程序在另一个文件夹中使用该库,以及在另一个目录中使用相同库的独立测试。查看使用 cmake 的项目,我发现没有一致性,所以这没有多大帮助。

(我是cmake菜鸟,想把比较大的项目转成cmake使用)

【问题讨论】:

  • I would like know which is the "preferred" way in a "modern" cmake project. - 没有单一的“首选”方式。选择一个对你来说似乎方便的,并实施它。顺便说一句,add_subdirectory 本身的方式并不意味着子项目是独立的。
  • @Tsyvarev - 作为一个完整的 cmake 菜鸟,我更愿意将我的选择基于某种常识而不是我自己的偏好(; 你说我的理解 CMakeLists.txt 意味着文件夹是独立是错误的?但是如果一个特定的存储库将包含一些 cmake 项目,你怎么知道你应该使用哪个CMakeLists.txt 来构建一些东西而不阅读文档?
  • “但是,如果一个特定的存储库包含几个 cmake 项目,你怎么知道应该使用哪个 CMakeLists.txt 来构建一些东西而不阅读文档呢?” - 没门。 On 可能猜测顶级CMakeLists.txt 将是需要的。但可能需要 CMakeLists.txtsome other 项目中;例如在给定项目提供插件的情况下。

标签: cmake


【解决方案1】:

最常用的规则是“每个目标一个CMakeLists.txt”。所以你的第一个选择。

如果“子文件夹中的每个源文件创建一个单独的可执行文件”,您的项目结构可能必须适应这一点。

而根CMakeLists.txt 是您的起点,其中包含project() 命令。

需要注意的是

  • CMake 将在其生成的构建环境中镜像您的 add_subdirectory()CMakeLists.txt 目录结构
  • CMake 将在每次 add_subdirectory() 调用 (the big difference to using include() command) 时创建一个新的变量范围

您应该避免使用 ../some_other_dir/some_other_source.cpp 之类的东西从其他子目录中引用源文件。它表明您的 CMake 结构没有根据上面引用的经验法则设置。

文档摘录

  1. CMake: add_subdirectory() command

    在构建中添加一个子目录。 source_dir 指定源 CMakeLists.txt 和代码文件所在的目录。

  2. CLion: CMakeLists File

    当项目结构复杂且包含一个或多个子目录(项目根目录和子目录)时,您可以创建子目录CMakeList.txt文件。子目录CMakeLists.txt 文件描述了子目录的构建、内容和目标规则。

  3. C++Now 2017: Daniel Pfeifer "Effective CMake: a random seletion of best practices

    包含CMakeLists.txt 的目录是构建系统生成器的入口点。子目录可以添加add_subdirectory(),也必须包含CMakeLists.txt

参考文献

【讨论】:

  • 谢谢弗洛里安。这是一个很棒的答案。我希望我在阅读其他所有内容之前就已经找到了这个。
  • 第二个参考:《CMake教程》坏了
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-27
相关资源
最近更新 更多