Contributing¶
The contents below are taken verbatim from README.coders at the
project root. It uses shell-style comment markers, not RST, so it is
embedded as a literal block.
This file contains notes to coders who want to contribute to the project.
#
# Development Setup
#
# Install development dependencies
uv pip install -e ".[dev]"
# On Termux (Android, aarch64), do NOT run the line above as-is. Use:
scripts/ct-venv-install-termux
# It handles the clang 21+ stringzilla CFLAGS and avoids the ruff sdist
# cargo build (which OOM-kills the device). See INSTALL section 6 or
# `scripts/ct-venv-install-termux --help` for the manual recipe and options.
# Install pre-commit hooks (required for all contributors). The project
# standardises on `prek` (a Rust drop-in for `pre-commit`, ~10× faster
# startup, single binary). prek is in [dev], so `uv pip install -e .[dev]`
# already put it in your venv; this just wires .git/hooks/pre-commit to it.
prek install
#
# Code Style
#
The code must run under Python 3.10+
Follow the PEP 8 style guide. Formatting and linting are enforced by ruff
via pre-commit hooks. You can also run them manually:
# Format code
ruff format src/compiletools/
# Lint code
ruff check src/compiletools/
# Auto-fix lint issues
ruff check --fix src/compiletools/
# Type-check
pyright src/compiletools/
Ruff configuration is in pyproject.toml under [tool.ruff]. Pyright is
configured under [tool.pyright] (venvPath = ".", venv = ".venv") so the
pre-commit hook's isolated env still resolves worktree dependencies.
#
# Pre-commit Hooks
#
Pre-commit hooks run automatically on every commit via prek. They enforce:
- Code formatting (ruff format)
- Linting (ruff check)
- Type checking (pyright)
- Trailing whitespace removal
- YAML/TOML validation
- Merge conflict detection
- Secret detection (detect-secrets)
To run all hooks against the entire codebase:
prek run --all-files
To skip hooks for a specific commit (not recommended):
git commit --no-verify
The hook config lives in .pre-commit-config.yaml. prek reuses that file
verbatim, so a contributor who already has the reference `pre-commit`
binary installed globally can substitute `pre-commit` for `prek` in any
of the commands above and get identical behaviour.
#
# Running tests
#
The project uses pytest as its testing framework:
# Run all tests
pytest src/compiletools
# Run tests in parallel (faster)
pytest src/compiletools -n auto
# Run specific test file
pytest src/compiletools/test_utils.py
# Run with verbose output
pytest src/compiletools -v
# Run pytest with crash-survivable diagnostics (useful on Termux/low-RAM
# devices where the OOM killer can SIGKILL the whole shell mid-test):
scripts/ct-pytest-monitor
# After a crash: tail -n1 /tmp/ct-pytest-monitor-*/checkpoint.log identifies
# the offending test. See scripts/ct-pytest-monitor --help for full docs.
#
# Caches/Performance
#
When you are doing performance testing there are 2 caches you need to be aware of
1) ccache: This can be cleaned by ccache -C
2) cake: Object files go to objdir (default: bin/<variant>/obj/).
Executables go to bindir (default: bin/<variant>/).
To clear: rm -rf bin
With --file-locking enabled, objdir may be a shared location
(e.g., <gitroot>/obj or /some/path/to/obj).
#
# Profiling
#
Three methods for profiling ct-cake and other ct-* commands:
# 1. Inline cProfile
source <compiletoolsrepo>/.venv/bin/activate && python -m cProfile -s cumulative $(which ct-cake) --auto
# 2. Project profiling script (supports any ct-* command, temp output dirs, metrics summary)
scripts/profile-ct ct-cake -d /path/to/project
scripts/profile-ct ct-compilation-database -d /path/to/project -- --include "dir1 dir2"
# 3. System-level profiling with py-spy (generates flame graph SVG)
py-spy record -o profile.svg -- python $(which ct-cake) --auto
#
# Build Timing
#
ct-cake supports --timing to collect per-phase build timing data.
See src/compiletools/README.ct-timing-report.rst for full documentation
of ct-timing-report and its output modes (TUI, summary, compare, chrome-trace).
#
# Gotchas
#
If you encounter any weird build issues (say due to a currently unknown bug in compiletools), then first try:
rm -rf bin
#
# Package Structure
#
src/compiletools/ - Main package code
*_backend.py - Pluggable build backends (make, ninja, cmake, bazel, shake, tup)
build_graph.py - Backend-agnostic IR (BuildRule, BuildGraph)
build_backend.py - BuildBackend ABC and backend registry
scripts/ - Shell script wrappers (ct-build, ct-release, etc.)
ct-* - Command-line entry points
pyproject.toml - Modern Python packaging configuration
#
# Worktree-Based Development
#
The repository uses a worktree layout: the `master` directory is the main
worktree under a parent directory (e.g., compiletools/master/).
Feature branches should be checked out as sibling worktrees:
# Create a worktree for a feature branch
git worktree add ../feature-x feature-x
# List worktrees
git worktree list
# Remove a worktree when done
git worktree remove ../feature-x
The profiling script `profile-ct-cake-worktree` creates temporary profiling
worktrees as siblings (e.g., compiletools/profile_worktree_master/).
#
# Making a release
#
Release-only tooling (twine) lives in the [release] extra so a plain dev
install stays minimal. Install it before publishing:
uv pip install -e ".[release]"
The ct-release script automates the release process. Read that script if you want to do each step manually.