Skip to content

CLI reference

postc is the command-line entry point of the POST Compiler (console script postc = postc.cli:main). It exposes four subcommands over the compilation pipeline:

Command Purpose
check Check files against the POST Python subset
build Compile a POST Python file (and its POST imports) to native code
backends List registered backends and their availability
backend-info Show one backend's capabilities and tool status

A subcommand is required. Every parser accepts -h / --help (postc build --help prints the build flags below).

postc check FILE...
postc build FILE [options]
postc backends
postc backend-info BACKEND

postc check

Structurally checks each file against the POST Python subset — the same gate build runs first — and prints every violation with source context.

postc check src/kernels.py examples/gaussian.py

check accepts one or more FILE arguments. It exits 0 when all files are clean and 1 when any violations are found (the total count is printed to stderr).

postc build

Compiles the entry FILE and every POST module it imports through the selected backend, then links the objects into one native shared library (.so, or .dylib on macOS). A directory target builds its package entry — __post__.py if present, otherwise __init__.py.

postc build examples/gaussian.py           # -> examples/gaussian.so (.dylib on macOS)

Options

Flag Argument Description
--output, -o PATH Output artifact path. Defaults to <FILE> with the platform library suffix beside the source (or <name><EXT_SUFFIX> for --ext-module).
--prefix DIR Install the libpp<name> layout under DIR: lib/lib<name>.so, include/<name>.h, share/postc/<name>.json. Always emits the header and manifest.
--ext-module (flag) Build an importable CPython extension module instead of a plain shared library (registers each public ufunc as a real numpy.ufunc). Requires a backend with the ext_module capability — C only.
--module-name NAME Artifact / importable module name. Defaults to the file stem, or the package directory's name when the entry is __init__.py / __post__.py.
--emit-header (flag) Also write the C ABI header next to the output as <output>.h.
--emit-manifest (flag) Also write the JSON export manifest next to the output as <output>.json.
--search-path DIR Additional POST module source root for resolving imports. Repeatable.
--backend {c,qbe,llvm} Code-generation backend. Default: c, or $POSTC_BACKEND (see precedence).
--mode {debug,release} Build mode (see Build modes). Default: debug, or $POSTC_MODE.
--release / --debug (flag) Shorthand for --mode release / --mode debug.
--no-overflow-checks (flag) In a debug build, keep bounds checks and assertions but drop integer-overflow diagnosis (for code that relies on modular arithmetic).
--cc CMD C compiler command. Default: cc.
--cflags FLAG... Extra flags passed to both the compile and link steps.
--keep-c (flag) Keep the intermediate build directory (emitted .c / .ssa sources and objects) instead of deleting it.

build prints the artifact path on stdout, followed by the header and/or manifest paths when those flags are set (--prefix prints all three). It exits 0 on success, 1 on a build error (subset violation, IR/ABI error, or toolchain failure), and 2 for a misused invocation — an unknown $POSTC_BACKEND, or combining --prefix with --ext-module.

--prefix and --ext-module are separate build targets

They cannot be combined. Build the extension with --output pointing into the recipe's site-packages instead.

Examples

# Explicit output path
postc build examples/gaussian.py -o build/gaussian.so

# Emit the stable C ABI header and JSON manifest alongside the library
postc build src/lib.py --emit-header --emit-manifest

# Importable CPython extension module (C backend)
postc build mypkg/ --ext-module --module-name mypkg

# Lower the scalar/array kernel subset through QBE
postc build examples/blur.py --backend qbe

# Extra POST source root + a custom compiler and flags
postc build src/app.py --search-path vendor/ --cc clang --cflags -O3 -march=native

# Packaging layout: lib/, include/, share/postc/ under $PREFIX
postc build src/lib.py --prefix "$PREFIX"

Build modes

postc build defaults to a debug build — the mode that cannot silently disagree with CPython. --release (or --mode release) elides the runtime checks and is what the published benchmark numbers measure. The mode also honours $POSTC_MODE, with --mode/--release/--debug taking precedence.

Construct Debug (default) Release
Array subscript per-axis bounds check on the normalized index no check
assert evaluated; a failure reports and aborts not lowered, as python -O does
Integer + - * ** // %, unary -, abs overflow and division-by-zero diagnosed (the program aborts) wraps at the declared width
range(a, b, step) with a runtime step traps if step is zero no check
Float→int cast of NaN or ±infinity reports and aborts returns 0

The build mode is a frontend parameter: no backend branches on it, so a release artifact's IR is byte-identical to what it would have been without the modes existing. That invariant is what keeps a debug check from perturbing the QBE backend's loop optimizations in release. Integer arithmetic wraps in release and traps in debug — postc's answer to §4.1.1's requirement that a compiler document its overflow behaviour. See ADR-0002 for the full rationale and the measured cost (bounds checks are hoisted out of loops, so array code pays almost nothing).

postc build kernels.py                      # debug: checked
postc build kernels.py --release            # release: elided, benchmarked
postc build kernels.py --no-overflow-checks # debug, minus only the overflow diagnosis

postc backends

Lists every registered backend with its availability on this machine, the source it emits, and its capabilities.

postc backends
c       available     emits .c     caps: complex, ext_module
llvm    available     emits .ll    caps: (base)
qbe     available     emits .ssa   caps: (base)

available means the backend's external tools are present: a C compiler for c; the qbe binary and a C compiler for qbe; llvmlite and a C compiler for llvm. Capabilities are drawn from complex, ext_module, and float16; (base) means none of those optional features (the scalar/array kernel subset the QBE and LLVM backends share).

postc backend-info

Shows one backend's name, emitted source extension, availability, and the full capability triple.

postc backend-info c
name         : c
source ext   : .c
available    : True
capabilities : complex=True ext_module=True float16=False

Exits 2 if BACKEND is not a registered name.

Backend selection

The build backend is chosen at runtime with a fixed precedence:

  1. an explicit --backend {c,qbe,llvm} on the command line;
  2. otherwise the POSTC_BACKEND environment variable;
  3. otherwise the default, c.
POSTC_BACKEND=qbe postc build examples/gaussian.py   # env selects qbe
postc build examples/gaussian.py --backend c         # flag overrides env

--backend is validated against the registered backends. An invalid POSTC_BACKEND is not caught by that validation, so build reports it explicitly and exits 2:

error: unknown backend 'wasm' (from POSTC_BACKEND?); choose from: c, llvm, qbe

See the C, QBE, and LLVM backend pages for what each lowers, and the backend protocol for the registry.

Version

The postc CLI does not expose a --version flag. Query the installed package version directly:

python -c "import postc; print(postc.__version__)"