A lightning-fast, workflow-first CMake formatter — built in Rust, built to last.
cmakefmt replaces the aging Python cmake-format tool with a
single native binary. Same spirit. No Python.
- crates.io:
cmakefmt-rust - CLI name:
cmakefmt
[!NOTE]
This project is independent from other Rust implementations, including:
azais-corentin/cmakefmtandyamadapc/cmakefmt.
- Why
cmakefmt? - Performance
- Installation
- Quick Start
- Common Workflows
- Configuration
- Formatter Disable Regions
- Library Usage
- Documentation
- Project Layout
- Development
- Status
- License
Why cmakefmt?
- 25× faster — not a typo. Geometric-mean speedup of
25.33xovercmake-formaton real-world corpora. Pre-commit hooks that once made you wince now finish before you blink. - Zero dependencies. One binary. No Python environment, no virtualenv bootstrap, no dependency drift. Drop it in CI and forget about it.
- Built for actual workflows.
--check,--diff,--staged,--changed,--files-from,--show-config,--explain-config, semantic verification, JSON reporting — all first-class, not scripted workarounds. - Knows your commands. Teach
cmakefmtthe argument structure of your project's custom CMake functions and macros. No more generic token-wrapping for code you wrote. - Errors that actually help. Parse and config failures come with file/line context, source snippets, and reproduction hints — not opaque parser noise.
- Designed for real repositories. Comment preservation, disable-region passthrough, config discovery, ignore files, Git-aware file selection, and opt-in parallelism are core features, not afterthoughts.
Performance
| Fixture | Lines | cmakefmt ms |
cmake-format ms |
Speedup |
|---|---|---|---|---|
abseil/CMakeLists.txt |
280 | 5.358 | 172.882 | 32.27× |
catch2/CMakeLists.txt |
230 | 5.177 | 110.495 | 21.34× |
cli11/CMakeLists.txt |
283 | 5.174 | 125.992 | 24.35× |
cmake_cmbzip2/CMakeLists.txt |
25 | 4.563 | 63.034 | 13.81× |
googletest/CMakeLists.txt |
36 | 4.376 | 65.244 | 14.91× |
ggml/CMakeLists.txt |
498 | 7.371 | 216.193 | 29.33× |
llama_cpp/CMakeLists.txt |
286 | 5.755 | 131.230 | 22.80× |
llvm_tablegen/CMakeLists.txt |
83 | 4.439 | 79.608 | 17.93× |
mariadb_server/CMakeLists.txt |
656 | 9.097 | 489.035 | 53.76× |
nlohmann_json/CMakeLists.txt |
237 | 5.035 | 140.580 | 27.92× |
opencv_flann/CMakeLists.txt |
2 | 4.263 | 54.812 | 12.86× |
protobuf/CMakeLists.txt |
351 | 5.478 | 114.711 | 20.94× |
spdlog/CMakeLists.txt |
413 | 6.461 | 220.804 | 34.17× |
qtbase_network/CMakeLists.txt |
420 | 7.852 | 293.745 | 37.41× |
xnnpack/CMakeLists.txt |
1354 | 26.965 | 1432.939 | 53.14× |
Geometric-mean speedup across the full corpus: 25.33×.
On a 220-file batch, --parallel 8 improves throughput by 3.80× vs serial.
Full methodology and profiler notes: cmakefmt.dev/performance/.
Update the pinned local corpus and generate local before/after review artifacts with:
Installation
Homebrew (macOS):
Cargo (any platform):
pip (any platform with Python):
conda-forge:
Pre-built binaries (Linux, macOS, and Windows):
Download the .zip / .tar.gz for your platform from
GitHub Releases,
extract, and place the binary on your PATH.
Build from source:
Verify:
Release channels and support levels are documented at cmakefmt.dev/release/. Shell completion installation instructions are available at cmakefmt.dev/install/.
Quick Start
1. Generate a starter config in your project root:
2. Dry-run — check your whole project without touching any files:
3. Apply formatting:
4. Format only the files you're about to commit:
Common Workflows
| Task | Command |
|---|---|
| Format file to stdout | cmakefmt CMakeLists.txt |
| Rewrite files in place | cmakefmt --in-place . |
| CI check | cmakefmt --check . |
| Preview which files would change | cmakefmt --list-changed-files . |
| See the exact patch | cmakefmt --diff CMakeLists.txt |
| Verify semantics while formatting to stdout | cmakefmt --verify CMakeLists.txt |
| Pre-commit guard (staged files only) | cmakefmt --staged --check |
| PR-scoped check | cmakefmt --changed --since origin/main --check |
| Machine-readable CI output | cmakefmt --check --report-format json . |
| GitHub Actions annotations | cmakefmt --check --report-format github . |
| Checkstyle / JUnit / SARIF output | cmakefmt --check --report-format checkstyle . |
| Pin the required binary version in CI | cmakefmt --required-version 0.9.0 --check . |
| Speed up repeated large-repo checks | cmakefmt --cache --check . |
| Roll out formatting file-by-file | cmakefmt --require-pragma --check . |
| Read from stdin | cat CMakeLists.txt | cmakefmt - |
Configuration
cmakefmt searches upward from each file for .cmakefmt.yaml, .cmakefmt.yml, or .cmakefmt.toml.
YAML is recommended for larger configs.
Example .cmakefmt.yaml:
format:
line_width: 100
tab_size: 4
style:
command_case: lower
keyword_case: upper
markup:
reflow_comments: true
Debug which config a file is actually using:
Migrate from an existing cmake-format config:
Full config reference: cmakefmt.dev/config/.
Formatter Disable Regions
Selectively opt out of formatting with barrier comments.
There are three barrier styles:
-
Legacy
cmake-formatdirectives:# cmake-format: off set(MESSY_THING a b c) # kept verbatim # cmake-format: on -
Native directive barriers, using either
cmakefmtor the shorterfmtspelling:# cmakefmt: off set(MESSY_THING a b c) # kept verbatim # cmakefmt: on # fmt: off set(MESSY_THING a b c) # kept verbatim # fmt: on -
Fence barriers, which toggle formatting on and off each time
# ~~~appears:# ~~~ set(MESSY_THING a b c) # kept verbatim # ~~~
Use directive barriers when you want an explicit start/end marker, and fence barriers when you want a shorter toggle-style block.
Library Usage
cmakefmt is also available as a Rust library:
use ;
Full API docs: cmakefmt.dev/api/.
Documentation
Start here: https://cmakefmt.dev.
| Doc | Description |
|---|---|
| Install | Install options, first-project setup, CI wiring |
| Coverage | How coverage is measured, published, and interpreted |
| Release Channels | Release contract, support levels, and release artifacts |
| CLI Reference | Every flag, exit code, and discovery rule |
| Config Reference | Full config schema with examples |
| Formatter Behavior | How the formatter makes layout decisions |
Migration from cmake-format |
Incremental rollout guide and CLI mapping |
| Library API | Embedding cmakefmt in your own Rust tools |
| Troubleshooting | Common issues and debug workflow |
| Performance | Benchmark methodology and profiler notes |
| Contributing | How to contribute, run tests, and open PRs |
| Changelog | What's changed in each release |
Preview the full docs locally:
&& &&
Project Layout
cmakefmt/
├── docs/ # Astro + Starlight source published to cmakefmt.dev
├── src/ # CLI, library API, parser, config, spec, formatter
├── tests/ # integration tests, snapshots, and fixtures
├── benches/ # Criterion benchmarks
├── scripts/ # repo maintenance and docs helpers
└── .github/ # CI and Pages workflows
Key modules under src/:
main.rs: CLI entry point and workflow orchestrationlib.rs: public library APIconfig/: config loading, merging, and legacy conversionparser/:pestgrammar, AST, and parse pipelinespec/: built-in and user-defined command registryformatter/: AST-to-doc formatting logic and comment handlingfiles.rs: file discovery and ignore handling
Development
Install pre-commit hooks:
Status
The repository is stable and actively maintained. cmakefmt is still
pre-1.0, so release packaging, package-manager distribution, and some output
or API details may continue to evolve. The built-in command registry is audited
through CMake 4.3.1.
Hit something unexpected? See Troubleshooting or run:
License
cmakefmt is dual-licensed under MIT or Apache-2.0 at your option.