Gersemi
Gersemi is a Python-based command-line formatter for CMake code, designed to make your CMakeLists.txt files and `.cmake` modules consistent and readable. It leverages a custom handwritten parser in Rust for robust and efficient formatting. The current version is 0.27.2, with frequent releases addressing bug fixes and introducing new features.
Common errors
-
gersemi: command not found
cause The `gersemi` command-line tool is not installed or not in your system's PATH.fixInstall the `gersemi` package using pip: `pip install gersemi`. Ensure your Python environment's script directory is in your PATH. -
My CMake files are formatted differently / more aggressively after upgrading Gersemi.
cause From version 0.27.0, the default behavior for 'unsafe' formatting changed from `false` to `true`. This means `gersemi` will, by default, apply more extensive formatting changes that might be considered 'unsafe' by some users.fixTo revert to the previous, less aggressive 'safe' formatting, run `gersemi format --safe <files...>` or configure `unsafe: false` in your `.gersemirc.toml`. -
Pre-commit hook fails to format CMake files or complains about missing commands.
cause The `pre-commit` configuration for `gersemi` is likely pointing to an incorrect or outdated repository, or `gersemi` isn't properly installed in the pre-commit environment.fixVerify your `.pre-commit-config.yaml` points to the correct repository for `gersemi`: `repo: https://github.com/BlankSpruce/pre-commit-gersemi`. Also, ensure `gersemi` is installed in your pre-commit environment by running `pre-commit install-hooks`.
Warnings
- breaking The default behavior of `gersemi` for 'unsafe' operations changed from `unsafe: false` to `unsafe: true` in version 0.27.0. This means formatting might be more aggressive by default, potentially introducing more changes to your CMake code.
- gotcha Gersemi's internal CMake parser was rewritten in Rust starting from version 0.27.0. While this improves performance and robustness, it might introduce subtle differences in how complex or edge-case CMake syntax is interpreted and formatted compared to previous versions.
- breaking For developers creating custom `gersemi` extensions, the extension API changed in version 0.26.0. Extensions are now required to specify a `signature` keyword (as one of `options`, `one_value_keywords`, or `multi_value_keywords`).
- gotcha The official `pre-commit` hook for `gersemi` is now maintained in a separate repository (`https://github.com/BlankSpruce/pre-commit-gersemi`). Referencing the main `gersemi` repository for the hook will not provide the latest or correct installation with wheels.
Install
-
pip install gersemi
Quickstart
import os
import subprocess
import tempfile
from pathlib import Path
# Create a temporary directory and CMake file for demonstration
with tempfile.TemporaryDirectory() as tmpdir_name:
tmp_path = Path(tmpdir_name)
cmake_file = tmp_path / "CMakeLists.txt"
original_content = """
cmake_minimum_required(VERSION 3.8)
project(MyProject CXX)
set(MY_VAR "Hello"
CACHE INTERNAL "A variable")
add_executable(my_app main.cpp
src/utils.cpp)
macro(MyMacro arg1 arg2)
message("Args: ${arg1} ${arg2}")
endmacro()
MyMacro(VALUE_ONE VALUE_TWO)
"""
cmake_file.write_text(original_content.strip())
print(f"--- Original {cmake_file.name} ---")
print(cmake_file.read_text())
# Run gersemi format command
try:
# Change current working directory for subprocess to find the file easily
process = subprocess.run(
["gersemi", "format", "CMakeLists.txt"],
cwd=tmp_path,
capture_output=True,
text=True,
check=True # Raise an exception for non-zero exit codes
)
print(f"\n--- gersemi command output ---")
print(process.stdout)
if process.stderr:
print(f"Stderr: {process.stderr}")
print(f"\n--- Formatted {cmake_file.name} ---")
print(cmake_file.read_text())
except FileNotFoundError:
print("\nERROR: 'gersemi' command not found.")
print("Please install it: pip install gersemi")
except subprocess.CalledProcessError as e:
print(f"\nERROR: gersemi exited with code {e.returncode}")
print(f"Stdout: {e.stdout}")
print(f"Stderr: {e.stderr}")