pyoz build¶
Build your PyOZ module into a Python wheel package.
Usage¶
Options¶
| Option | Description |
|---|---|
-d, --debug |
Build in debug mode (default) |
-r, --release |
Build in release mode (optimized) |
--target <targets> |
Build for other platforms: comma-separated x86_64-linux, aarch64-linux, x86_64-macos, aarch64-macos, x86_64-windows, aarch64-windows, or all (default: this machine's platform) |
--python <version> |
CPython to build for, e.g. 3.12 or 3.14t (default: the python3 on PATH) |
--native |
Build for this machine's CPU and libc only; not for distribution |
--stubs |
Generate .pyi type stub file (default) |
--no-stubs |
Skip type stub generation |
-h, --help |
Show help message |
Build Modes¶
| Mode | Use Case |
|---|---|
| Debug (default) | Fast compilation, debug symbols, safety checks - best for development |
| Release | Optimized, smaller binary - best for distribution |
Portable wheels¶
Wheels run on other machines, not just the one that built them:
- Baseline CPU. No instructions only the build machine has (AVX-512 and the like), which would crash older CPUs with an illegal instruction.
- Linux: built against glibc 2.17, tagged
manylinux_2_17_<arch>(manylinux2014), which PyPI accepts and every current distribution can install. Setlinux-platform-tag = "manylinux_2_28_x86_64"in[tool.pyoz]to require a newer glibc instead. - macOS: built for macOS 13.0, the oldest version Zig 0.16 targets
(
macosx_13_0_<arch>). - Windows:
win_amd64/win_arm64.
The platform tag is read from the built binary (the highest glibc symbol
version it references, its minimum macOS version, its architecture), the way
auditwheel and delocate check wheels, so it is correct however the module was
built. A Linux module that links a library outside the manylinux set (for
example a system libfoo.so) is tagged linux_<arch> with a warning: PyPI
rejects those, so link such libraries statically.
--native skips all of this and builds for the exact machine (native CPU,
installed glibc); Linux native wheels are tagged linux_<arch>. pyoz develop
and pip install -e . always build natively.
Other platforms and Python versions¶
Zig cross-compiles, so one machine can build every wheel:
pyoz build --release --target all # six platforms, this Python
pyoz build --release --target aarch64-linux,x86_64-windows --python 3.13
pyoz build --release --python 3.14t # free-threaded, this platform
When the target or Python version differs from the build machine's, PyOZ
downloads that CPython's headers (and, for Windows, its import libraries) from
python-build-standalone,
verifies them against the release's SHA256SUMS, and caches them (only
include/ and libs/ are kept) in $PYOZ_CACHE_DIR, or by default
~/.cache/pyoz (Linux), ~/Library/Caches/pyoz (macOS) or
%LOCALAPPDATA%\pyoz (Windows). CPython 3.10 to 3.14 are available, plus
free-threaded 3.13t and 3.14t; 3.10 has no Windows ARM64 build, so
--target all skips it there.
Output¶
Wheel tags follow the Python the module was built for:
| Build | Tag |
|---|---|
| Regular CPython 3.12 | cp312-cp312-<platform> |
| Free-threaded CPython 3.14t | cp314-cp314t-<platform> |
abi3 = true |
cp310-abi3-<platform> (works on 3.10+) |
abi3 = true is rejected when building with a free-threaded interpreter: the
Stable ABI does not cover free-threaded builds.
Wheel Contents¶
The wheel includes:
- Compiled Zig extension (
.so/.pyd) - Type stubs (
.pyi) — unless--no-stubsis passed - Python packages listed in
py-packages(see configuration) - dist-info: WHEEL, METADATA, RECORD,
licenses/andentry_points.txt
METADATA comes from the [project] table (PEP 621): description, readme
(a path, or a table with file/text and content-type), license (an SPDX
expression such as "MIT", or a legacy { text = ... } / { file = ... }
table), license-files, authors, maintainers, keywords, classifiers,
urls, requires-python, dependencies and optional-dependencies.
[project.scripts], [project.gui-scripts] and [project.entry-points]
become entry_points.txt.
License files are shipped in <name>.dist-info/licenses/ (PEP 639): those
matching license-files, or by default any top-level LICEN[CS]E*,
COPYING*, NOTICE* and AUTHORS* files. An SPDX license cannot be
combined with License :: classifiers (PyPI rejects that), so the build
stops with an error if both are present.
pyoz develop¶
Build the extension and install the project in editable mode (PEP 660).
Usage¶
pyoz develop builds a standard editable wheel and installs it with pip into
the active environment. The wheel contains a __editable__.<name>-<version>.pth
file that points at the build output (zig-out/lib, or zig-out/bin on
Windows); for package layouts the extension is linked into the package
directory and the package's parent directory is added instead. A .pyi stub is
written next to the built module for IDEs.
- Rebuilds are picked up without reinstalling: run
zig buildorpyoz develop. - It is a normal install:
pip listshows it,pip uninstall <name>removes it. pip install -e .does the same through thepyoz.backendbuild backend.
pyoz publish¶
Publish wheel packages to PyPI.
Usage¶
Options¶
Only wheels in dist/ for the current project name and version are
uploaded; wheels left over from other versions are skipped (and reported),
since PyPI rejects re-uploads.
The upload carries the same metadata as the wheel's METADATA, so PyPI shows
the classifiers, license, links and readme from pyproject.toml. If PyPI
rejects a wheel, its explanation is printed, with a hint for common causes
(version already uploaded, non-portable platform tag, unknown classifier).
| Option | Description |
|---|---|
-t, --test |
Upload to TestPyPI instead of PyPI |
-h, --help |
Show help message |
Authentication¶
Set your API token as an environment variable:
| Variable | Description |
|---|---|
PYPI_TOKEN |
API token for PyPI |
TEST_PYPI_TOKEN |
API token for TestPyPI |
Generate tokens at pypi.org or test.pypi.org.