From dd49517b031ea450dca88ad5e67904fbfa4b0226 Mon Sep 17 00:00:00 2001 From: Xianpeng Shen Date: Wed, 30 Sep 2026 15:07:38 +0300 Subject: [PATCH] docs: rework the README to the org layout and fix outdated facts Follow the layout the other cpp-linter READMEs move to: name, four badges, one sentence, a link line, then Quick start, Usage, topic sections, Used by, Contributing and License. Fix what no longer matches the code: the hooks install the newest wheel on every run instead of a bundled default, the mirrors-clang-format comparison, and the --export-fixes warning. Use full URLs so the PyPI page links work, and drop the duplicated sections. In examples/, drop --checks=.clang-tidy (a check glob, not a file), the unsupported "~80%" claim and rev v1.5.0. --- README.md | 327 ++++++++++++++----------------- examples/README.md | 10 +- examples/cmake/README.md | 4 +- examples/large-project/README.md | 2 +- 4 files changed, 152 insertions(+), 191 deletions(-) diff --git a/README.md b/README.md index 8a990b0..45c909f 100644 --- a/README.md +++ b/README.md @@ -1,76 +1,20 @@ # cpp-linter-hooks -[![PyPI](https://img.shields.io/pypi/v/cpp-linter-hooks?color=blue)](https://pypi.org/project/cpp-linter-hooks/) -[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/cpp-linter-hooks)](https://pypi.org/project/cpp-linter-hooks/) -[![codecov](https://codecov.io/gh/cpp-linter/cpp-linter-hooks/branch/main/graph/badge.svg?token=L74Z3HZ4Y5)](https://codecov.io/gh/cpp-linter/cpp-linter-hooks) -[![Test](https://github.com/cpp-linter/cpp-linter-hooks/actions/workflows/test.yml/badge.svg)](https://github.com/cpp-linter/cpp-linter-hooks/actions/workflows/test.yml) -[![CodeQL](https://github.com/cpp-linter/cpp-linter-hooks/actions/workflows/codeql.yml/badge.svg)](https://github.com/cpp-linter/cpp-linter-hooks/actions/workflows/codeql.yml) -[![cpp-linter hub](https://img.shields.io/badge/%F0%9F%8F%A0_cpp--linter_hub-%E2%86%90_home-22863a)](https://cpp-linter.github.io/) - -A pre-commit hook repository for C/C++ projects that installs and runs -`clang-format` and `clang-tidy` through the -[pre-commit](https://pre-commit.com/) framework. - -## Why cpp-linter-hooks? - -Use `cpp-linter-hooks` when you want the same C/C++ formatting and linting tools -to run consistently on developer machines and in CI without requiring every -developer to install LLVM tools manually. - -- Runs both `clang-format` and `clang-tidy` from one pre-commit repository. -- Installs clang tools from Python wheels for a cross-platform setup. -- Lets projects pin the clang tool version explicitly with `--version`. -- Supports project-native `.clang-format` and `.clang-tidy` configuration files. -- Auto-detects `compile_commands.json` for CMake and Meson-style build trees. -- Supports `clang-format` dry-run checks, verbose diagnostics, and opt-in - `clang-tidy` fixes. - -Compared with [`mirrors-clang-format`](https://github.com/pre-commit/mirrors-clang-format), -this project also provides `clang-tidy`, compile database discovery, explicit -tool-version selection, and richer diagnostics. See the [FAQ](#faq) for the full -comparison. +[![PyPI](https://img.shields.io/pypi/v/cpp-linter-hooks?labelColor=454a63&color=007ec6)](https://pypi.org/project/cpp-linter-hooks/) +[![ci](https://img.shields.io/github/actions/workflow/status/cpp-linter/cpp-linter-hooks/test.yml?branch=main&label=ci&labelColor=454a63)](https://github.com/cpp-linter/cpp-linter-hooks/actions/workflows/test.yml) +[![coverage](https://img.shields.io/codecov/c/github/cpp-linter/cpp-linter-hooks?labelColor=454a63)](https://codecov.io/gh/cpp-linter/cpp-linter-hooks) +[![part of cpp-linter](https://img.shields.io/badge/part%20of-cpp--linter-ffc20a?labelColor=454a63)](https://cpp-linter.github.io/) -> [!TIP] -> Using GitHub Actions for CI? Check out -> **[cpp-linter-action](https://github.com/cpp-linter/cpp-linter-action)** — -> our companion GitHub Action that runs the same tools in CI with rich PR reviews, -> thread comments, step summaries, and file annotations. - -## Quick Start - -Add this configuration to your `.pre-commit-config.yaml` file: - -```yaml -repos: - - repo: https://github.com/cpp-linter/cpp-linter-hooks - rev: v1.6.0 # Use the tag or commit you want - hooks: - - id: clang-format - args: [--style=Google] # Other coding style: LLVM, GNU, Chromium, Microsoft, Mozilla, WebKit. - - id: clang-tidy - args: ["--checks=boost-*,bugprone-*,performance-*,readability-*,portability-*,modernize-*,clang-analyzer-*,cppcoreguidelines-*"] -``` - -### Custom Configuration Files +[pre-commit](https://pre-commit.com/) hooks that pip-install the clang-format and clang-tidy +version you pin, on every developer's machine. -To use custom configurations like `.clang-format` and `.clang-tidy`: +[Website](https://cpp-linter.github.io/) · +[Get started](https://cpp-linter.github.io/getting-started/#before-every-commit) · +[Discussions](https://github.com/orgs/cpp-linter/discussions) -```yaml -repos: - - repo: https://github.com/cpp-linter/cpp-linter-hooks - rev: v1.6.0 - hooks: - - id: clang-format - args: [--style=file] # Loads style from .clang-format file - - id: clang-tidy # clang-tidy reads your .clang-tidy file by itself -``` +## Quick start -> [!TIP] -> The `rev` tag (e.g. `v1.6.0`) is the **project** version, not the clang tool version. Each release bundles a default version of `clang-format` and `clang-tidy` — check the [release notes](https://github.com/cpp-linter/cpp-linter-hooks/releases) to see which tool version a given `rev` ships with. To pin an exact tool version independently of the project release, use `--version` as shown below. - -### Custom Clang Tool Version - -To use specific versions of clang-format and clang-tidy (using Python wheel packages): +Add this configuration to your `.pre-commit-config.yaml` file: ```yaml repos: @@ -78,62 +22,47 @@ repos: rev: v1.6.0 hooks: - id: clang-format - args: [--style=file, --version=21] # Specifies version + args: [--style=file, --version=21] - id: clang-tidy - args: [--version=21] # Specifies version + args: [--version=21] ``` -> [!TIP] -> For production use, always pin the tool version explicitly with `--version` (e.g. `--version=21`) so upgrades to `cpp-linter-hooks` never silently change your linter version. +Run `pre-commit install` once in each clone. `--style=file` loads the style from your +`.clang-format` file, and clang-tidy reads your `.clang-tidy` file by itself. The clang-tidy hook +needs a `compile_commands.json`, which it looks for in `build/` and a few other directories (see +[Compilation database](https://github.com/cpp-linter/cpp-linter-hooks#compilation-database)); +leave it out if you only run clang-tidy in CI, for example with +[cpp-linter-action](https://cpp-linter.github.io/cpp-linter-action/). -### Compilation Database (CMake/Meson Projects) - -For CMake or Meson projects, clang-tidy works best with a `compile_commands.json` -file that records the exact compiler flags used for each file. Without it, clang-tidy -may report false positives from missing include paths or wrong compiler flags. +## Usage -The hook auto-detects `compile_commands.json` in common build directories (`build/`, -`out/`, `cmake-build-debug/`, `_build/`) and passes `-p ` to clang-tidy -automatically — no configuration needed for most projects: +### Custom clang tool version -```yaml -repos: - - repo: https://github.com/cpp-linter/cpp-linter-hooks - rev: v1.6.0 - hooks: - - id: clang-tidy - # Auto-detects ./build/compile_commands.json if present -``` +> [!TIP] +> The `rev` tag (e.g. `v1.6.0`) is the **project** version, not the clang tool version. Without +> `--version`, each hook installs the newest clang-format or clang-tidy wheel on PyPI at the time it +> runs, so the tool version can change without any change to your configuration, and the two hooks +> can run different LLVM versions. For production use, always pin the tool version explicitly +> with `--version`. -To specify the build directory explicitly: +- `--version=21` installs the newest 21.x wheel, and `--version=21.1.8` pins an exact release. + clang-tidy wheels are released separately from clang-format wheels and skip some releases, so + give clang-tidy the major version. +- clang-format wheels cover LLVM 6 to 23 and clang-tidy wheels LLVM 13 to 22. For a version without + a wheel, the hook fails and lists some of the versions that exist. +- The hook looks the version up on pypi.org every time it runs. Without network access it fails + when `--version` is set, and otherwise uses the clang-format or clang-tidy already installed. -```yaml - - id: clang-tidy - args: [--compile-commands=build] -``` +### clang-format -To disable auto-detection (e.g. in a monorepo where auto-detect might pick the wrong database): +To use a predefined coding style instead of your `.clang-format` file: ```yaml - - id: clang-tidy - args: [--no-compile-commands] + - id: clang-format + args: [--style=Google] # Other coding style: LLVM, GNU, Chromium, Microsoft, Mozilla, WebKit. ``` -To see which `compile_commands.json` the hook is using, add `-v`: - -```yaml - - id: clang-tidy - args: [--compile-commands=build, -v] -``` - -> [!NOTE] -> Generate `compile_commands.json` with CMake using `cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -Bbuild .` -> or add `set(CMAKE_EXPORT_COMPILE_COMMANDS ON)` to your `CMakeLists.txt`. -> `--compile-commands` takes the **directory** containing `compile_commands.json`, not the file path itself. - -## Output - -### clang-format Output +When clang-format changes a file, the hook fails and pre-commit stops the commit: ```bash clang-format.............................................................Failed @@ -141,7 +70,7 @@ clang-format.............................................................Failed - files were modified by this hook ``` -Here’s a sample diff showing the formatting applied: +Here’s a sample diff showing the formatting applied with `--style=Google`: ```diff --- a/testing/main.c @@ -156,35 +85,45 @@ Here’s a sample diff showing the formatting applied: + return 0; +} ``` + > [!NOTE] -> Use `--dry-run` in `args` of `clang-format` to print instead of changing the format, e.g.: +> Use `--dry-run` in `args` of `clang-format` to print instead of changing the format. +> In v1.6.0 the hook passes and prints nothing even when files need formatting; the fix is on +> `main` and not released yet. With the fix, the output looks like this: ```bash clang-format.............................................................Failed - hook id: clang-format -- exit code: 255 +- exit code: 1 -main.c:2:11: warning: code should be clang-formatted [-Wclang-format-violations] -int main() {for (;;) break; printf("Hello world!\n");return 0;} - ^ -main.c:2:13: warning: code should be clang-formatted [-Wclang-format-violations] +main.c:2:13: error: code should be clang-formatted [-Wclang-format-violations] int main() {for (;;) break; printf("Hello world!\n");return 0;} ^ -main.c:2:21: warning: code should be clang-formatted [-Wclang-format-violations] +main.c:2:21: error: code should be clang-formatted [-Wclang-format-violations] int main() {for (;;) break; printf("Hello world!\n");return 0;} ^ -main.c:2:28: warning: code should be clang-formatted [-Wclang-format-violations] +main.c:2:28: error: code should be clang-formatted [-Wclang-format-violations] int main() {for (;;) break; printf("Hello world!\n");return 0;} ^ -main.c:2:54: warning: code should be clang-formatted [-Wclang-format-violations] +main.c:2:54: error: code should be clang-formatted [-Wclang-format-violations] int main() {for (;;) break; printf("Hello world!\n");return 0;} ^ -main.c:2:63: warning: code should be clang-formatted [-Wclang-format-violations] +main.c:2:63: error: code should be clang-formatted [-Wclang-format-violations] int main() {for (;;) break; printf("Hello world!\n");return 0;} ^ ``` -### clang-tidy Output +### clang-tidy + +To set the checks in `args` instead of your `.clang-tidy` file, quote the whole option: inside +`[...]`, YAML splits an unquoted value at each comma. + +```yaml + - id: clang-tidy + args: ["--checks=boost-*,bugprone-*,performance-*,readability-*,portability-*,modernize-*,clang-analyzer-*,cppcoreguidelines-*"] +``` + +When clang-tidy reports a warning or an error, the hook fails: ```bash clang-tidy...............................................................Failed @@ -219,13 +158,55 @@ repos: args: [--fix] ``` -> [!WARNING] -> When `--fix` (or `-fix-errors`) is active, parallel execution via `--jobs`/`-j` is -> automatically disabled to prevent concurrent writes to the same header file. +### Compilation database + +For CMake or Meson projects, clang-tidy works best with a `compile_commands.json` +file that records the exact compiler flags used for each file. Without it, clang-tidy +may report false positives from missing include paths or wrong compiler flags. + +The hook auto-detects `compile_commands.json` in common build directories (`build/`, +`out/`, `cmake-build-debug/`, `_build/`) and passes `-p ` to clang-tidy +automatically — no configuration needed for most projects: + +```yaml +repos: + - repo: https://github.com/cpp-linter/cpp-linter-hooks + rev: v1.6.0 + hooks: + - id: clang-tidy + # Auto-detects ./build/compile_commands.json if present +``` + +To specify the build directory explicitly: + +```yaml + - id: clang-tidy + args: [--compile-commands=build] +``` + +To disable auto-detection (e.g. in a monorepo where auto-detect might pick the wrong database): + +```yaml + - id: clang-tidy + args: [--no-compile-commands] +``` + +> [!NOTE] +> Generate `compile_commands.json` with CMake using `cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -Bbuild .` +> or add `set(CMAKE_EXPORT_COMPILE_COMMANDS ON)` to your `CMakeLists.txt`. +> `--compile-commands` takes the **directory** containing `compile_commands.json`, not the file path itself. + +### Examples + +Two self-contained templates plus quick snippets for other common setups. + +- [CMake minimal config](https://github.com/cpp-linter/cpp-linter-hooks/tree/main/examples/cmake) +- [Large project `files:` regex](https://github.com/cpp-linter/cpp-linter-hooks/tree/main/examples/large-project) — scoping hooks for speed +- [Quick snippets](https://github.com/cpp-linter/cpp-linter-hooks/blob/main/examples/README.md) — Meson, clang-format-only, monorepo, CI, `compile_commands.json` ## Troubleshooting -### Performance Optimization +### Performance optimization > [!TIP] > For large codebases, if your `pre-commit` runs longer than expected, it is highly recommended to add `files` in `.pre-commit-config.yaml` to limit the scope of the hook. This helps improve performance by reducing the number of files being checked and avoids unnecessary processing. Here's an example configuration: @@ -254,10 +235,10 @@ or `-j`: ``` > [!WARNING] -> When using `--jobs`/`-j`, avoid sharing options that write to a single output file -> (for example `--export-fixes=fixes.yaml`) across parallel `clang-tidy` invocations. -> If you need `--export-fixes`, ensure each job writes to a unique file path to avoid -> corrupted or overwritten outputs. +> When `args` include `--fix`, `-fix`, `-fix-errors` or `--export-fixes`, the hook ignores +> `--jobs`. pre-commit itself still runs the hook on groups of files in parallel, so each group +> overwrites a shared `--export-fixes` file and fixes to the same header can collide. Add +> `require_serial: true` to the hook to run it once for all files. Alternatively, if you want to run the hooks manually on only the changed files, you can use the following command: @@ -267,12 +248,13 @@ pre-commit run --files $(git diff --name-only) This approach ensures that only modified files are checked, further speeding up the linting process during development. -### Verbose Output +### Verbose output > [!NOTE] > Use `-v` or `--verbose` in `args` to enable verbose output. > For `clang-format`, it shows the list of processed files. > For `clang-tidy`, it prints which `compile_commands.json` is being used (when auto-detected or explicitly set). +> pre-commit shows this output only when the hook fails; add `verbose: true` to the hook to see it on every run. ```yaml repos: @@ -285,65 +267,44 @@ repos: args: [--verbose] # Shows which compile_commands.json is used ``` -## Examples +## Compared with mirrors-clang-format -Two self-contained templates plus quick snippets for other common setups. - -- [CMake minimal config](examples/cmake/) — covers ~80% of C++ projects -- [Large project `files:` regex](examples/large-project/) — scoping hooks for speed -- [Quick snippets](examples/README.md) — Meson, clang-format-only, monorepo, CI, `compile_commands.json` - -## Used By - -

