Skip to content

Build wheels

Build wheels #32

Workflow file for this run

name: Build wheels
on:
schedule:
- cron: "0 0 * * 0" # weekly, Sunday midnight UTC
workflow_dispatch:
inputs:
llvm_ref:
description: "LLVM git ref (tag, branch, or SHA)"
required: true
jobs:
# ---------------------------------------------------------------------------
# Job 1: Determine whether we need to build at all
# ---------------------------------------------------------------------------
check:
name: Check for existing wheels
runs-on: ubuntu-latest
outputs:
should_build: ${{ steps.check.outputs.should_build }}
llvm_ref: ${{ steps.check.outputs.llvm_ref }}
steps:
- uses: actions/checkout@v4
- name: Resolve ref and check PyPI
id: check
shell: python
env:
HALIDE_LLVM_REF: ${{ inputs.llvm_ref || 'main' }}
GITHUB_TOKEN: ${{ github.token }}
PYTHONPATH: .
run: |
import os, urllib.request
from _version_provider import version_from_tag, get_commit_info
ref = os.environ["HALIDE_LLVM_REF"]
# Build the search pattern for this ref
tag_version = version_from_tag(ref)
if tag_version:
pattern = f"halide_llvm-{tag_version}-"
resolved_ref = ref
print(f"Release tag detected, searching for: {pattern}")
else:
sha, _ = get_commit_info(ref)
pattern = f"g{sha[:8]}"
resolved_ref = sha
print(f"Dev ref detected, resolved to: {resolved_ref}")
print(f"Searching for: {pattern}")
# Check the simple index for existing wheels
try:
req = urllib.request.Request("https://pypi.halide-lang.org/simple/halide-llvm/")
index = urllib.request.urlopen(req, timeout=30).read().decode()
except Exception:
index = ""
should_build = "false" if pattern in index else "true"
print(f"should_build={should_build}")
with open(os.environ["GITHUB_OUTPUT"], "a") as f:
f.write(f"should_build={should_build}\n")
f.write(f"llvm_ref={resolved_ref}\n")
# ---------------------------------------------------------------------------
# Job 2: Build wheels for all platforms
# ---------------------------------------------------------------------------
build:
name: Build / ${{ matrix.platform }}
needs: check
if: needs.check.outputs.should_build == 'true'
runs-on: ${{ matrix.runner }}
container: ${{ matrix.container }}
strategy:
fail-fast: false
matrix:
include:
- platform: x86-64-linux
runner: ubuntu-latest
container: quay.io/pypa/manylinux_2_28_x86_64
toolchain: x86-64-linux.cmake
manylinux_plat: manylinux_2_28_x86_64
# i686: Node.js 20 has no i686 binaries, so actions/checkout
# cannot run inside the container. We run on the host and use
# docker for the build/repair steps instead.
- platform: x86-32-linux
runner: ubuntu-latest
toolchain: x86-32-linux.cmake
docker_image: quay.io/pypa/manylinux_2_28_i686
manylinux_plat: manylinux_2_28_i686
pin_gcc12: true
- platform: arm-64-linux
runner: ubuntu-24.04-arm
container: quay.io/pypa/manylinux_2_28_aarch64
toolchain: arm-64-linux.cmake
manylinux_plat: manylinux_2_28_aarch64
# armv7l: same Node.js issue as i686 -- use docker run.
- platform: arm-32-linux
runner: ubuntu-24.04-arm
toolchain: arm-32-linux.cmake
docker_image: quay.io/pypa/manylinux_2_31_armv7l
manylinux_plat: manylinux_2_31_armv7l
- platform: x86-64-macos
runner: macos-15-intel
toolchain: x86-64-macos.cmake
- platform: arm-64-macos
runner: macos-15
toolchain: arm-64-macos.cmake
- platform: x86-64-windows
runner: windows-latest
toolchain: x86-64-windows.cmake
msvc_arch: amd64
- platform: x86-32-windows
runner: windows-latest
toolchain: x86-32-windows.cmake
msvc_arch: amd64_x86
wheel_plat: win32
env:
HALIDE_LLVM_REF: ${{ needs.check.outputs.llvm_ref }}
GITHUB_TOKEN: ${{ github.token }}
CMAKE_GENERATOR: Ninja
MACOSX_DEPLOYMENT_TARGET: "11"
steps:
# ---- Checkout ----
- uses: actions/checkout@v4
# ---- Toolchain (manylinux containers) ----
# Pin GCC 12 to avoid GCC 14 libstdc++ symbols (e.g. __cxa_call_terminate)
# leaking into static libraries. auditwheel doesn't catch these, so
# consumers with older libstdc++ would get linker errors.
- name: Set up GCC 12 and Python (manylinux)
if: matrix.container
run: |
yum install -y gcc-toolset-12-gcc-c++
echo "/opt/rh/gcc-toolset-12/root/usr/bin" >> "$GITHUB_PATH"
echo "/opt/python/cp312-cp312/bin" >> "$GITHUB_PATH"
# ---- Python (non-container, non-docker) ----
- name: Set up Python
if: ${{ !matrix.container && !matrix.docker_image }}
uses: actions/setup-python@v5
with:
python-version: "3.12"
# ---- MSVC (Windows) ----
- name: Set up MSVC
if: matrix.msvc_arch
uses: ilammy/msvc-dev-cmd@v1
with:
arch: ${{ matrix.msvc_arch }}
# ---- Build wheel ----
- name: Build wheel
if: ${{ !matrix.docker_image }}
run: >
pip wheel . -w dist/ -v
--config-settings=cmake.define.CMAKE_TOOLCHAIN_FILE=toolchains/${{ matrix.toolchain }}
# ---- Retag wheel (scikit-build-core bug: x86 cross-compile gets win_amd64) ----
- name: Retag wheel
if: matrix.wheel_plat
shell: bash
run: |
pip install wheel
wheel tags --platform-tag ${{ matrix.wheel_plat }} --remove dist/*.whl
# ---- Build wheel (docker, for i686 and armv7l) ----
- name: Build wheel (docker)
if: matrix.docker_image
run: |
docker run --rm \
-v "${{ github.workspace }}:/project" \
-w /project \
-e HALIDE_LLVM_REF \
-e GITHUB_TOKEN \
-e PIN_GCC12=${{ matrix.pin_gcc12 && 'true' || 'false' }} \
${{ matrix.docker_image }} \
bash -c '
set -euo pipefail
if [ "$PIN_GCC12" = "true" ]; then
yum install -y gcc-toolset-12-gcc-c++
export PATH="/opt/rh/gcc-toolset-12/root/usr/bin:$PATH"
fi
export PATH="/opt/python/cp312-cp312/bin:$PATH"
pip wheel . -w dist/ -v \
--config-settings=cmake.define.CMAKE_TOOLCHAIN_FILE=toolchains/${{ matrix.toolchain }}
'
# ---- Repair wheel (auditwheel, in container) ----
- name: Repair wheel (auditwheel)
if: ${{ matrix.manylinux_plat && !matrix.docker_image }}
run: |
pip install auditwheel
auditwheel repair --plat ${{ matrix.manylinux_plat }} -w dist/ dist/*.whl
# Remove the original unrepaired wheel
rm -f dist/*-linux_*.whl
# ---- Repair wheel (auditwheel via docker, for i686) ----
- name: Repair wheel (auditwheel/docker)
if: ${{ matrix.manylinux_plat && matrix.docker_image }}
run: |
docker run --rm \
-v "${{ github.workspace }}:/project" \
-w /project \
${{ matrix.docker_image }} \
bash -c '
set -euo pipefail
export PATH="/opt/python/cp312-cp312/bin:$PATH"
pip install auditwheel
auditwheel repair --plat ${{ matrix.manylinux_plat }} -w dist/ dist/*.whl
rm -f dist/*-linux_*.whl
'
# ---- Repair wheel (macOS) ----
# Disabled: delocate's -e flag does not apply to the deployment target
# version check, so excluded iossim/ios dylibs still cause a false
# failure. Our CMAKE_INSTALL_RPATH settings handle runtime resolution.
# See: https://github.com/matthew-brett/delocate/issues/273
#- name: Repair wheel (delocate)
# if: runner.os == 'macOS'
# run: |
# pip install delocate
# delocate-wheel -e lib/darwin -w dist/ dist/*.whl
# ---- Upload artifact ----
- name: Upload wheel
uses: actions/upload-artifact@v4
with:
name: wheel-${{ matrix.platform }}
path: dist/*.whl
# ---------------------------------------------------------------------------
# Job 3: Upload all wheels to private PyPI
# ---------------------------------------------------------------------------
upload:
name: Upload to PyPI
needs: build
runs-on: ubuntu-latest
steps:
- name: Download all wheel artifacts
uses: actions/download-artifact@v4
with:
pattern: wheel-*
path: dist/
merge-multiple: true
- name: Upload to PyPI
env:
TWINE_USERNAME: upload
TWINE_PASSWORD: ${{ secrets.PYPI_UPLOAD_PASSWORD }}
TWINE_REPOSITORY_URL: https://pypi.halide-lang.org/
run: |
pip install "twine>=6" "packaging>=24.2"
twine upload dist/*.whl