C Symbols, Headers, and Dependencies

Present several C symbols as one Python name

An authored contract can dispatch supported dtype and rank variants behind one Python name. Mark the concrete candidates @private, then name them with @overload(...).

Create overloads.c:

int scale_integer(int value) { return value * 2; }

double scale_real(double value) { return value * 2.0; }

Create overloads.pyi:

from prik.contracts import Float64, Int32, overload, private

@private
def scale_integer(value: Int32) -> Int32: ...

@private
def scale_real(value: Float64) -> Float64: ...

@overload("scale_integer")
def scale(value: Int32) -> Int32: ...

@overload("scale_real")
def scale(value: Float64) -> Float64: ...
python3 -m prik --language c overloads.pyi \
  --native-c-sources overloads.c \
  --compiler cc \
  --out overloads \
  --out-dir build
import sys

import numpy as np

sys.path.insert(0, "build")
import overloads

print(overloads.scale(np.int32(21)))
print(overloads.scale(np.float64(1.5)))
print([name for name in dir(overloads) if not name.startswith("_")])
42
3.0
['scale']

Candidates must remain distinguishable by their supported dtype and rank.

Qualifiers and compiler attributes

Use C qualifiers as constraints when authoring a contract: const T * must not be presented as writable NumPy storage. const and restrict do not add a separate Python type or calling convention.

Common non-ABI attributes such as deprecated and warn_unused_result do not change a wrapper. An attribute that may change the ABI, symbol identity, or layout stops the build instead of being ignored.

Compiler-preprocessed system headers may contain unavailable extended floating types in private declarations. PRIK can use those declarations as parsing context without adding wrapper support for the extended type. Prototype parameters may omit names; actual K&R definitions remain unsupported.

Symbols declared by binding headers

A header included by the generated binding may already declare the same name for a different API. Select that symbol for an isolated collision forwarder:

python3 -m prik --language c vendor.pyi \
  --native-library vendor \
  --collision-adapter evaluate \
  --out vendor_api --out-dir build

The build writes a separate forwarding translation unit that includes no Python header. Its signature uses the completed exact native C types:

long long evaluate(double x);

long long prik_collision_adapter_evaluate(double x) {
    return (evaluate)(x);
}

The adapter targets a real function symbol; PRIK does not expose macros. The forwarder has hidden visibility and works with or without --lto. Use --collision-adapter-all to adapt every eligible C source function.

This solves a declaration collision inside the generated binding. It does not choose between two linked libraries that export the same external symbol. Normal linker and loader resolution must already select the intended library.

A source-free .pyi contract must preserve every exact native scalar identity needed by the declaration. A target-generated contract does this automatically. See CLI Commands for selection, validation, and LTO options.

Build and inspect APIs

Use build_c_extension() for source builds or build_pyi_extension() for authored contracts from Python. See the Python API for those calls and CLI Commands for build, generation, Makefile, and inspection options.

Native dependencies

Pass public C source files as positional inputs. Add implementation-only C files with --native-c-sources, compiler flags with --native-c-compile-flags, existing objects with --native-objects, and libraries with --native-library and --native-library-dir.

For headers and conditional source, pass the native project's preprocessing configuration with -I, -D, --std, and, when available, --compile-commands build/compile_commands.json.

To wrap a reviewed subset of a broad or system header, list the public functions in a file and generate their contract:

python3 -m prik generate --pyi --language c api_probe.h \
  --include-exposure roots-only \
  --export-symbols reviewed_functions.txt \
  --out contracts/api.pyi

The export file selects the semantic API, not linker exports. Selected functions still need native link inputs and a signature supported by the C wrapper. See C include exposure for the file format and validation rules.

The Python API accepts already-resolved names:

build = build_c_extension(
    "api_probe.c",
    export_symbols=("evaluate", "normalize"),
    native_libraries=("vendor",),
)

Inspect a broader C API

The parser and contract generator accept more syntax than the supported wrapper surface. Use them to inspect declarations:

python3 -m prik parse --language c include/library.h --json
python3 -m prik semantics --language c include/library.h
python3 -m prik generate --pyi --language c include/library.h --out contracts/library.pyi

Pass the native preprocessing configuration when the header needs it:

python3 -m prik parse --language c include/library.h \
  -I include \
  -D LIBRARY_ENABLE_FAST=1 \
  --std c11 \
  --compile-commands build/compile_commands.json

Only declarations in the wrapped translation unit become a source build's public API; headers provide declarations and preprocessing context.

Next

See C Support for the complete supported surface, or continue with the libm and TA-Lib examples.