Skip to main content

A PEP 517 build backend using zig cc

Project description

zigcc-build-backend

Test 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:

  1. Reads your pyproject.toml configuration.
  2. Identifies the source files specified in [tool.zigcc-build].
  3. Invokes zig cc (provided by the ziglang package) to compile these sources into a native extension module (.pyd on Windows, .so on Linux/macOS).
  4. 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 src directory exists, it looks for packages inside src.
  • 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 ziglang package (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

zigcc_build-0.2.5.tar.gz (11.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

zigcc_build-0.2.5-py3-none-any.whl (10.3 kB view details)

Uploaded Python 3

File details

Details for the file zigcc_build-0.2.5.tar.gz.

File metadata

  • Download URL: zigcc_build-0.2.5.tar.gz
  • Upload date:
  • Size: 11.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for zigcc_build-0.2.5.tar.gz
Algorithm Hash digest
SHA256 fcd132ea42e44063064e56202aca754bb28dbd5761c6727e2bbeff1f39e2aaaf
MD5 173463e7904ad60a9a562c6f29cade23
BLAKE2b-256 d9f1a696fa5d96e2125c924fed1bd40d1be3162bf53f9420254874d5f4dd7dcd

See more details on using hashes here.

File details

Details for the file zigcc_build-0.2.5-py3-none-any.whl.

File metadata

  • Download URL: zigcc_build-0.2.5-py3-none-any.whl
  • Upload date:
  • Size: 10.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for zigcc_build-0.2.5-py3-none-any.whl
Algorithm Hash digest
SHA256 64b431eabf11a9b32420f96d67983126f663142ad517c3b463b9f66a6b8fa5a7
MD5 3cd2b264b7c824643adf269f5def16d8
BLAKE2b-256 bda4b42b5e9c6a2e56f0be4d990b46e9071a42697389f50d776b4769c071be2d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page