cpre
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/#elifndefstructure for refactoring and source-aware tools. - Macro Boolean simplification and rewriting — analyzes object-like
#definereplacements with bounded ROBDD proofs, supporting both ordinary C truth semantics and opt-in symbolic-literal mode (--symbolic-literal 0/--symbolic-zero). Dedicatedsimplify-macros/analyze-macrosCLI 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 throughMacroConfiguration, deterministic preprocessing context,__has_includequeries, and host-owned pragma handling. - Conservative integration contracts — structured errors and diagnostics, deterministic ordering, atomic 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.
Installation
python -m pip install cpre
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
Select a concrete configuration and emit preprocessed source:
cpre preprocess source.c -D FEATURE
cpre preprocess source.c --compact
Quickly evaluate and simplify arbitrary Boolean expressions:
cpre test-input 'A && (A || B)'
cpre test-input --json '(A && B) || (A && !B)'
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:
if not result.complete:
for diagnostic in result.incomplete:
print("analysis incomplete:", diagnostic)
else:
for finding in result.findings:
print(finding.kind, finding.location, finding.reason)
Always check result.complete before treating an empty finding set as clean. Bounded analysis never exposes findings derived from partial proofs.
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:
- Command-line interface
- Python API integration
- Macro Boolean simplification
- Concrete preprocessing
- Compact preprocessing output
- Macro expansion
- Concrete macro configuration
- Concrete conditional expressions
- Host-assisted
__has_include - Pragma handling
- SARIF output
- Downstream compatibility
- pcpp replacement readiness
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.
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
The package version is defined by cpre.__version__ and consumed by pyproject.toml during builds.
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 should be deliberate and documented. Incremental features and fixes generally use patch releases, while deliberate compatibility changes should be reflected more prominently in release planning.
License
Licensed under the Apache License, Version 2.0. See the repository license.
Metadata
Release files for cpre 0.15.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| cpre-0.15.0.tar.gz | 148.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| cpre-0.15.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 244.5 kB
Release files / cpre-0.15.0.tar.gz
| Download URL | cpre-0.15.0.tar.gz |
|---|---|
| Size | 148.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
48ec761d312eaccf632d03d730488e7fd8775e81e161acdf57a6b1a199d490b7
|
|
BLAKE2b-256 checksum How to use checksums |
07e7017a31952d53a9d3803d3f3bb61719a3ac88b3fc82a4383aaa71471df12a
|
| 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 6, 2026.
Transparency logRelease files / cpre-0.15.0-py3-none-any.whl
| Download URL | cpre-0.15.0-py3-none-any.whl |
|---|---|
| Size | 96.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ccd4830df1d291cb1f27c5565c565dbe529eb0dff3ca19d36318d08f83adbeff
|
|
BLAKE2b-256 checksum How to use checksums |
347717545abd7420efeb9d6b2148592e5290e481e5480cb197b7efb8ba5385dd
|
| 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 6, 2026.
Transparency log