Skip to main content

A CMake formatter and static analyzer

Project description

cmtk 🛠️

Rust License: MIT

cmtk (CMake Toolkit) is a high-performance, schema-driven CMake code formatter and analyzer built in Rust. It utilizes a lossless Concrete Syntax Tree (CST) pipeline to guarantee that formatting operations never destroy comments, whitespace, or any other source details.

Unlike general-purpose formatters or simple regular-expression tools, cmtk formats CMake files according to known function signature schemas. It can automatically discover schemas for custom CMake functions/macros by analyzing the codebase (e.g. looking for uses of cmake_parse_arguments), allowing for precise, semantic layouts without tedious manual configuration.


Key Features

  • Lossless CST Architecture: Built on top of the Rowan library (used in rust-analyzer) and the Logos lexer. The formatting pipeline guarantees tree.to_string() == original_source prior to styling, meaning comments, bracket arguments, and trivia are fully preserved.
  • Schema-Driven Formatting: Employs structural layouts based on CMake commands' signatures. It distinguishes positional arguments, options (flags), one-value keywords, and list keywords.
  • Auto-Schema Discovery: The cmtk scan subcommand inspects your macros and functions, parsing their inner cmake_parse_arguments calls to automatically generate configuration schemas.
  • Advanced List Wrapping Rules:
    • Packed: Packed by width (default for target names, components).
    • Path: One-per-line formatting for file lists, keeping singletons inline.
    • Command Arguments (command_argv): Retains executable and initial flags on the same line, wrapping trailing arguments.
    • N per Line: Groups arguments into sets of n (e.g., n = 2 for properties key-value pairs).
  • Searchability Preservation: Keeps the first argument (e.g., target names in set_target_properties, or variable names in set / option) on the opening line to maintain searchability via simple tools like grep.
  • Configurable: Settings are easily configured using a .cmtkrc file or a [tool.cmtk] section in pyproject.toml.

Installation

Ensure you have the Rust toolchain installed. Build the project using cargo:

git clone https://github.com/halide/cmtk.git
cd cmtk
cargo build --release

The resulting binary will be available at target/release/cmtk.


Usage

cmtk provides a CLI with three subcommands: format, scan, and parse.

1. Formatting Files

To format a CMake file and print the result to stdout:

cmtk format CMakeLists.txt

To format files in-place:

cmtk format -i CMakeLists.txt src/CMakeLists.txt

To check if files are formatted (useful in CI pipelines):

cmtk format --check CMakeLists.txt

Automated Schema Discovery during Format

You can point the formatter to files containing custom definitions (--scan-only) to teach it your custom command signatures on-the-fly:

cmtk format CMakeLists.txt --scan-only cmake/MyMacros.cmake

You can also instruct it to find all CMake files in your Git repository automatically:

cmtk format CMakeLists.txt --discover=git

2. Scanning / Schema Discovery

To scan custom CMake files, extract schemas, and output them in TOML:

cmtk scan cmake/MyMacros.cmake

To write/append the scanned schemas directly to your local .cmtkrc:

cmtk scan cmake/MyMacros.cmake --write

3. Parsing (Debug representation)

To inspect the raw lossless syntax tree produced by the parser:

cmtk parse CMakeLists.txt

Formatting Style Guidelines

For multiline commands, cmtk avoids visually random continuation indentation or alignment under the opening parenthesis. Instead, it aligns the closing parenthesis with the command name and applies block indentation.

Preferred (Block Indentation)

find_package(
    Halide_LLVM 21...99 REQUIRED
    COMPONENTS WebAssembly X86
    OPTIONAL_COMPONENTS AArch64 ARM Hexagon NVPTX PowerPC RISCV
)

List Layouts (list_type)

  • packed (Default): Packs items as long as they fit the line, wrapping them when they exceed the limit:

    target_link_libraries(
        MyTarget
        PUBLIC Halide_Runtime Halide_Headers Halide_Compiler Halide_Tools
        PRIVATE LLVMCore LLVMSupport LLVMAnalysis LLVMTarget
    )
    
  • path: Paths format one-per-line when multiple, but singletons stay inline.

    When there are multiple keyword blocks, they are all indented:

    target_sources(
        MyTarget
        PUBLIC
            include/Halide.h
            include/HalideBuffer.h
        PRIVATE
            src/Argument.cpp
            src/Bounds.cpp
            src/Buffer.cpp
    )
    

    When a list is at the end of the argument list (the last block) and no prior blocks were indented, it is flattened/de-dented to align with the keyword:

    target_sources(
        MyTarget
        PRIVATE
        src/file1.cpp
        src/file2.cpp
        src/file3.cpp
    )
    

    Similarly, if a singleton path is too long to fit inline and is in the last block, it wraps and is de-dented:

    target_sources(
        MyTarget
        PRIVATE
        extremely/long/path/to/some/nested/source/file/that/will/definitely/exceed/the/column/limit/to/verify/the/dedented/singleton/rule.cpp
    )
    
  • n_per_line (e.g. n = 2 for property pairs):

    set_target_properties(MyTarget
        PROPERTIES
        CXX_STANDARD 17
        CXX_STANDARD_REQUIRED YES
        EXPORT_NAME MyTarget
    )
    

Configuration

cmtk automatically discovers configuration by searching for .cmtkrc in the current directory first, then fallback to [tool.cmtk] in pyproject.toml.

Configuration Options

Option Type Default Description
indent_style string "space" Indentation style: "space" or "tab"
indent_width integer 4 Indent size in spaces
line_width integer 100 Target column boundary for wrapping
source_vertical_list_threshold integer 3 Number of items in the source after which packed lists are forced vertical (-1 to disable)
function_schemas table {} Mappings of lowercase CMake functions to custom format schemas

