如何优雅的使用CMakePresets

如何优雅的使用CMakePresets

前提

  1. CMake>=3.21

引入

通常情况下, 配置一个cmake项目是这样的

git clone http://www.gayhub.com/balabala/bala.git
cd balabala/
mkdir build && cd build
cmake -S .. -B . -DCMAKE_INSTALL_PREFIX=/path/to/install -DDEBUG_INFO=ON -DUSE_BOOST_STL=ON -DNO_COMPILE_VISION=ON \
    -DSOME_LIB_PATH=/path/to/some/lib -DANOTHER_LIB_PATH=/path/to/another/lib
make -j10
make install

这里, 随着我们的项目的扩大, 以及对不同平台的交叉编译的配置需求, 我们就需要不断的增加在cmake配置时引入的选项,
比如我们希望对这个编译结果使用这个版本的库, 对另一个编译结果使用另一个版本的库. 有的时候我们希望编译某个库,
有的时候我们不想编译某个库. 这在我们的项目中是很常见的.而且随着我们的项目规模的增加, 这种选项往往会越来越多.
很多时候我们会通过ccmake/cmake-gui的方式来对选项进行配置. 而这种方式往往很难分享给其他人, 而且随着交叉编译的规模增加,
这种手工配置的方式就不再适合我们了.

CMakePresets在这时候就起到了一个比较关键的作用, 在形式上, CMakePresets其实与VSCode的配置文件类似, 但是与VSCode不同,
CMakePreset并不关心你使用何种IDE. 只要你在命令行中指定对应的presets即可.

而这时候我们又会引入一个疑问, 既然仍然需要指定presets, 那岂不和我们直接用命令行的方式没有区别?

CMakePresets对此的解决方法是, 使用预设的继承, 宏以及不同级别之间的组合的方法, 来减少重复的配置选项.

例子

废话少说, 让我们用一个简单的例子来看看CMakePresets.json是什么结构.

{
  "version": 3,
  "cmakeMinimumRequired": {
    "major": 3,
    "minor": 19,
    "patch": 0
  },
  "configurePresets": [
    {
      "name": "default",
      "hidden": true,
      "cacheVariables": {
        "DEBUG_INFO": "ON",
        "USE_BOOST_STL": "ON",
        "NO_COMPILE_VISION": "ON",
        "SOME_LIB_PATH": "/path/to/some/lib",
        "ANOTHER_LIB_PATH": "/path/to/another/lib"
      },
      "environment": {},
      "vendor": {
        "jetbrains.com/clion": {
          "toolchain": "System"
        }
      }
    },
    {
      "name": "debug",
      "inherits": "default",
      "displayName": "configure for debug",
      "binaryDir": "${sourceDir}/build",
      "installDir": "/path/to/install",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Debug"
      }
    },
    {
      "name": "release",
      "inherits": "default",
      "displayName": "configure for debug",
      "binaryDir": "${sourceDir}/build-release",
      "installDir": "/path/to/install",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Release"
      }
    }
  ],
  "buildPresets": [
    {
      "name": "build-debug",
      "configurePreset": "debug",
      "configuration": "Debug",
      "jobs": 10,
      "verbose": true
    }
  ]
}

这个preset文件与上面的命令的作用是完全一致的.

通过观察我们不难发现, 文件中的cacheVariables字段的内容起到的作用就相当于在cmake的配置命令中的 -D{cmd} 的作用.
每个配置项中的binaryDir字段的作用与cmake命令中的 -B的作用是相同的.
配置项中的 installDir字段的作用与cmake命令中的 -DCMAKE_INSTALL_PREFIX作用相同.

configurePresets中, 第一个对象的 hidden字段被我们设置为true. 这一字段表示这个项目并不是真正的configurePreset,
而是作为其他的configurePreset的基础出现的. (作用类似Java中的abstract)

而第二个对象中, 其 inherits字段被设置为了default, 这一字段的作用为说明当前配置项继承自哪个配置项.
在这里我们将其继承自 default, 这时候我们的各种参数会默认被设置为 default中的提供的值. 与类的继承完全相同,
当我们在子类中指定某个字段的值的时候, 这个值就不再是父类中给出的值, 而是我们指定的值了.

第二个选项的 displayName字段比较有趣, 这个字段的内容用于说明当前配置项, 同样在cmake命令行中, 这个配置项的内容也会被展示在命令行输出中.
比如说, 我们在CMakePresets.json所在的目录下执行如下命令.

$ cmake --list-presets
Available configure presets:

  "debug"               - configure for debug
  "release"             - configure for release

可以看到, 我们使用了一个列出所有presets的命令, 这时候cmake就会把displayName中指定的值给打印出来了.

在这个例子中, 我们可以使用如下的命令来替代上面的又臭又长的命令

cmake --preset debug

cmake在执行这段命令后会自动检测所在文件夹的CMakePresets.json文件, 然后找到对应的preset进行configure.

当然, CMake同样提供了一个使用buildConfigure中的预设来进行编译的命令. 在上面的例子中, 我们执行如下命令.

cmake --build --preset build-debug

就可以让cmake自动的调用名称为 build-debug的编译预设.

一些宏

除了继承, CMakePresets还提供了一些比较方便使用的宏选项. 这个例子中, binaryDir中就使用了 ${sourceDir}宏.
这个宏会被展开为当前文件所在的目录路径.

这对于我们想在当前文件夹下的子文件夹下编译的时候会非常方便, 也省去了在不同机器上编译时的重新编写的成本.

环境变量

在CMake的configure过程中, CMake往往会调用一些环境变量, 而很多环境变量会随着不同的配置过程发生变化(
比如不同的github账号之类的), 这时候configurePreset中的environment字段就起到了作用.

vendor

不同的编译器厂商的自定义配置, 我习惯使用jetbrain, 所以这里我会让CMake去自动搜索CLion中提供的名为System的toolchain.

总结

CMakePresets为我们的交叉编译提供了一个非常强大而方便的集成. 通过CMakePresets我们可以简化不同的配置项目的配置命令与配置过程.

参考:

  1. cmake-presets.7.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值