Build wheels #32
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |