跳过正文
  1. Posts/

cpp-linter-hooks:C/C++ 项目最完整的 pre-commit 方案

·1665 字·4 分钟· ·
沈显鹏
作者
沈显鹏
Engineer. Builder. Maintainer.
目录

大家好,我是沈工。

如果你写过 Python 项目,大概率用过 pre-commit —— 在 git commit 之前自动跑一遍 blackruffmypy,格式不对就拦下来,问题多了甚至不让你提交。这套流程在 Python 生态里已经非常成熟。

但如果你写的是 C/C++,情况就不太一样了。

pre-commit 官方的 mirrors-clang-format 只支持格式化,lint 检查(clang-tidy)需要自己另外折腾。至于编译数据库自动检测、版本锁定、自动修复这些功能,更是想都不要想。

cpp-linter-hooks 就是来解决这个问题的。它在 pre-commit 里同时提供 clang-formatclang-tidy 两个 hook,并且把 C/C++ 项目实际需要的周边能力一并补齐了。


为什么不用 mirrors-clang-format?
#

先看一眼两者对比:

功能cpp-linter-hooksmirrors-clang-format
clang-format 支持
clang-tidy 支持
通过 --style 直接指定格式风格
通过 --version 锁定工具版本❌(靠 rev tag)
自定义 .clang-tidy 配置文件
编译数据库自动检测
--dry-run(只检查不修改)
--fix(自动修复 clang-tidy 问题)
--verbose 详细输出
并行执行(--jobs

mirrors-clang-format 做的事情很单一:下载一个 clang-format 二进制,然后跑在改动的文件上。如果你的项目只需要格式化,它够用。

但现实中的 C/C++ 项目,真正让人头疼的不是代码风格不统一,而是 clang-tidy 的那些静态分析检查 —— 内存泄漏、未定义行为、性能陷阱。这些才是 pre-commit 阶段最值得拦截的问题。


快速上手
#

在你的 .pre-commit-config.yaml 里加一段配置:

repos:
  - repo: https://github.com/cpp-linter/cpp-linter-hooks
    rev: v1.4.1
    hooks:
      - id: clang-format
        args: [--style=file]
      - id: clang-tidy
        args: [--checks=.clang-tidy]

然后:

pre-commit install
pre-commit run --all-files

第一次运行会从 PyPI 下载对应的 clang 工具,之后就会缓存在 pre-commit 的环境里。


几个实用的配置细节
#

锁定工具版本
#

一个容易被忽略的点:rev 是 cpp-linter-hooks 的项目版本,不是 clang 工具的版本。如果你不显式指定,每次升级 rev 都可能静默换掉 clang-format / clang-tidy 的版本,导致格式化结果不一致。

建议加上 --version

- id: clang-format
  args: [--style=file, --version=21]
- id: clang-tidy
  args: [--checks=.clang-tidy, --version=21]

这样工具版本就被锁定在 clang 21,不受项目 rev 升级影响。

编译数据库
#

clang-tidy 需要知道编译参数才能做准确的静态分析。如果你的项目用 CMake 或 Meson 构建,生成 compile_commands.json 之后,cpp-linter-hooks 会自动检测常见构建目录(build/out/cmake-build-debug/ 等),不需要额外配置。

也可以显式指定:

- id: clang-tidy
  args: [--compile-commands=build, --checks=.clang-tidy]

生成编译数据库的命令:

cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -Bbuild .

自动修复
#

clang-tidy 的 --fix 可以自动修复部分检查项的问题。cpp-linter-hooks 从 v1.4.0 开始支持这个参数,但默认不开 —— 因为自动修改源代码有风险,你需要自己判断是否信任它。

- id: clang-tidy
  args: [--checks=.clang-tidy, --fix]

注意:开启 --fix 后,并行执行(--jobs)会自动禁用,防止多个进程同时写入同一个头文件。

性能优化
#

大项目跑全量 clang-tidy 可能会比较慢。两种方式优化:

限制检查范围,用 files 过滤:

- id: clang-tidy
  args: [--checks=.clang-tidy, --version=21]
  files: ^(src|include)/.*\.(cpp|cc|cxx|h|hpp)$

开启并行

- id: clang-tidy
  args: [--checks=.clang-tidy, --jobs=4]

日常开发时,也可以只检查变更的文件:

pre-commit run --files $(git diff --name-only)

和 cpp-linter-action 的关系
#

如果你关注过 C/C++ 的 CI 工具,可能见过 cpp-linter-action(GitHub Marketplace 上 139 星)。它是一个 GitHub Action,在 CI 流水线里跑 clang-format 和 clang-tidy,然后把结果以 file annotations、thread comments、PR review 的形式展示出来。

cpp-linter-hooks 和它是同一组织下的两个互补工具:

  • cpp-linter-action:跑在 CI 里,面向 PR 审查流程
  • cpp-linter-hooks:跑在本地 git commit 之前,面向开发者日常提交

两者共用相同的 .clang-format.clang-tidy 配置,本地通过的代码到 CI 上也不会出问题。这是一种典型的"本地 + CI 双重保障"模式。


最后
#

cpp-linter-hooks 目前是我在 cpp-linter 组织下维护的主要项目之一。从 2022 年到现在,陆续加了版本锁定、编译数据库检测、自动修复、并行执行这些功能,基本上覆盖了 C/C++ 项目在 pre-commit 阶段的核心需求。

如果你在做 C/C++ 开发,或者维护一个 C/C++ 开源项目,可以试试把它加到 .pre-commit-config.yaml 里。几分钟就能跑起来,之后每次提交前自动检查格式和潜在问题,不用再等到 CI 红了才回头修。

  • GitHub:https://github.com/cpp-linter/cpp-linter-hooks
  • PyPI:https://pypi.org/project/cpp-linter-hooks/

有问题去 GitHub 提 Issue,欢迎反馈。

老司机们,我们下期见~


转载本站文章请注明作者和出处,请勿用于任何商业用途。欢迎关注公众号「沈显鹏」

相关文章

pi 项目里那些反直觉的设计:从 AGENTS.md 到「先把你的 PR 关掉」

·5526 字·12 分钟
读完 Mario Zechner 的「I’ve sold out」,又翻了 pi 仓库里的 AGENTS.md 和 CONTRIBUTING.md,我发现这个项目在很多地方都和常见的开源协作方式不太一样。新贡献者的 issue 和 PR 默认关闭、周末不 review、不懂代码就别提 PR。看起来很强硬,但背后其实是在认真处理一个问题:AI 时代,开源项目要怎么避免被低质量贡献拖垮。