我正在做一个项目,叫它A
吧。它有自己的CMakeLists.txt
。这个项目还依赖于另外两个项目,B
和C
。每个都有自己的CMakeLists.txt
。项目C
也依赖于项目D
,它也有自己的CMakeLists.txt
。项目B
,C
和D
也是我的项目,它们作为单独的GitHub存储库驻留。它们生成了一些A
项目所需的库。我需要满足以下条件的解决方案:
1.我可以用一个命令编译所有东西。通常,我会先为每个项目执行cd build/ && cmake ../B/ && make .
,然后再为A
执行相同的操作。我的目标是cd build/ && cmake ../A/ && make .
。
1.我可以为任何我想要的项目编写代码,然后重新编译所有内容。同样,我拥有所有项目,它们都作为GitHub子模块驻留。
1.不需要安装依赖项。我不想这样做,因为它已经造成了足够的混乱。我只希望能够分别从源代码树和build
目录中直接读取头文件和库文件。
1.允许每个项目使用不同的生成配置。如果我只在项目A
上工作,我希望它处于调试状态,但B
应该处于发布状态(与其他依赖项无关)。
我已经尝试使用Visual Studio Code的cmake-tools
。它创建了一个名为build
的单独目录,但这意味着对所有依赖项进行树外编译,并且除了A
之外的所有项目都失败。将所有CMakeLists.txt
重新配置为指向build
是一项繁琐的工作,我仍然无法修复所有错误。我继承了B
、C
和D
的代码库,不想弄乱它们的CMake配置。
这是我当前的目录结构:
A/
├── build/
├── CMakeLists.txt
│
├── B/
│ └── CMakeLists.txt
├── C/
│ ├── CMakeLists.txt
│ └── D/
│ └── CMakeLists.txt
|
├── include/
├── src/
│ └── CMakeLists.txt
└── test/
└── CMakeLists.txt
我的目标可以实现吗?我的源代码树结构是否正确?有没有什么聪明的方法可以解决这些问题?
2条答案
按热度按时间6l7fqoea1#
基础直觉
如果你想在一个命令行调用中构建多个项目,你需要将它们都作为同一个生成的构建系统的一部分,或者使用the ExternalProject module,或者编写一个 Package 器脚本来为你调用多个构建系统。
据我所知,一般来说,一个生成的单一配置构建系统只能有一个总体构建配置(“调试”,“发布”等)。),并且单个生成的多配置只能具有多个“同类”配置(没有“混合”配置:“Debug”配置是“Debug”through and through,等等。如果你希望不同的项目都有自己的构建配置,这意味着你需要为每个项目提供自己生成的构建系统。要么我错过了什么,要么唯一的方法就是做一些丑陋的黑客,我不知道,即使我知道,我也不推荐。
当使用混合构建配置和多配置构建系统时,您可能需要查看the
MAP_IMPORTED_CONFIG_<CONFIG>
target property和its associated initialization variable。add_subdirectory()
一个解决方案是
add_subdirectory
B和C在A中,D在C中。这将导致CMake生成一个构建系统,该系统将构建所有A、B、C和D。1.我可以用一个命令编译所有东西。✅
1.我可以为任何我想要的项目编写代码,然后重新编译所有内容。✅
1.不需要安装依赖项。✅
1.允许每个项目使用不同的生成配置。❌
export()
+include()
另一种解决方案是在每个依赖项项目中使用
export()
,然后在目标导出文件中使用include()
来添加依赖项。这意味着为每个项目生成一个单独的构建系统。1.我可以用一个命令编译所有东西。你要么需要单独调用每个构建系统,要么编写一个调用所有构建系统的 Package 器脚本。
1.我可以为任何我想要的项目编写代码,然后重新编译所有内容。✅
1.不需要安装依赖项。✅
1.允许每个项目使用不同的生成配置。✅
ExternalProject
我认为,如果将the ExternalProject module与
export()
+include()
合并,您将能够获得the ExternalProject module所需的一切(您还可以将其与使用安装的方法一起使用,这实际上不会增加手动步骤,我假设这是您想要避免的)。每个项目都有自己的buildsystem,但是configure和build的调用将由依赖的项目驱动(尽管您也可以使用cmake --build <build_dir>
以正常的方式调用单个项目)。您特别感兴趣的是SOURCE_DIR
和BUILD_DIR
选项。您可能还希望使用BUILD_ALWAYS
构建步骤选项。1.我可以用一个命令编译所有东西。✅
1.我可以为任何我想要的项目编写代码,然后重新编译所有内容。✅
1.不需要安装依赖项。✅
1.允许每个项目使用不同的生成配置。✅
杂文
请注意,在Pitchfork布局规范中(您不必关心它),您的B和C目录可能会在A/external/下,而您的D目录可能会在C/external/下。
VS Code CMake Tools扩展允许您配置构建目录。参见settings docs。支持CMake Presets。参见its CMake Presets support docs。
源代码外的构建不是一件坏事。它们使删除整个构建系统及其工件变得更容易,因为它们将它们与源代码树分开。
i86rm4rw2#
我的目标可以实现吗?
是的。看看CMake presets。通过预置,您可以以灵活的方式预定义典型构建,并仅使用一个CLI命令(例如:例如,
cmake --workflow --preset make-everything-the-way-I-like
:)。然而,该功能还有点粗糙,因此由于缺乏人性化的诊断,编写正确的预设(和工作流程)可能会很棘手%)
我的源代码树结构是否正确?
没有 * 正确 * 或 * 不正确 *:)这是你使用它的方式的问题,它是多么方便,容易理解/预先设置/维护/等.这种用法/布局是为你个人、你团队中的其他开发人员或其他任何试图构建你的项目的人准备的。恕我直言,如果任何一个熟悉w/ CMake CLI的人都可以在几分钟内(不到10分钟)开始从头开始构建它(项目),并使用所需的构建变体和选项。..当你作为一个维护者可以为自己感到自豪:)
有没有什么聪明的方法可以解决这些问题?
Sure:)
1.了解现代CMake方式
1.不要给自己制造麻烦(通常是由于误解了CMake或构建过程,并希望使用通常在CMake %中以另一种方式完成的smth)
1.熟悉源代码外的构建,尽快忘记源代码内的构建
1.修正你所有的项目,使其在源代码外的构建中表现良好(通常是因为CML有太多的硬代码,以及关于构建过程/环境的假设)。
1.根据我的经验,Git子模块(以及任何其他“解决方案”,如mono repo,在构建期间获取等)。)是一个很大的麻烦源,并且使构建过程(和预设置)比需要的更困难(特别是在维护中)。拥有独立的依赖关系会让一切变得更容易。..但这是一个单独的故事;)