Presets 文件结构:CMakePresets.json 与 CMakeUserPresets.json 的区别与作用

说实话,我刚接触 CMake Presets 那会儿,也被这两个文件搞晕过。为什么要有两个?一个不够用吗?

后来在团队里踩了几次坑,才真正理解了这个设计的精妙之处。今天我就把这两个文件的区别、作用,以及我个人的使用心得,一次性给你讲清楚。

一、两个文件,两种角色

简单来说,CMakePresets.json 是给项目用的,CMakeUserPresets.json 是给你自己用的。一个公开,一个私有。

特性 CMakePresets.json CMakeUserPresets.json
用途 项目级共享配置 个人/本地配置
是否提交到 Git ✅ 必须提交 ❌ 禁止提交
适用范围 所有开发者 仅当前用户
存放位置 项目根目录 项目根目录
优先级 低(被覆盖) 高(覆盖前者)

核心原则:CMakePresets.json 放「通用配置」,CMakeUserPresets.json 放「个人偏好」。两者通过 inherit 机制联动。

二、CMakePresets.json:团队的「标准答案」

这个文件是项目的官方配置。我一般会把它放在 Git 仓库里,所有开发者拉下来就能用。

它通常包含:

  • 项目必须的构建类型(Debug、Release、RelWithDebInfo)
  • 标准的编译选项(比如 -Wall -Wextra)
  • 公共的第三方依赖路径
  • CI/CD 流水线使用的配置

举个例子,我上一个项目是这样写的:

{
  "version": 6,
  "configurePresets": [
    {
      "name": "default",
      "displayName": "默认配置",
      "description": "适用于大多数开发者的标准配置",
      "generator": "Ninja",
      "binaryDir": "${sourceDir}/build/${presetName}",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Debug",
        "CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
      }
    },
    {
      "name": "release",
      "displayName": "发布版",
      "description": "生产环境构建",
      "inherits": "default",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Release",
        "ENABLE_OPTIMIZATION": "ON"
      }
    }
  ]
}

我的习惯:我会在 CMakePresets.json 里定义 3-5 个核心配置,覆盖 80% 的使用场景。太多了反而让人眼花缭乱。

三、CMakeUserPresets.json:你的「私人定制」

这个文件不会提交到 Git。它存在的意义,就是让你在不影响别人的情况下,调整自己的构建环境。

我经常用它来:

  • 覆盖本机的工具链路径(比如我 Mac 上装的是 Homebrew 的 GCC)
  • 添加个人常用的调试标志
  • 指定本机特有的缓存目录

你看,这就是我本机的配置:

{
  "version": 6,
  "configurePresets": [
    {
      "name": "my-debug",
      "displayName": "我的调试配置",
      "description": "个人调试用,加了更多日志",
      "inherits": "default",
      "cacheVariables": {
        "CMAKE_C_COMPILER": "/usr/local/bin/gcc-12",
        "CMAKE_CXX_COMPILER": "/usr/local/bin/g++-12",
        "ENABLE_VERBOSE_LOGGING": "ON"
      }
    }
  ]
}

我曾经踩过的坑:有次不小心把 CMakeUserPresets.json 提交到了 Git,结果同事拉下来后编译直接崩了——因为他的机器上没有我指定的那个编译器路径。从那以后,我每次提交前都会检查 .gitignore 里有没有加上这个文件。

四、两者的协作机制:inherit 继承

这两个文件不是孤立的。它们通过 inherit 字段串联起来。

流程是这样的:

  1. CMake 先加载 CMakePresets.json 里的配置
  2. 再加载 CMakeUserPresets.json 里的配置
  3. 如果同名,用户配置覆盖项目配置
  4. 如果用了 inherits,则从父配置继承所有字段

说白了,就是「项目定基调,你定细节」。

关键点:CMakeUserPresets.json 里的 preset 可以继承 CMakePresets.json 里的 preset,但反过来不行。项目配置不能依赖个人配置——这很合理,因为个人配置可能根本不存在。

五、知识体系结构图

下面这张图,把两个文件的关系和各自职责梳理清楚了:

CMake Presets 文件结构 CMakePresets.json 项目级 · 提交到 Git 📌 包含内容: • 构建类型(Debug/Release) • 标准编译选项 • 公共依赖路径 • CI/CD 配置 ⚠ 所有人共享,不可修改 inherit CMakeUserPresets.json 个人级 · 不提交到 Git 📌 包含内容: • 本机工具链路径 • 个人调试标志 • 本地缓存目录 • 覆盖项目配置 ✅ 自由修改,不影响他人 💡 两者通过 inherit 联动:项目定基调,个人定细节

六、实际项目中的最佳实践

我在几个中型项目里实践下来,总结了几条经验:

  • CMakePresets.json 要精简:只放团队共识的配置,别塞太多花哨的东西
  • CMakeUserPresets.json 要灵活:允许开发者自由发挥,但别破坏项目结构
  • 版本号要一致:两个文件的 version 字段必须相同,否则 CMake 会报错
  • 记得加 .gitignore:确保 CMakeUserPresets.json 不会被提交

我个人推荐的做法:在 CMakePresets.json 里定义好「骨架」,然后在 CMakeUserPresets.json 里用 inherits 继承并微调。这样既保证了团队一致性,又给了个人自由度。

嗯,这两个文件的关系,说白了就是「公共规范」和「私人定制」的平衡。理解了这一点,你就能用好 CMake Presets 了。


公众号:蓝海资料掘金营,微信 deep3321