Recipes and continuous integration (CI) to build musllinux (Alpine) wheels for Python packages that don't provide them on PyPI. Built with cibuildwheel and hosted on Cloudsmith.
| Path | Purpose |
|---|---|
build.yaml |
Python versions and architectures every recipe is built for |
recipes/<name>/recipe.yaml |
One package: version, system packages, build environment, test |
scripts/wheels.py |
Works out what is missing from the index and builds it |
.github/workflows/ci.yaml |
Runs the script and uploads the result |
CI compares what should exist (every recipe × Python version × architecture) against the
Cloudsmith index and builds only what is missing. Pull requests build the missing wheels
as a check; pushes to master build and upload them. Nothing else triggers a build, so
every task below is a one-line change.
Edit the python list in build.yaml. Every recipe is built and uploaded for the new version.
Change version in its recipe.yaml. Renovate opens these PRs automatically.
When one recipe limits which versions of another it accepts (borgbackup caps msgpack),
replace version with version_from:
name: msgpack
version_from: borgbackup # recipe directory nameThe newest release that recipe's requirement allows is built, so it moves on its own
when the other package is updated. wheels.py plan --force shows the version chosen.
Create recipes/<name>/recipe.yaml, where <name> matches the PyPI name:
---
name: borgbackup
version: "1.4.5" # quoted; the sdist is downloaded from PyPI
apk: # Alpine packages the build needs, each with its reason
- openssl-dev # libcrypto
environment: # optional: extra environment variables for the build
SOME_FLAG: "1"
test: borg --version # optional: run against each built wheelRun the workflow manually from the Actions tab with force ticked.
The apk list is the complete set of system packages for a build. The musllinux image
already ships gcc, g++, make, pkgconf and linux-headers, so list only the -dev packages
for libraries the package links against (see its setup.py or build documentation).
To check a list, build locally. A package is needed if removing its line makes the build
or the test command fail:
pip install -r scripts/requirements.txt
python scripts/wheels.py build borgbackup --python 3.15 --arch x86_64This needs Docker. Wheels are written to wheelhouse/. Building an architecture other
than the host's also needs QEMU (docker run --privileged --rm tonistiigi/binfmt --install all).
To see what CI would build right now:
python scripts/wheels.py plan