Skip to main content

cpre

CI

cpre analyzes Boolean conditions in C and C++ preprocessor conditional blocks without parsing the surrounding translation unit. It finds dead and redundant branches, simplifies conditions with bounded ROBDD reasoning, and also exposes a concrete preprocessing API for downstream analyzers that need one selected, macro-expanded source representation.

Project status: Beta. The documented CLI and top-level Python API are intended for downstream integration, while broader real-world use may still uncover compatibility, modeling, or performance edges before 1.0.

What cpre provides

cpre has grown beyond a conditional-linting CLI into a set of focused, integration-oriented C/C++ preprocessing primitives. The surfaces are deliberately separate so callers can choose the level of interpretation they need:

  • Symbolic conditional analysis — finds dead and redundant branches and distinguishes exact from contextual simplifications using bounded, deterministic ROBDD-backed reasoning. Known macro assumptions can constrain proofs without silently turning unknown macros into false.
  • Exact Boolean proofs and witnesses — public APIs support satisfiability, implication, equivalence, exact simplification, and deterministic witness assignments, with explicit incomplete results when proof budgets are exhausted.
  • Lossless conditional structure — parse_conditionals() exposes source-preserving blocks, directives, tokens, physical ranges, recovery diagnostics, and C23 #elifdef/#elifndef structure for refactoring and source-aware tools.
  • Macro Boolean simplification and rewriting — analyzes object-like #define replacements with bounded ROBDD proofs, supporting both ordinary C truth semantics and opt-in symbolic-literal mode (--symbolic-literal 0 / --symbolic-zero). Dedicated simplify-macros / analyze-macros CLI commands and Python APIs (simplify_macros(), rewrite_macros()) report and safely apply proven-equivalent simplifications in-place.
  • Concrete preprocessing — preprocess_source() selects one configuration, tracks source-order macro state, performs bounded macro expansion (including variadics, stringification, token pasting, and __VA_OPT__), and preserves physical provenance through source mappings. External state is explicit through MacroConfiguration, deterministic preprocessing context, __has_include queries, and host-owned pragma handling.
  • Branch-covering configurations — cover_branches() (and cpre cover on the command line) generates a small, deterministic set of concrete macro configurations that together select every reachable conditional-branch outcome, verifies each one with concrete preprocessing, and reports unreachable or uncovered outcomes with reasons.
  • Conservative integration contracts — structured errors and diagnostics, deterministic ordering, explicit complete, partial and incomplete results, SARIF 2.1.0 findings, and downstream compatibility tests make it practical to embed cpre in analyzers and CI without parsing human-readable output or guessing about partial results.

The documentation index keeps the detailed contracts separate from this overview; the README is intentionally focused on the capabilities a new user should understand first.

Where to start

  • New here? Getting started installs cpre and walks through each command on a small sample project, with real output.
  • Setting up CI or a hook? The cookbook has ready-made recipes: exit-status gating, SARIF upload, pull-request-only checks, pre-commit, macro cleanup, configuration matrices.
  • Something failed or looks wrong? Troubleshooting maps each message and exit status to its cause and fix.
  • Embedding in Python? The API guide has a public API index and typical setups.

Installation

python -m pip install cpre
cpre --version

cpre needs Python 3.9 or later and has no runtime dependencies. For development:

git clone https://github.com/sahebbiswas/cpre.git
cd cpre
python -m pip install -e ".[dev]"

CLI quick start

Analyze one source file (evaluates both conditional directives and macro simplifications in a single pass):

cpre source.c

Preserve transient disabled controls with symbolic-zero semantics:

cpre --symbolic-zero source.c

Scan a directory recursively and emit SARIF:

cpre --recursive --sarif src > cpre.sarif

Fail CI when dead, redundant, or simplifiable branches/macros are found:

cpre --recursive --fail-on-findings src

The module form is equivalent:

python -m cpre source.c

Inspect simplified macro definitions or rewrite them safely in-place:

# Report-only mode (never modifies source)
cpre simplify-macros source.c

# Explicit in-place rewrite mode
cpre simplify-macros --rewrite source.c

# Preview the rewrite as a unified diff, or fail CI when a rewrite is available
cpre simplify-macros --diff source.c
cpre simplify-macros --check source.c

Select a concrete configuration and emit preprocessed source:

cpre preprocess source.c -D FEATURE
cpre preprocess source.c --compact
cpre preprocess source.c --list-unknown-macros   # macros the conditionals still need
cpre preprocess source.c --dump-macros -D FEATURE   # the macro environment cpre starts from
git show HEAD:source.c | cpre preprocess -D FEATURE -   # '-' reads stdin (named <stdin>)

Generate configurations that together exercise every reachable branch:

cpre cover source.c --skip-includes   # each line is an argument list for `cpre preprocess`

Quickly evaluate and simplify arbitrary Boolean expressions:

cpre test-input 'A && (A || B)'
cpre test-input --json '(A && B) || (A && !B)'

