cmakefmt-rust 0.1.1

A fast, correct CMake formatter
Documentation
<p align="center">
  <img src="assets/logo.png" alt="cmakefmt logo" width="100%"/>
</p>

<h1><code>cmakefmt</code></h1>

[![CI](https://github.com/cmakefmt/cmakefmt/actions/workflows/ci.yml/badge.svg)](https://github.com/cmakefmt/cmakefmt/actions/workflows/ci.yml)
[![Pages](https://github.com/cmakefmt/cmakefmt/actions/workflows/pages.yml/badge.svg)](https://github.com/cmakefmt/cmakefmt/actions/workflows/pages.yml)
[![Coverage](https://github.com/cmakefmt/cmakefmt/actions/workflows/coverage.yml/badge.svg)](https://github.com/cmakefmt/cmakefmt/actions/workflows/coverage.yml)
[![Crates.io](https://img.shields.io/crates/v/cmakefmt-rust.svg)](https://crates.io/crates/cmakefmt-rust)

**A blazing-fast, workflow-first CMake formatter — built in Rust, built to last.**

`cmakefmt` replaces the aging Python [`cmake-format`](https://github.com/cheshirekow/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`](https://github.com/azais-corentin/cmakefmt) and
[`yamadapc/cmakefmt`](https://github.com/yamadapc/cmakefmt).

<h2>Contents</h2>

- [Why `cmakefmt`?]#why-cmakefmt
- [Performance]#performance
- [Installation]#installation
- [Quick Start]#quick-start
- [Common Workflows]#common-workflows
- [Configuration]#configuration
- [Formatter Disable Regions]#formatter-disable-regions
- [Library Usage]#library-usage
- [Documentation]#documentation
- [Project Layout]#project-layout
- [Development]#development
- [Status]#status
- [License]#license

## 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](https://cmakefmt.dev/performance.html).

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

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

## Installation

**Homebrew (macOS and Linux):**

```bash
brew tap cmakefmt/cmakefmt
brew install cmakefmt
```

Or in one step:

```bash
brew install cmakefmt/cmakefmt/cmakefmt
```

**Cargo:**

```bash
cargo install cmakefmt-rust
```

**Build from source:**

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

Verify:

```bash
cmakefmt --version
```

Planned release channels and support levels are documented at [cmakefmt.dev/release.html](https://cmakefmt.dev/release.html).
Shell completion installation guidance lives in [cmakefmt.dev/install.html](https://cmakefmt.dev/install.html).

## Quick Start

**1. Generate a starter config in your project root:**

```bash
cmakefmt --dump-config > .cmakefmt.yaml
```

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

```bash
cmakefmt --check .
```

**3. Apply formatting:**

```bash
cmakefmt --in-place .
```

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

```bash
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`:

```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:

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

Migrate from an existing `cmake-format` config:

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

Full config reference: [cmakefmt.dev/config.html](https://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
    # cmake-format: off
    set(MESSY_THING  a   b   c)   # kept verbatim
    # cmake-format: on
    ```

1. Native directive barriers, using either `cmakefmt` or the shorter `fmt` spelling:

    ```cmake
    # cmakefmt: off
    set(MESSY_THING  a   b   c)   # kept verbatim
    # cmakefmt: on

    # fmt: off
    set(MESSY_THING  a   b   c)   # kept verbatim
    # fmt: on
    ```

1. Fence barriers, which toggle formatting on and off each time `# ~~~` appears:

    ```cmake
    # ~~~
    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:

```rust
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](https://cmakefmt.dev/api.html).

## Documentation

Start here: [https://cmakefmt.dev](https://cmakefmt.dev).

| Doc                                                                  | Description                                                              |
|----------------------------------------------------------------------|--------------------------------------------------------------------------|
| [Install]https://cmakefmt.dev/install.html                         | Install options, first-project setup, CI wiring                          |
| [Coverage]https://cmakefmt.dev/coverage.html                       | How coverage is measured, published, and interpreted                     |
| [Release Channels]https://cmakefmt.dev/release.html                | Release contract, support levels, release artifacts, and shell completions |
| [CLI Reference]https://cmakefmt.dev/cli.html                       | Every flag, exit code, and discovery rule                                |
| [Config Reference]https://cmakefmt.dev/config.html                 | Full config schema with examples                                         |
| [Formatter Behavior]https://cmakefmt.dev/behavior.html             | How the formatter makes layout decisions                                 |
| [Migration from `cmake-format`]https://cmakefmt.dev/migration.html | Incremental rollout guide and CLI mapping                                |
| [Library API]https://cmakefmt.dev/api.html                         | Embedding `cmakefmt` in your own Rust tools                              |
| [Troubleshooting]https://cmakefmt.dev/troubleshooting.html         | Common issues and debug workflow                                         |
| [Performance]https://cmakefmt.dev/performance.html                 | Benchmark methodology and profiler notes                                 |
| [Contributing]CONTRIBUTING.md                                      | How to contribute, run tests, and open PRs                               |
| [Changelog]CHANGELOG.md                                            | What's changed in each release                                           |

Preview the full docs locally:

```bash
mdbook serve docs
```

## Project Layout

```text
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

```bash
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:

```bash
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](https://cmakefmt.dev/troubleshooting.html) or run:

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

## License

`cmakefmt` is dual-licensed under [MIT](LICENSES/MIT.txt) or [Apache-2.0](LICENSES/Apache-2.0.txt) at your option.