What is cibuildwheel?
mainauditwheel (Linux), delocate (macOS), and delvewheel (Windows).repository·main·Indexed 25 days ago
https://github.com/pypa/cibuildwheelA tool for automating the building and testing of Python wheels across multiple platforms (macOS, Linux, Windows, etc.) and Python implementations (CPython, PyPy, GraalPy) within CI environments such as GitHub Actions, Azure Pipelines, CircleCI, and GitLab CI. It handles shared library dependency bundling using auditwheel, delocate, and delvewheel, and supports configuration via pyproject.toml or CIBW_ environment variables.
auditwheel (Linux), delocate (macOS), and delvewheel (Windows).Use the MACOSX_DEPLOYMENT_TARGET environment variable to ensure backwards compatibility. cibuildwheel will cap your value to the lowest supported version for your specific architecture and Python version.
Note for Rust users: Rustc requires MACOSX_DEPLOYMENT_TARGET to be at least 10.12. Since cibuildwheel may default to 10.9 for certain Intel/CPython builds, you must manually set it to 10.12 or higher.
cibuildwheel supports x86_64 (Intel), arm64 (Apple Silicon), and universal2 (both architectures in one wheel).
macos.archs setting or CIBW_ARCHS_MACOS environment variable (e.g., CIBW_ARCHS_MACOS="x86_64 universal2").arm64 runners: You can test x86_64 and universal2 wheels using Rosetta 2.x86_64 runners: You can compile arm64 code, but you cannot test it. To suppress warnings when testing is impossible, use test-skip = ["*_arm64", "*_universal2:arm64"].wheel tags command.Building and testing wheels with cibuildwheel executes arbitrary code from your project and its dependencies. Even when using OCI containers or Pyodide, there are no security guarantees; the code being built has full access to the environment invoking cibuildwheel.
To maintain security hygiene:
When using [[tool.cibuildwheel.overrides]], you can control how tables and lists are merged with the existing configuration using the inherit key. This prevents you from having to repeat all original values when you only want to add or change one.
[[tool.cibuildwheel.overrides]]
select = "cp311*"
inherit.test-command = "prepend"
test-command = ["pyproject-before"]
[[tool.cibuildwheel.overrides]]
select = "cp311*"
inherit.environment = "append"
environment.NEWVAR = "Added!"Because iOS builds are cross-platform, the build environment uses a minimal PATH to avoid linking macOS-specific libraries into iOS binaries.
If your build process requires external tools (e.g., cmake, ninja, rustc, or even sub-dependencies like magick called by cmake), you must explicitly declare them using the xbuild-tools option. Every tool used anywhere in the build chain must be included in this list.
The [[tool.cibuildwheel.overrides]] array allows you to apply specific settings to builds that match a select string. The select string references a build identifier (not the wheel name).
Rules for overrides:
output-dir, build, skip, test_skip selectors, or architectures.before-all or the image will trigger the launch of new containers.[tool.cibuildwheel.linux]
before-all = "yum install mylib"
test-command = "echo 'installed'"
[[tool.cibuildwheel.overrides]]
select = "*-musllinux*"
before-all = "apk add mylib"Some options support placeholders that are substituted by cibuildwheel before they are used. Common placeholders include:
{project}{package}{wheel}If you need to use the literal name of a placeholder (e.g., you want the string {project} to appear literally in a command), prefix it with a hash character: #{project}. This is only necessary for strings that would otherwise be modified by substitution.
Building and testing wheels executes arbitrary code from your project and its dependencies. Although cibuildwheel uses OCI containers and Pyodide for some builds, these provide no security guarantees. The code you're building and testing has full access to the environment that's invoking cibuildwheel.
Best Practices:
cibuildwheel categorizes Pyodide releases into three types, which determine how users access them via the CIBW_ENABLE flag:
0.29.x / cp313). These are enabled by default and require no special flags.314.0.0a1 / cp314). Users must opt in using CIBW_ENABLE: pyodide-prerelease.CIBW_ENABLE: pyodide-eol for users needing to build for older ABIs.ABI3 wheels use the CPython Limited API to ensure forward compatibility across Python versions.
To build them, you must configure your build backend (e.g., setuptools) to compile using the Limited API. cibuildwheel automatically runs abi3audit after the repair step to verify that the resulting wheel does not violate the stable ABI. If violations are found, the build will fail.
To build manylinux, musllinux, macOS, and Windows wheels using GitHub Actions, you can use a workflow file that defines a matrix of operating systems. You must install cibuildwheel via pip and then run it using python -m cibuildwheel. Options for the build can be passed via environment variables prefixed with CIBW_.
name: Build
on: [push, pull_request]
jobs:
build_wheels:
name: Build wheels on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, windows-11-arm, macos-15-intel, macos-latest]
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
# Used to host cibuildwheel
- uses: actions/setup-python@v6
- name: Install cibuildwheel
run: python -m pip install cibuildwheel==4.1.1
- name: Build wheels
run: python -m cibuildwheel --output-dir wheelhouse
# to supply options, put them in 'env', like:
# env:
# CIBW_SOME_OPTION: value
# ...
- uses: actions/upload-artifact@v6
with:
name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }}
path: ./wheelhouse/*.whlTo avoid breaking builds due to unpinned versions, use Dependabot to manage updates.
If using pypa/cibuildwheel as a GitHub Action, pin to a minor version (e.g., @v4.1) to receive patch updates automatically. Use Dependabot for the github-actions ecosystem.
If using cibuildwheel via pip, create a dedicated requirements file (e.g., requirements-cibw.txt) containing only the cibuildwheel pin. Use Dependabot for the pip ecosystem.
# .github/dependabot.yml for GitHub Actions
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"# requirements-cibw.txt
cibuildwheel==4.1.1# .github/dependabot.yml for pip requirements
version: 2
updates:
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "daily"