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

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.0.tar.gz (7.1 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.0-py3-none-any.whl (7.5 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for zigcc_build-0.2.0.tar.gz
Algorithm Hash digest
SHA256 36c5752458a773a3eb9170a0554259ae6cb575b2d9d423364d86be3410a51339
MD5 f1b2028c04b62ea379a89c878471e59e
BLAKE2b-256 a25ecdb426a2d7ebb35cc8b7994a415622e7e5145544c866c9786d4c39f8c12e

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for zigcc_build-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4747a6bed28cf425b2bcc201a58f935dd4acf74caf25302623a7c23c5d1d80be
MD5 7f5b29cc90c96b22b83c900488e42b83
BLAKE2b-256 0ca7be143e9409f91b5d42a44e434e607d0c16e597a6b56c99d0b899b713d89e

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