cmakefmt-rust 0.1.1

A fast, correct CMake formatter
Documentation

CI Pages Coverage Crates.io

A blazing-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. No compromises.

Crates.io package name: cmakefmt-rust (CLI binary remains cmakefmt). This project is independent from other Rust implementations, including: azais-corentin/cmakefmt and yamadapc/cmakefmt.

Why cmakefmt?

  • 20× faster — not a typo. Geometric-mean speedup of 20.69x over cmake-format on 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 cmakefmt the shape 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.804 168.570 29.04×
catch2/CMakeLists.txt 230 5.768 105.614 18.31×
cli11/CMakeLists.txt 283 5.570 120.994 21.72×
cmake_cmbzip2/CMakeLists.txt 25 5.042 61.751 12.25×
googletest/CMakeLists.txt 36 5.004 62.439 12.48×
ggml/CMakeLists.txt 498 7.773 210.200 27.04×
llama_cpp/CMakeLists.txt 286 6.257 126.584 20.23×
llvm_tablegen/CMakeLists.txt 83 5.172 75.429 14.58×
mariadb_server/CMakeLists.txt 656 9.774 473.879 48.49×
nlohmann_json/CMakeLists.txt 237 5.705 138.936 24.35×
opencv_flann/CMakeLists.txt 2 4.719 51.497 10.91×
protobuf/CMakeLists.txt 351 6.226 111.802 17.96×
spdlog/CMakeLists.txt 413 9.204 213.649 23.21×
qtbase_network/CMakeLists.txt 420 8.146 284.355 34.91×

Geometric-mean speedup across the full corpus: 20.69×. On a 220-file batch, --parallel 8 improves throughput by 3.80× vs serial.

Full methodology and profiler notes: cmakefmt.dev/performance.html.

Refresh the pinned local corpus and generate local before/after review artefacts with:

python3 scripts/fetch-real-world-corpus.py
scripts/review-real-world-corpus.sh

Installation

Homebrew (macOS and Linux):

brew tap cmakefmt/cmakefmt
brew install cmakefmt

Or in one step:

brew install cmakefmt/cmakefmt/cmakefmt

Cargo:

cargo install cmakefmt-rust

Build from source:

git clone https://github.com/cmakefmt/cmakefmt
cd cmakefmt
cargo install --path .

Verify:

cmakefmt --version

Planned release channels and support levels are documented at cmakefmt.dev/release.html. Shell completion installation guidance lives in cmakefmt.dev/install.html.

Quick Start

1. Generate a starter config in your project root:

cmakefmt --dump-config > .cmakefmt.yaml

2. Dry-run — check your whole project without touching any files:

cmakefmt --check .

3. Apply formatting:

cmakefmt --in-place .

4. Format only the files you're about to commit:

cmakefmt --staged --check

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.1.1 --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:

cmakefmt --show-config-path src/CMakeLists.txt
cmakefmt --show-config src/CMakeLists.txt
cmakefmt --explain-config

Migrate from an existing cmake-format config:

cmakefmt --convert-legacy-config .cmake-format.py > .cmakefmt.yaml

Full config reference: cmakefmt.dev/config.html.

Formatter Disable Regions

Selectively opt out of formatting with barrier comments.

There are three barrier styles:

  1. Legacy cmake-format directives:

    # cmake-format: off
    set(MESSY_THING  a   b   c)   # kept verbatim
    # cmake-format: on
    
  2. Native directive barriers, using either cmakefmt or the shorter fmt spelling:

    # cmakefmt: off
    set(MESSY_THING  a   b   c)   # kept verbatim
    # cmakefmt: on
    
    # fmt: off
    set(MESSY_THING  a   b   c)   # kept verbatim
    # fmt: on
    
  3. 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 cmakefmt::{format_source, Config};

fn main() -> Result<(), cmakefmt::Error> {
    let src = r#"target_link_libraries(foo PUBLIC bar baz)"#;
    let out = format_source(src, &Config::default())?;
    println!("{out}");
    Ok(())
}

Full API docs: cmakefmt.dev/api.html.

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, release artifacts, and shell completions
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:

mdbook serve docs

Project Layout

cmakefmt/
├── docs/        # mdBook 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 orchestration
  • lib.rs: public library API
  • config/: config loading, merging, and legacy conversion
  • parser/: pest grammar, AST, and parse pipeline
  • spec/: built-in and user-defined command registry
  • formatter/: AST-to-doc formatting logic and comment handling
  • files.rs: file discovery and ignore handling

Development

cargo fmt --check                          # formatting
cargo clippy --all-targets -- -D warnings  # lints
cargo test                                 # all tests
cargo llvm-cov --workspace --all-targets   # coverage
cargo bench                                # benchmarks

Install pre-commit hooks:

pre-commit install
pre-commit install --hook-type pre-push

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:

cmakefmt --debug --check path/to/CMakeLists.txt

License

cmakefmt is dual-licensed under MIT or Apache-2.0 at your option.