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.