c++ 如何将单独的git+CMake项目组合在一起,以便于构建,同时允许混合构建配置?

rqqzpn5f  于 2023-05-02  发布在  Git
关注(0)|答案(2)|浏览(198)

我正在做一个项目,叫它A吧。它有自己的CMakeLists.txt。这个项目还依赖于另外两个项目,BC。每个都有自己的CMakeLists.txt。项目C也依赖于项目D,它也有自己的CMakeLists.txt。项目BCD也是我的项目,它们作为单独的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是一项繁琐的工作,我仍然无法修复所有错误。我继承了BCD的代码库,不想弄乱它们的CMake配置。
这是我当前的目录结构:

A/
├── build/
├── CMakeLists.txt
│ 
├── B/
│   └── CMakeLists.txt
├── C/
│   ├── CMakeLists.txt
│   └── D/
│       └── CMakeLists.txt
|
├── include/
├── src/
│   └── CMakeLists.txt
└── test/
    └── CMakeLists.txt

我的目标可以实现吗?我的源代码树结构是否正确?有没有什么聪明的方法可以解决这些问题?

6l7fqoea

6l7fqoea1#

基础直觉

如果你想在一个命令行调用中构建多个项目,你需要将它们都作为同一个生成的构建系统的一部分,或者使用the ExternalProject module,或者编写一个 Package 器脚本来为你调用多个构建系统。
据我所知,一般来说,一个生成的单一配置构建系统只能有一个总体构建配置(“调试”,“发布”等)。),并且单个生成的多配置只能具有多个“同类”配置(没有“混合”配置:“Debug”配置是“Debug”through and through,等等。如果你希望不同的项目都有自己的构建配置,这意味着你需要为每个项目提供自己生成的构建系统。要么我错过了什么,要么唯一的方法就是做一些丑陋的黑客,我不知道,即使我知道,我也不推荐。
当使用混合构建配置和多配置构建系统时,您可能需要查看the MAP_IMPORTED_CONFIG_<CONFIG> target propertyits 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 moduleexport() + include()合并,您将能够获得the ExternalProject module所需的一切(您还可以将其与使用安装的方法一起使用,这实际上不会增加手动步骤,我假设这是您想要避免的)。每个项目都有自己的buildsystem,但是configure和build的调用将由依赖的项目驱动(尽管您也可以使用cmake --build <build_dir>以正常的方式调用单个项目)。您特别感兴趣的是SOURCE_DIRBUILD_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
源代码外的构建不是一件坏事。它们使删除整个构建系统及其工件变得更容易,因为它们将它们与源代码树分开。

i86rm4rw

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,在构建期间获取等)。)是一个很大的麻烦源,并且使构建过程(和预设置)比需要的更困难(特别是在维护中)。拥有独立的依赖关系会让一切变得更容易。..但这是一个单独的故事;)

相关问题