- MIT ACL - MIT ACL   - bazel-contrib - Bazel Contrib   - CodSpeedHQ - CodSpeed   - doldecomp - doldecomp   - HKUST-Aerial-Robotics - HKUST Aerial Robotics   -
- kubewarden - Kubewarden   - computationalgeography - Computational Geography   - IMSY-DKFZ - IMSY   - CONVINCE-Project - CONVINCE-Project   - and many more. -

- See the cpp-linter showcase for projects using cpp-linter tools. -

- -## FAQ - -### What's the difference between [`cpp-linter-hooks`](https://github.com/cpp-linter/cpp-linter-hooks) and [`mirrors-clang-format`](https://github.com/pre-commit/mirrors-clang-format)? +[mirrors-clang-format](https://github.com/pre-commit/mirrors-clang-format) is pre-commit's +mirror of the clang-format wheel. | Feature | `cpp-linter-hooks` | `mirrors-clang-format` | |----------------------------------|-------------------------------------------|----------------------------------------| -| Supports `clang-format` and `clang-tidy` | ✅ (`clang-format` & `clang-tidy`)| ✅ (`clang-format` only) | -| Custom configuration files | ✅ `.clang-format`, `.clang-tidy` | ✅ `.clang-format` | -| Specify tool version | ✅ via `--version` arg (e.g. `--version=21`) | ✅ via `rev` tag (e.g. `rev: v21.1.8`) | -| `rev` tag meaning | Project version — see release notes for bundled tool version | Equals the clang-format version directly | -| Supports passing format style string | ✅ via `--style` | ❌ | -| Verbose output | ✅ via `--verbose` | ❌ | -| Dry-run mode | ✅ via `--dry-run` | ❌ | -| Auto-fix mode | ✅ via `--fix` (clang-tidy only) | ❌ | -| Compilation database support | ✅ auto-detect or `--compile-commands` | ❌ | - - - +| Supports `clang-format` and `clang-tidy` | Both | `clang-format` only | +| Custom configuration files | `.clang-format`, `.clang-tidy` | `.clang-format` | +| Specify tool version | via `--version` arg (e.g. `--version=21`) | via `rev` tag (e.g. `rev: v21.1.8`) | +| `rev` tag meaning | Project version, not the tool version | Equals the clang-format version directly | +| Default file types | C, C++ | C, C++, C#, CUDA, Java, JavaScript, JSON, Objective-C, proto, textproto, Metal | +| Supports passing format style string | via `--style` | via `--style` | +| Verbose output | via `--verbose` | via `--verbose` | +| Dry-run mode | via `--dry-run` (v1.6.0 always passes) | via `--dry-run --Werror` | +| Auto-fix mode | via `--fix` (clang-tidy only) | No | +| Compilation database support | auto-detect or `--compile-commands` | No | + +## Used by + +These organizations run cpp-linter-hooks on their default branch: + +[ MIT ACL](https://github.com/mit-acl) · +[ Bazel Contrib](https://github.com/bazel-contrib) · +[ CodSpeed](https://github.com/CodSpeedHQ) · +[ doldecomp](https://github.com/doldecomp) · +[ HKUST Aerial Robotics](https://github.com/HKUST-Aerial-Robotics) · +[ Kubewarden](https://github.com/kubewarden) · +[ Computational Geography](https://github.com/computationalgeography) · +[ IMSY](https://github.com/IMSY-DKFZ) · +[ CONVINCE-Project](https://github.com/convince-project) + +The [showcase](https://cpp-linter.github.io/showcase/) lists more projects that use cpp-linter tools. ## Contributing -We welcome contributions! Whether it's fixing issues, suggesting improvements, or submitting pull requests, your support is greatly appreciated. +See the [contributing guide](https://github.com/cpp-linter/cpp-linter-hooks/blob/main/CONTRIBUTING.md) and [open an issue](https://github.com/cpp-linter/cpp-linter-hooks/issues) for bugs and feature requests. ## License -This project is licensed under the [MIT License](LICENSE). +This project is licensed under the [MIT License](https://github.com/cpp-linter/cpp-linter-hooks/blob/main/LICENSE). diff --git a/examples/README.md b/examples/README.md index d5bfbd5..ea0e53e 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,6 +1,6 @@ # Examples -- [CMake project](cmake/) — the default for ~80% of C++ projects +- [CMake project](cmake/) - [Large project `files:` regex](large-project/) — scoping hooks for speed ## Quick snippets @@ -19,13 +19,13 @@ meson setup build # auto-detect works with build/ ``` -Or point explicitly: `args: [--compile-commands=builddir, --checks=.clang-tidy]`. +Or point explicitly: `args: [--compile-commands=builddir]`. ### clang-tidy + compile_commands.json ```yaml - id: clang-tidy - args: [--compile-commands=build, --checks=.clang-tidy, --version=21, --jobs=4] + args: [--compile-commands=build, --version=21, --jobs=4] files: ^src/.*\.cpp$ ``` @@ -55,8 +55,8 @@ jobs: pre-commit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 with: { python-version: '3.11' } - uses: pre-commit/action@v3.0.1 ``` diff --git a/examples/cmake/README.md b/examples/cmake/README.md index 4d07ff7..3a1fda3 100644 --- a/examples/cmake/README.md +++ b/examples/cmake/README.md @@ -7,14 +7,14 @@ If you already have a CMake project, you need **two files**: ```yaml repos: - repo: https://github.com/cpp-linter/cpp-linter-hooks - rev: v1.5.0 + rev: v1.6.0 hooks: - id: clang-format args: [--style=file, --version=21] files: ^(src|include)/.*\.(cpp|cc|cxx|h|hpp)$ - id: clang-tidy - args: [--checks=.clang-tidy, --version=21] + args: [--version=21] files: ^(src|include)/.*\.(cpp|cc|cxx)$ ``` diff --git a/examples/large-project/README.md b/examples/large-project/README.md index 7d10da6..0311439 100644 --- a/examples/large-project/README.md +++ b/examples/large-project/README.md @@ -35,4 +35,4 @@ files: \.(c|h|s|S)$ - **Don't lint headers directly with `clang-tidy`** — they're processed when a `.cpp` includes them. Restrict to `files: ^src/.*\.cpp$`. - **Use `--jobs=N` for `clang-tidy`** — start with `N=2`, go up to CPU core count. -- **`--dry-run` for `clang-format` in CI** — fail with a readable diff instead of auto-committing formatting. +- **`--dry-run` for `clang-format` in CI** — report the lines that need formatting instead of changing the files.