Setup¶
Run cibuildwheel locally (optional)¶
Before getting to CI setup, it can be convenient to test cibuildwheel locally to quickly iterate and track down issues without even touching CI.
Install cibuildwheel and run a build like this:
# using pipx (https://github.com/pypa/pipx)
pipx run cibuildwheel
# or,
pip install cibuildwheel
cibuildwheel
You should see the builds taking place. You can experiment with options using environment variables or pyproject.toml.
Environment variables
cibuildwheel will read config from the environment. Syntax varies, depending on your shell:
POSIX shell (Linux/macOS)
# run a command to set up the build system
export CIBW_BEFORE_ALL='uname -a'
cibuildwheel
CMD (Windows)
set CIBW_BEFORE_ALL='uname -a'
cibuildwheel
pyproject.toml
If you write your options into pyproject.toml
, you can work on your options locally, and they'll be automatically picked up when running in CI.
pyproject.toml
[tool.cibuildwheel]
before-all = "uname -a"
Then invoke cibuildwheel, like:
cibuildwheel
Linux builds¶
If you've got Docker installed on your development machine, you can run a Linux build.
Tip
You can run the Linux build on any platform. Even Windows can run Linux containers these days, but there are a few hoops to jump through. Check this document for more info.
Because the builds are happening in manylinux Docker containers, they're perfectly reproducible.
The only side effect to your system will be docker images being pulled.
macOS / Windows builds¶
Pre-requisite: you need to have native build tools installed.
Because the builds are happening without full isolation, there might be some differences compared to CI builds (Xcode version, Visual Studio version, OS version, local files, ...) that might prevent you from finding an issue only seen in CI.
In order to speed-up builds, cibuildwheel will cache the tools it needs to be reused for future builds. The folder used for caching is system/user dependent and is reported in the printed preamble of each run (e.g. "Cache folder: /Users/Matt/Library/Caches/cibuildwheel").
You can override the cache folder using the CIBW_CACHE_PATH
environment variable.
Warning
cibuildwheel uses official python.org macOS installers for CPython but those can only be installed globally.
In order not to mess with your system, cibuildwheel won't install those if they are missing. Instead, it will error out with a message to let you install the missing CPython:
Error: CPython 3.6 is not installed.
cibuildwheel will not perform system-wide installs when running outside of CI.
To build locally, install CPython 3.6 on this machine, or, disable this version of Python using CIBW_SKIP=cp36-macosx_*
Download link: https://www.python.org/ftp/python/3.6.8/python-3.6.8-macosx10.9.pkg
Pyodide (WebAssembly) builds (experimental)¶
Pre-requisite: you need to have a matching host version of Python (unlike all
other cibuildwheel platforms). Linux host highly recommended; macOS hosts may
work (e.g. invoking pytest
directly in CIBW_TEST_COMMAND
is currently failing) and Windows hosts will not work.
You must target pyodide with --platform pyodide
(or use --only
on the identifier).
Configure a CI service¶
GitHub Actions [linux/mac/windows]¶
To build Linux, Mac, and Windows wheels using GitHub Actions, create a .github/workflows/build_wheels.yml
file in your repo.
Action
For GitHub Actions, cibuildwheel
provides an action you can use. This is
concise and enables easier auto updating via GitHub's Dependabot; see
Automatic updates.
.github/workflows/build_wheels.yml
name: Build
on: [push, pull_request]
jobs:
build_wheels:
name: Build wheels on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
# macos-13 is an intel runner, macos-14 is apple silicon
os: [ubuntu-latest, windows-latest, macos-13, macos-14]
steps:
- uses: actions/checkout@v4
- name: Build wheels
uses: pypa/cibuildwheel@v2.22.0
# env:
# CIBW_SOME_OPTION: value
# ...
# with:
# package-dir: .
# output-dir: wheelhouse
# config-file: "{package}/pyproject.toml"
- uses: actions/upload-artifact@v4
with:
name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }}
path: ./wheelhouse/*.whl
Use env:
to pass build options and with:
to set
package-dir: .
, output-dir: wheelhouse
and config-file: ''
locations (those values are the defaults).
pipx
The GitHub Actions runners have pipx installed, so you can easily build in just one line. This is internally how the action works; the main benefit of the action form is easy updates via GitHub's Dependabot.
.github/workflows/build_wheels.yml
name: Build
on: [push, pull_request]
jobs:
build_wheels:
name: Build wheels on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
# macos-13 is an intel runner, macos-14 is apple silicon
os: [ubuntu-latest, windows-latest, macos-13, macos-14]
steps:
- uses: actions/checkout@v4
- name: Build wheels
run: pipx run cibuildwheel==2.22.0
- uses: actions/upload-artifact@v4
with:
name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }}
path: ./wheelhouse/*.whl
Generic
This is the most generic form using setup-python and pip; it looks the most like the other CI examples. If you want to avoid having setup that takes advantage of GitHub Actions features or pipx being preinstalled, this might appeal to you.
.github/workflows/build_wheels.yml
name: Build
on: [push, pull_request]
jobs:
build_wheels:
name: Build wheels on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
# macos-13 is an intel runner, macos-14 is apple silicon
os: [ubuntu-latest, windows-latest, macos-13, macos-14]
steps:
- uses: actions/checkout@v4
# Used to host cibuildwheel
- uses: actions/setup-python@v5
- name: Install cibuildwheel
run: python -m pip install cibuildwheel==2.22.0
- name: Build wheels
run: python -m cibuildwheel --output-dir wheelhouse
- uses: actions/upload-artifact@v4
with:
name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }}
path: ./wheelhouse/*.whl
Commit this file, and push to GitHub - either to your default branch, or to a PR branch. The build should start automatically.
For more info on this file, check out the docs.
examples/github-deploy.yml
extends this minimal example with a demonstration of how to automatically upload the built wheels to PyPI.
Azure Pipelines [linux/mac/windows]¶
To build Linux, Mac, and Windows wheels on Azure Pipelines, create a azure-pipelines.yml
file in your repo.
azure-pipelines.yml
jobs:
- job: linux
pool: {vmImage: 'Ubuntu-20.04'}
steps:
- task: UsePythonVersion@0
- bash: |
set -o errexit
python3 -m pip install --upgrade pip
pip3 install cibuildwheel==2.22.0
displayName: Install dependencies
- bash: cibuildwheel --output-dir wheelhouse .
displayName: Build wheels
- task: PublishBuildArtifacts@1
inputs: {pathtoPublish: 'wheelhouse'}
- job: macos
pool: {vmImage: 'macOS-12'}
steps:
- task: UsePythonVersion@0
- bash: |
set -o errexit
python3 -m pip install --upgrade pip
python3 -m pip install cibuildwheel==2.22.0
displayName: Install dependencies
- bash: cibuildwheel --output-dir wheelhouse .
displayName: Build wheels
- task: PublishBuildArtifacts@1
inputs: {pathtoPublish: wheelhouse}
- job: windows
pool: {vmImage: 'windows-2019'}
steps:
- task: UsePythonVersion@0
- bash: |
set -o errexit
python -m pip install --upgrade pip
pip install cibuildwheel==2.22.0
displayName: Install dependencies
- bash: cibuildwheel --output-dir wheelhouse .
displayName: Build wheels
- task: PublishBuildArtifacts@1
inputs: {pathtoPublish: 'wheelhouse'}
Commit this file, enable building of your repo on Azure Pipelines, and push.
Wheels will be stored for you and available through the Pipelines interface. For more info on this file, check out the docs.
Travis CI [linux/windows]¶
To build Linux and Windows wheels on Travis CI, create a .travis.yml
file in your repo.
.travis.yml
os: linux
dist: focal
language: python
python: "3.12"
jobs:
include:
# perform a linux build
- services: docker
# perform a linux ARMv8 build
- services: docker
arch: arm64
# perform a linux PPC64LE build
- services: docker
arch: ppc64le
# perform a linux S390X build
- services: docker
arch: s390x
# and a windows build
- os: windows
language: shell
before_install:
- choco upgrade python -y --version 3.12.4
- export PATH="/c/Python312:/c/Python312/Scripts:$PATH"
# make sure it's on PATH as 'python3'
- ln -s /c/Python312/python.exe /c/Python312/python3.exe
install:
- python3 -m pip install cibuildwheel==2.22.0
script:
# build the wheels, put them into './wheelhouse'
- python3 -m cibuildwheel --output-dir wheelhouse
Commit this file, enable building of your repo on Travis CI, and push.
Then setup a deployment method by following the Travis CI deployment docs, or see Delivering to PyPI. For more info on .travis.yml
, check out the docs.
examples/travis-ci-deploy.yml
extends this minimal example with a demonstration of how to automatically upload the built wheels to PyPI.
AppVeyor [linux/mac/windows]¶
To build Linux, Mac, and Windows wheels on AppVeyor, create an appveyor.yml
file in your repo.
appveyor.yml
environment:
matrix:
- APPVEYOR_BUILD_WORKER_IMAGE: Ubuntu2204
APPVEYOR_JOB_NAME: "linux-x64"
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
APPVEYOR_JOB_NAME: "windows-x64"
- APPVEYOR_BUILD_WORKER_IMAGE: macos-sonoma
APPVEYOR_JOB_NAME: "macos-x64"
stack: python 3.12
install: python -m pip install cibuildwheel==2.22.0
build_script: python -m cibuildwheel --output-dir wheelhouse
artifacts:
- path: "wheelhouse\\*.whl"
name: Wheels
Commit this file, enable building of your repo on AppVeyor, and push.
AppVeyor will store the built wheels for you - you can access them from the project console. Alternatively, you may want to store them in the same place as the Travis CI build. See AppVeyor deployment docs for more info, or see Delivering to PyPI below.
For more info on this config file, check out the docs.
CircleCI [linux/mac]¶
To build Linux and Mac wheels on CircleCI, create a .circleci/config.yml
file in your repo,
.circleci/config.yml
version: 2
jobs:
linux-wheels:
working_directory: ~/linux-wheels
docker:
- image: cimg/python:3.12
steps:
- checkout
- setup_remote_docker
- run:
name: Build the Linux wheels.
command: |
python3 -m pip install --user cibuildwheel==2.22.0
cibuildwheel --output-dir wheelhouse
- store_artifacts:
path: wheelhouse/
linux-aarch64-wheels:
working_directory: ~/linux-aarch64-wheels
machine:
image: default
# resource_class is what tells CircleCI to use an ARM worker for native arm builds
# https://circleci.com/product/features/resource-classes/
resource_class: arm.medium
steps:
- checkout
- run:
name: Build the Linux aarch64 wheels.
command: |
python3 -m pip install --user cibuildwheel==2.22.0
python3 -m cibuildwheel --output-dir wheelhouse
- store_artifacts:
path: wheelhouse/
osx-wheels:
working_directory: ~/osx-wheels
macos:
xcode: 15.4.0
resource_class: macos.m1.medium.gen1
steps:
- checkout
- run:
name: Build the OS X wheels.
command: |
sudo softwareupdate --install-rosetta --agree-to-license # for python<=3.8 or x86_64/universal2 tests
pip3 install cibuildwheel==2.22.0
cibuildwheel --output-dir wheelhouse
- store_artifacts:
path: wheelhouse/
workflows:
version: 2
all-tests:
jobs:
- linux-wheels
- linux-aarch64-wheels
- osx-wheels
Commit this file, enable building of your repo on CircleCI, and push.
Note
CircleCI doesn't enable free macOS containers for open source by default, but you can ask for access. See here for more information.
CircleCI will store the built wheels for you - you can access them from the project console. Check out the CircleCI docs for more info on this config file.
Gitlab CI [linux]¶
To build Linux wheels on Gitlab CI, create a .gitlab-ci.yml
file in your repo,
.gitlab-ci.yml
linux:
image: python:3.12
# make a docker daemon available for cibuildwheel to use
services:
- name: docker:dind
entrypoint: ["env", "-u", "DOCKER_HOST"]
command: ["dockerd-entrypoint.sh"]
variables:
DOCKER_HOST: tcp://docker:2375/
DOCKER_DRIVER: overlay2
# See https://github.com/docker-library/docker/pull/166
DOCKER_TLS_CERTDIR: ""
script:
- curl -sSL https://get.docker.com/ | sh
- python -m pip install cibuildwheel==2.22.0
- cibuildwheel --output-dir wheelhouse
artifacts:
paths:
- wheelhouse/
windows:
image: mcr.microsoft.com/windows/servercore:1809
before_script:
- choco install python -y --version 3.12.4
- choco install git.install -y
- py -m pip install cibuildwheel==2.22.0
script:
- py -m cibuildwheel --output-dir wheelhouse --platform windows
artifacts:
paths:
- wheelhouse/
tags:
- saas-windows-medium-amd64
macos:
image: macos-14-xcode-15
before_script:
- python3 -m pip install cibuildwheel==2.22.0
script:
- python3 -m cibuildwheel --output-dir wheelhouse
artifacts:
paths:
- wheelhouse/
tags:
- saas-macos-medium-m1
Commit this file, and push to Gitlab. The pipeline should start automatically.
Gitlab will store the built wheels for you - you can access them from the Pipelines view. Check out the Gitlab docs for more info on this config file.
Cirrus CI [linux/mac/windows]¶
To build Linux, Mac, and Windows wheels on Cirrus CI, create a .cirrus.yml
file in your repo,
.cirrus.yml
build_and_store_wheels: &BUILD_AND_STORE_WHEELS
install_cibuildwheel_script:
- python -m pip install cibuildwheel==2.22.0
run_cibuildwheel_script:
- cibuildwheel
wheels_artifacts:
path: "wheelhouse/*"
linux_x86_task:
name: Build Linux x86 wheels.
compute_engine_instance:
image_project: cirrus-images
image: family/docker-builder
platform: linux
cpu: 4
memory: 4G
env:
VENV_ROOT: ${HOME}/venv-cibuildwheel
PATH: ${VENV_ROOT}/bin:${PATH}
install_pre_requirements_script:
- add-apt-repository -y ppa:deadsnakes/ppa
- apt-get update
- apt-get install -y python3.12-venv
- python3.12 -m venv ${VENV_ROOT}
<<: *BUILD_AND_STORE_WHEELS
linux_aarch64_task:
name: Build Linux aarch64 wheels.
compute_engine_instance:
image_project: cirrus-images
image: family/docker-builder-arm64
architecture: arm64
platform: linux
cpu: 4
memory: 4G
env:
VENV_ROOT: ${HOME}/venv-cibuildwheel
PATH: ${VENV_ROOT}/bin:${PATH}
install_pre_requirements_script:
- add-apt-repository -y ppa:deadsnakes/ppa
- apt-get update
- apt-get install -y python3.12-venv
- python3.12 -m venv ${VENV_ROOT}
<<: *BUILD_AND_STORE_WHEELS
windows_x86_task:
name: Build Windows x86 wheels.
windows_container:
image: cirrusci/windowsservercore:visualstudio2022
cpu: 4
memory: 4G
install_pre_requirements_script:
- choco install -y --no-progress python3 --version 3.12.4
- refreshenv
- echo PATH=%PATH% >> "%CIRRUS_ENV%"
<<: *BUILD_AND_STORE_WHEELS
macos_arm64_task:
name: Build macOS arm64 wheels.
macos_instance:
image: ghcr.io/cirruslabs/macos-runner:sonoma
env:
VENV_ROOT: ${HOME}/venv-cibuildwheel
PATH: ${VENV_ROOT}/bin:${PATH}
install_pre_requirements_script:
- brew install python@3.12
- python3.12 -m venv ${VENV_ROOT}
<<: *BUILD_AND_STORE_WHEELS
Commit this file, enable building of your repo on Cirrus CI, and push.
Cirrus CI will store the built wheels for you - you can access them from the individual task view. Check out the Cirrus CI docs for more info on this config file.
⚠️ Got an error? Check the FAQ.
Next steps¶
Once you've got the wheel building successfully, you might want to set up testing or automatic releases to PyPI.