A PEP 517 build backend using zig cc
Project description
zigcc-build-backend
A PEP 517 build backend that uses zig cc (via the ziglang Python package) to compile C/C++ extensions for Python.
This backend allows you to easily compile native Python extensions without needing a pre-installed C compiler on the system, as it leverages the portable Zig compiler toolchain distributed via PyPI.
How it works
When you build your project (e.g., using pip or build), this backend:
- Reads your
pyproject.tomlconfiguration. - Identifies the source files specified in
[tool.zigcc-build]. - Invokes
zig cc(provided by theziglangpackage) to compile these sources into a native extension module (.pydon Windows,.soon Linux/macOS). - Packages the result into a standard Python Wheel.
Usage
1. Configure [build-system]
In your pyproject.toml, specify zigcc-build as the build backend.
Option A: Using from PyPI (if published)
[build-system]
requires = ["zigcc-build"]
build-backend = "zigcc_build"
Option B: Using directly from GitHub
[build-system]
requires = ["zigcc-build @ git+https://github.com/jrialland/zigcc-build.git"]
build-backend = "zigcc_build"
2. Configure [tool.zigcc-build]
Define your extension module settings in the [tool.zigcc-build] table.
[tool.zigcc-build]
# The name of the compiled extension module (optional).
# Defaults to the project name (with dashes replaced by underscores).
module-name = "my_extension"
# List of source files to compile (C or C++).
sources = ["src/main.c", "src/utils.c"]
# List of additional include directories (optional).
include-dirs = ["include"]
# List of compiler macros/defines (optional).
# Translates to -Dname or -Dname=value
defines = ["MY_MACRO=1", "DEBUG"]
# List of library directories (optional).
# Translates to -Lpath
library-dirs = ["libs"]
# List of libraries to link against (optional).
# Translates to -lname
libraries = ["m", "user32"]
# Optional python script to configure the build dynamically
configurer-script = "configure.py"
# List of python packages to include (optional).
# If omitted, the backend will try to auto-discover packages in 'src/' or the root directory.
packages = ["mypackage"]
Including Pure Python Code
The backend automatically detects and includes pure Python packages.
- If a
srcdirectory exists, it looks for packages insidesrc. - Otherwise, it looks for packages in the project root.
You can also explicitly specify packages to include using the packages option in [tool.zigcc-build].
Dynamic Configuration
If you specify a configurer-script, the backend will load this Python script and call a configure(config) function. This allows you to modify the build configuration dynamically (e.g., based on the platform or environment).
Example configure.py:
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from zigcc_build.config import ZigCcConfig
def configure(config: "ZigCcConfig"):
# config is a dictionary with keys: 'sources', 'include_dirs', 'defines', 'module_name'
print("Running custom configuration...")
# Add a define dynamically
config["defines"].append("DYNAMIC_MACRO=1")
# Add sources based on platform
import sys
if sys.platform == "win32":
config["sources"].append("src/windows_utils.c")
Configuration Schema
The configuration object passed to configure() follows this TypedDict schema:
class ZigCcConfig(TypedDict):
sources: List[str] # List of source files to compile
include_dirs: List[str] # List of include directories
defines: List[str] # List of compiler macros
library_dirs: List[str] # List of library directories
libraries: List[str] # List of libraries to link against
module_name: str # The name of the extension module
packages: List[str] # List of python packages to include
3. Build
You can build your project using standard Python tooling:
# Install the package in editable mode
pip install -e .
# Build a wheel and sdist
python -m build
PEP 621 Metadata Support
The zigcc-build backend fully supports PEP 621 metadata fields defined in your pyproject.toml. All metadata is automatically included in the generated wheel's METADATA file and the source distribution's PKG-INFO file.
Supported Metadata Fields
- name - Package name
- version - Package version
- description - Short one-line summary
- readme - Long description from README file (supports
.md,.rst,.txt) - requires-python - Python version requirements
- license - License information (text or file)
- authors - List of authors with name and email
- maintainers - List of maintainers with name and email
- keywords - List of keywords for PyPI
- classifiers - List of PyPI classifiers
- urls - Project URLs (Homepage, Repository, Issues, etc.)
- dependencies - Runtime dependencies
- optional-dependencies - Optional dependency groups
Example with Full Metadata
[build-system]
requires = ["zigcc-build"]
build-backend = "zigcc_build"
[project]
name = "my-package"
version = "1.0.0"
description = "A package with C extensions"
readme = "README.md"
requires-python = ">=3.12"
license = {text = "MIT"}
authors = [
{name = "Your Name", email = "you@example.com"}
]
keywords = ["c-extension", "zig", "compiler"]
classifiers = [
"Development Status :: 4 - Beta",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3.12",
]
dependencies = [
"numpy>=1.20",
]
[project.urls]
Homepage = "https://github.com/user/my-package"
Repository = "https://github.com/user/my-package"
Issues = "https://github.com/user/my-package/issues"
[tool.zigcc-build]
module-name = "my_extension"
sources = ["src/extension.c"]
The backend will automatically generate complete METADATA and PKG-INFO files with all this information, ensuring your packages are fully compliant with PyPI requirements.
Example pyproject.toml
Here is a complete example for a project named demo-package:
[build-system]
requires = ["zigcc-build"]
build-backend = "zigcc_build"
[project]
name = "demo-package"
version = "1.0.0"
description = "A demo package built with zigcc"
readme = "README.md"
requires-python = ">=3.7"
[tool.zigcc-build]
module-name = "demo"
sources = ["src/hello.c"]
Requirements
- Python >= 3.7
- The
ziglangpackage (automatically handled by the build system requirements).
Tutorial: Building the Demo Project
This repository includes a demo-project to illustrate how to use zigcc-build.
1. Install the backend locally
Since zigcc-build is not yet on PyPI, you need to install it in your environment first.
# From the root of the repository
pip install -e .
2. Build the demo project
Navigate to the demo-project directory and build it. We use --no-build-isolation because the backend is installed locally, not from PyPI.
cd demo-project
python -m build --no-isolation
3. Install and Test
Install the generated wheel and run the tests.
# Install the generated wheel (replace * with the actual version/platform)
pip install dist/demo_package-*.whl --force-reinstall
# Run the tests
python -m pytest tests
4. Recompiling
To recompile after changing the C source code, simply run the build command again:
python -m build --no-isolation
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file zigcc_build-0.2.2.tar.gz.
File metadata
- Download URL: zigcc_build-0.2.2.tar.gz
- Upload date:
- Size: 10.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9c7f58e4d1349e1d537cd016adca0128f9e0b244a280e34cb2580c6219dd3691
|
|
| MD5 |
9e388442b96390327e793f8fd35f9d26
|
|
| BLAKE2b-256 |
96fd58b258c44206ab48b48c9e454a22b10cf17f440dceaed7c5cc6e96100ac8
|
File details
Details for the file zigcc_build-0.2.2-py3-none-any.whl.
File metadata
- Download URL: zigcc_build-0.2.2-py3-none-any.whl
- Upload date:
- Size: 9.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
895b7a6f5f2a5f243b2c1d1489db7743ff4081a914dbaf501abc1bedf1789c9f
|
|
| MD5 |
edea9189db12bbadddb62e415fc0813b
|
|
| BLAKE2b-256 |
8999793737d9a91fae2a08a7e6a74188bc2d3a88fabc14da9d1c28508341f06b
|