Example .cmtkrc (TOML)

indent_style = "space"
indent_width = 4
line_width = 100
source_vertical_list_threshold = 3

[function_schemas.my_custom_install]
no_break_first_argument = true
options = ["FORCE", "VERBOSE"]
one_value_keywords = ["DESTINATION", "RENAME"]
multi_value_keywords = [
    { name = "TARGETS", list_type = "packed" },
    { name = "FILES", list_type = "path" }
]

Example pyproject.toml integration

[tool.cmtk]
indent_style = "space"
indent_width = 4
line_width = 80

[tool.cmtk.function_schemas.add_halide_library]
no_break_first_argument = true
one_value_keywords = ["GENERATOR"]
multi_value_keywords = [
    { name = "SOURCES", list_type = "path" }
]

Architecture Overview

  1. syntax.rs: Defines token and node types (SyntaxKind) via logos derive macros and implements the rowan::Language trait (CmakeLanguage).
  2. lexer.rs: Feeds tokens, whitespace, and comments to the parser.
  3. parser.rs: Lossless recursive-descent parser that constructs a rowan::GreenNode syntax tree.
  4. cst.rs: Strongly typed AST wrappers for raw Rowans (such as CommandNode).
  5. schema.rs: Definitions for schema representations of CMake commands.
  6. analyzer.rs: Infers custom schemas by analyzing local CMake source trees.
  7. formatter.rs: Implements the layout engine, making formatting decisions based on line widths and schemas.

Development

Run tests, check formatting, and lint with the following cargo commands:

# Run unit, integration, and golden tests
cargo test

# Force-update the golden test specs
UPDATE_GOLDENS=1 cargo test

# Verify formatting
cargo fmt -- --check

# Run lints
cargo clippy -- -D warnings

License

This project is licensed under the MIT License. See LICENSE or project files for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

cmtk-0.1.0-py3-none-win_amd64.whl (943.8 kB view details)

Uploaded Python 3Windows x86-64

cmtk-0.1.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.1 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

cmtk-0.1.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.0 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64

cmtk-0.1.0-py3-none-macosx_11_0_arm64.whl (972.0 kB view details)

Uploaded Python 3macOS 11.0+ ARM64

cmtk-0.1.0-py3-none-macosx_10_12_x86_64.whl (1.0 MB view details)

Uploaded Python 3macOS 10.12+ x86-64

File details

Details for the file cmtk-0.1.0-py3-none-win_amd64.whl.

File metadata

  • Download URL: cmtk-0.1.0-py3-none-win_amd64.whl
  • Upload date:
  • Size: 943.8 kB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for cmtk-0.1.0-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 c7ce53be0b9dadd249f9b6d616f224b8b03cdc5c0840c98a175717cc8275c407
MD5 289de50ccdfcc5abbe9e3a74fe308805
BLAKE2b-256 b7d37bf5f52f1567a3dd5a5c4bedb59e3732b056de8854b52093838f4ced8939

See more details on using hashes here.

Provenance

The following attestation bundles were made for cmtk-0.1.0-py3-none-win_amd64.whl:

Publisher: release.yml on halide/cmtk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file cmtk-0.1.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for cmtk-0.1.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 357af9ece3ac0ef5719eadadc85feb886995b4f08e1d71d13b0eb5a94fc29b0b
MD5 0da4d15c20432c380c3dfe85cd3cfcd5
BLAKE2b-256 57c37206cd1e594eafac63710ddb3400546110393b105aefaedc706063fd45bf

See more details on using hashes here.

Provenance

The following attestation bundles were made for cmtk-0.1.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on halide/cmtk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file cmtk-0.1.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for cmtk-0.1.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 845492777391ad4d90be1b5528e8a0e9b933f4c2adf80a34f3c0b5953876d48a
MD5 26aa751bb8245240cabc4ab7bc70d702
BLAKE2b-256 4abc38eade6a6a7125e6348e5993520bb24e6cbc65e9838d71d5237bcf039e6a

See more details on using hashes here.

Provenance

The following attestation bundles were made for cmtk-0.1.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: release.yml on halide/cmtk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file cmtk-0.1.0-py3-none-macosx_11_0_arm64.whl.

File metadata

  • Download URL: cmtk-0.1.0-py3-none-macosx_11_0_arm64.whl
  • Upload date:
  • Size: 972.0 kB
  • Tags: Python 3, macOS 11.0+ ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for cmtk-0.1.0-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 1cb8ba7234988e699295524ccfd17c4e3beecc08ede9a0dcf61344bdb5bbb774
MD5 caf8a36257f2028aafd8a84ee5b93171
BLAKE2b-256 c1706b30662b7f0c19b7d89c6bb1f36351c4362789e3140037d9e93015238934

See more details on using hashes here.

Provenance

The following attestation bundles were made for cmtk-0.1.0-py3-none-macosx_11_0_arm64.whl:

Publisher: release.yml on halide/cmtk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file cmtk-0.1.0-py3-none-macosx_10_12_x86_64.whl.

File metadata

  • Download URL: cmtk-0.1.0-py3-none-macosx_10_12_x86_64.whl
  • Upload date:
  • Size: 1.0 MB
  • Tags: Python 3, macOS 10.12+ x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for cmtk-0.1.0-py3-none-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 3174813a0bfd1ff7757fd50420b9acf321a2eda98ed03fa06aaea9bb83705aed
MD5 d51a0fd09ce7dbb30591f8c61d845d08
BLAKE2b-256 46c231d5af3df91c020b9c878df825ae773b7e48d99ef48f81700bea75490a90

See more details on using hashes here.

Provenance

The following attestation bundles were made for cmtk-0.1.0-py3-none-macosx_10_12_x86_64.whl:

Publisher: release.yml on halide/cmtk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page