This repository provides an automated system for building Python wheels for multiple platforms using cibuildwheel.
- Automated wheel building for Android and iOS platforms
- Python 3.14 support (officially released October 7th, 2025)
- Android builds for arm64_v8a and x86_64 architectures (as specified)
- Recipe-based configuration - Organize packages with patches in
recipes/directory - Easy package configuration via
packages.txt,packages.yaml, orrecipes/ - Host dependency management - Install system libraries needed by packages (e.g., libffi for cffi)
- Custom source support - Build from custom URLs or Git repositories
- Patch support - Apply patches to source code before building (local files or URLs)
- Dynamic package list reading from configuration file
- Separate wheels for each package and platform combination
- Automatic deployment to GitHub Pages as a PyPI-like index
After wheels are built and deployed, you can install them using pip with the extra index URL:
pip install --extra-index-url https://cfms-dev.github.io/platform-wheels/ <package-name>For example:
pip install --extra-index-url https://cfms-dev.github.io/platform-wheels/ pyyamlOr you can configure it in your pip.conf or requirements.txt:
pip.conf:
[global]
extra-index-url = https://cfms-dev.github.io/platform-wheels/requirements.txt:
--extra-index-url https://cfms-dev.github.io/platform-wheels/
pyyaml
requests
You can configure packages in three ways:
Recommended for packages requiring special configuration. Create a directory under recipes/ for each package:
recipes/
├── cffi/
│ ├── recipe.yaml
│ └── patches/
│ └── mobile.patch
└── cryptography/
└── recipe.yaml
Example recipes/cffi/recipe.yaml:
package:
name: cffi
host_dependencies:
- libffi-dev
patches:
- patches/mobile.patch # Local patch fileBenefits:
- Keeps patches organized with their packages
- Easy to maintain and version control
- Clear separation of concerns
- Patches stored locally in the repository
See recipes/README.md for detailed documentation.
Edit the packages.txt file to specify which Python packages to build. Add one package per line:
numpy==1.24.0
pandas
requests>=2.28.0
You can specify:
- Exact versions:
package==1.0.0 - Minimum versions:
package>=1.0.0 - Version ranges:
package>=1.0.0,<2.0.0 - Just package names (latest version):
package
Lines starting with # are treated as comments and ignored. Empty lines are also ignored.
See packages.txt.example for more examples.
For centralized configuration of multiple packages, create a packages.yaml file:
Note: Packages defined in recipes/ take priority over packages.yaml.
packages:
# Simple package
- name: requests
# Package with version constraint
- name: numpy
version: "==1.24.0"
# Package with alias (creates indexes for both names)
# Useful when the PyPI package name differs from the desired index name
- name: pyyaml
alias: PyYAML
# Package with host dependencies and external patch URL
- name: some-package
host_dependencies:
- libffi-dev
patches:
- https://example.com/patches/fix.patch
# Package with multiple host dependencies
- name: cryptography
host_dependencies:
- libssl-dev
- libffi-dev
- cargo
- rustc
# Package from custom URL
- name: custom-package
source: url
url: https://example.com/package.tar.gz
# Package from Git repository
- name: git-package
source: git
url: https://github.com/user/repo.gitSupported options:
name: Package name (required)version: Version constraint (optional, e.g.,"==1.0.0",">=2.0.0")alias: Alternative package name for the index (optional). When specified, creates indexes for both thenameandaliaswith appropriately renamed wheel filessource: Source type (optional:pypi,url,git; default:pypi)url: Custom URL forurlorgitsources (required if source is notpypi)host_dependencies: System packages to install before building (optional). For cross-compilation, you should provide custom build scripts viacibw_before_allto compile these libraries for the target architecturepip_dependencies: Python packages needed for building (optional)build_dependencies: List of other packages that must be built first (optional). Useful when post-compilation tests require pre-built wheels of other packagespatches: List of patch file URLs to apply to the source code (optional)
Build Dependencies:
The build_dependencies field allows you to specify that a package needs other packages to be built before it starts building. This is particularly useful when:
- Post-compilation tests require pre-built wheels of other packages
- A package needs to import/test against another package during its build process
Example:
packages:
- name: cffi
host_dependencies:
- libffi-dev
- name: cryptography
build_dependencies:
- cffi # Wait for cffi to build first
host_dependencies:
- libssl-devThe build system will automatically:
- Sort packages based on their dependencies (topological sort)
- Build packages in the correct order
- Wait for dependency wheels to be available before starting dependent builds
- Install dependency wheels before building packages that depend on them
Host Dependencies and Cross-Compilation:
When specifying host_dependencies, you need to ensure these libraries are compiled for the target architecture (Android/iOS). The build system provides:
-
Manual approach (current, recommended): Create custom build scripts in
cibw_before_allthat cross-compile the libraries- Example:
recipes/cffi/build_libffi.shshows how to cross-compile libffi
- Example:
-
Automatic environment setup: After your
cibw_before_allscript runs, the system automatically sourcesscripts/setup_cross_compile_env.shwhich:- Searches for cross-compiled libraries in
/tmp/*-install-*directories - Sets environment variables like
LIBFFI_INCLUDE_DIR,LIBFFI_LIB_DIR, etc. - Adds library paths to
CFLAGS,LDFLAGS, andPKG_CONFIG_PATH - Makes it easier for packages to discover cross-compiled dependencies
- Searches for cross-compiled libraries in
Configuration Priority:
recipes/directory (highest priority - recommended for packages with patches)packages.yaml(for centralized configuration)packages.txt(simple list, backward compatibility)
See packages.yaml.example and recipes/README.md for more examples.
The workflow can be triggered in multiple ways:
- Manual trigger: Go to Actions → Build → Run workflow
- Pull request: Wheels are built when PRs are created/updated
- Push to main: Wheels are built on every push to the main branch
- Release: Wheels are built when a new release is published
After a successful build:
- GitHub Actions artifacts: Available for all workflow runs
- GitHub Pages: Deployed automatically on push to main or release (accessible via pip)
- Release assets: Attached to releases when triggered by a release event
Each artifact is named: cibw-wheels-{platform}-{package}
The wheel index is available at: https://cfms-dev.github.io/platform-wheels/
- arm64_v8a (64-bit ARM)
- x86_64 (64-bit Intel/AMD)
- Default architectures for iOS
The build is configured for Python 3.14 (cp314), which was officially released on October 7th, 2025.
The workflow uses these cibuildwheel environment variables:
CIBW_PLATFORM: Specifies the target platform (android/ios)CIBW_ARCHS: Specifies the architecture(s) to build forCIBW_BUILD: Set tocp314-*to build only for Python 3.14
For advanced configuration, you can modify the .github/workflows/wheels.yml file.
To enable wheel deployment, GitHub Pages must be configured in your repository:
- Go to Settings → Pages
- Under Source, select GitHub Actions
- The workflow will automatically deploy the wheel index on push to main or release
The index will be available at: https://<username>.github.io/<repository>/
- The
read_packagesjob reads thepackages.txtfile and parses the package list - The
build_wheelsjob creates a matrix of all packages × platforms - For each combination:
- Installs required host dependencies (system libraries) if specified
- Installs required pip dependencies if specified
- Downloads the package source distribution (from PyPI, custom URL, or Git)
- Extracts it
- Uses cibuildwheel to build the wheel for the target platform
- Uploads the built wheel as an artifact
- The
deploy_indexjob (on push to main or release):- Downloads all built wheel artifacts
- Generates a PyPI-like HTML index structure
- Deploys the index to GitHub Pages
The generated index follows the simple repository API format used by pip:
- Root page (
/) lists all available packages - Each package has its own page (
/<package-name>/) listing all available wheels - Wheels include SHA256 hashes for verification
- Packages must be available on PyPI, accessible via URL, or in a Git repository
- Packages must have proper
setup.pyorpyproject.tomlfor building - Host dependencies (system libraries) can be specified in
packages.yamlif needed