Exit status is 0 on completion, 1 for findings (with --fail-on-findings, or an uncovered cpre cover outcome or pending simplify-macros --check rewrite) and 2 when cpre could not finish. Status 2 is never a clean result. If analysis stops at a size limit, raise it with --max-atoms, --max-bdd-nodes or --max-work; --telemetry shows where the cost went.

By default, text and JSON reports show notable branches and simplified macros; --verbose includes unchanged branches and unsimplified macros. --json emits structural conditional trees alongside macro simplification results, while --sarif emits findings for static-analysis interchange. Specific analyses can be disabled with --no-macros or --no-conditionals. See the CLI guide for discovery rules, batch output, stderr behavior, and the 0/1/2 exit-status contract.

Python analysis quick start

import cpre

try:
    result = cpre.analyze_source(source_text, filename="example.c")
except cpre.CpreError as error:
    print(error.code, error.location, error.message)
else:
    for finding in result.findings:  # always proven, even when the result is partial
        print(finding.kind, finding.location, finding.reason)
    for diagnostic in result.incomplete:
        print("analysis incomplete:", diagnostic)

Always check result.complete before treating an empty finding set as clean. Bounded analysis never exposes findings derived from partial proofs: when some independent conditionals exceed a resource limit, result.partial is true, the findings cover the rest of the file, and result.incomplete_components describes what was not analyzed.

See the Python API integration guide for findings, simplifications, edits, assumptions, resource limits, structured errors, and compatibility expectations.

Concrete preprocessing quick start

preprocess_source() selects one configuration and returns a canonical coordinate/source-map-oriented representation:

import cpre

result = cpre.preprocess_source(
    source_text,
    filename="example.c",
    assumptions={"FEATURE": True},
)

if result.complete:
    canonical = result.source

Canonical output remains the default. If a caller explicitly wants a presentation-oriented compact view, it can opt in separately:

if result.complete:
    compact_source = cpre.compact(result)

compact() never runs automatically, and the canonical result.source_map describes result.source, not the compact view.

See Concrete preprocessing for macro configuration/state, mappings, removed-line provenance, deterministic predefined context, __has_include, pragma handling, incomplete results, and downstream-parser guidance.

Documentation

The documentation index links the full user and integration guides. Key references include:

The README uses absolute repository links so the same navigation works when rendered as the package long description on PyPI.

Development and testing

Install the development dependencies and run the suite:

python -m pip install -e ".[dev]"
python -m pytest

Release validation also builds both distributions and checks their metadata/long description:

python -m build
python -m twine check dist/*

GitHub Actions runs tests across supported Python versions on Linux, macOS, and Windows, plus a build/twine/public-wheel-contract job. The release workflow tests the built wheel and sdist, uploads to TestPyPI and checks that install before publishing to PyPI; see CONTRIBUTING.

When extending cpre, keep downstream integrations on the documented top-level cpre API. Preserve deterministic ordering, structured diagnostics, and complete/incomplete semantics rather than requiring consumers to parse human-readable output.

Versioning

cpre follows Semantic Versioning. The package version is defined once by cpre.__version__ and consumed by pyproject.toml during builds. Every pull request merged to main bumps it by one step (patch for fixes, docs and tooling; minor for new features and, while cpre is 0.x, deliberate compatibility breaks), and CI checks the bump. Releases are cut from main when it is stable, so not every version is published to PyPI. See CONTRIBUTING for the full rules.

0.7.0 marked the transition from Alpha to Beta. During Beta, the documented top-level API is intended for real integrations; compatibility-sensitive changes must be deliberate and called out as a Behaviour change: in the pull request and release notes.

License

Licensed under the Apache License, Version 2.0. See the repository license.

Metadata

Release files for cpre 0.40.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cpre 0.40.1
File Size Uploaded Provenance
cpre-0.40.1.tar.gz 291.0 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for cpre 0.40.1
File Interpreter ABI Platform
cpre-0.40.1-py3-none-any.whl Python 3 none any Details

Total release size: 460.0 kB

Release files / cpre-0.40.1.tar.gz

Download URL cpre-0.40.1.tar.gz
Size 291.0 kB
Tags Source
SHA-256 checksum
How to use checksums
e2514a812277fb69e76177f03ff54d245be093a450b030d9e52fb4137e5af809
BLAKE2b-256 checksum
How to use checksums
9ef1aad56e7e78f3662582386469c1c4cbc997ea267f0fae47370c348c9fd515
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.

Transparency log

Release files / cpre-0.40.1-py3-none-any.whl

Download URL cpre-0.40.1-py3-none-any.whl
Size 168.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b8b4e23ee49d83ad9513694932994842661bc21cc58f90ebc5da4d0ab01f1574
BLAKE2b-256 checksum
How to use checksums
fd01e46b4a02ec8ebbf0428cfcf8e2709503b1e102124605fff9d91bfcea57e6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.

Transparency log

Security for cpre 0.40.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for cpre-0.40.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page