Wheel builder #327
This file contains 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
# Workflow to build and test wheels. | |
# To work on the wheel building infrastructure on a fork, comment out: | |
# | |
# if: github.repository == 'numpy/numpy' | |
# | |
# in the get_commit_message job. Be sure to include [wheel build] in your commit | |
# message to trigger the build. All files related to wheel building are located | |
# at tools/wheels/ | |
# Alternatively, you can add labels to the pull request in order to trigger wheel | |
# builds. | |
# The labels that trigger builds are: | |
# 36 - Build(for changes to the building process, | |
# 14 - Release(ensure wheels build before release) | |
name: Wheel builder | |
on: | |
schedule: | |
# ┌───────────── minute (0 - 59) | |
# │ ┌───────────── hour (0 - 23) | |
# │ │ ┌───────────── day of the month (1 - 31) | |
# │ │ │ ┌───────────── month (1 - 12 or JAN-DEC) | |
# │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT) | |
# │ │ │ │ │ | |
- cron: "42 2 * * SUN,WED" | |
pull_request: | |
branches: | |
- main | |
- maintenance/** | |
push: | |
tags: | |
- v* | |
workflow_dispatch: | |
concurrency: | |
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} | |
cancel-in-progress: true | |
permissions: | |
contents: read # to fetch code (actions/checkout) | |
jobs: | |
get_commit_message: | |
name: Get commit message | |
runs-on: ubuntu-latest | |
# To enable this job and subsequent jobs on a fork, comment out: | |
if: github.repository == 'numpy/numpy' | |
outputs: | |
message: ${{ steps.commit_message.outputs.message }} | |
steps: | |
- name: Checkout numpy | |
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 | |
# Gets the correct commit message for pull request | |
with: | |
ref: ${{ github.event.pull_request.head.sha }} | |
- name: Get commit message | |
id: commit_message | |
run: | | |
set -xe | |
COMMIT_MSG=$(git log --no-merges -1 --oneline) | |
echo "message=$COMMIT_MSG" >> $GITHUB_OUTPUT | |
echo github.ref ${{ github.ref }} | |
build_wheels: | |
name: Build wheel ${{ matrix.python }}-${{ matrix.buildplat[1] }}-${{ matrix.buildplat[2] }} | |
needs: get_commit_message | |
if: >- | |
contains(needs.get_commit_message.outputs.message, '[wheel build]') || | |
github.event_name == 'schedule' || | |
github.event_name == 'workflow_dispatch' || | |
(github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') && ( ! endsWith(github.ref, 'dev0'))) | |
runs-on: ${{ matrix.buildplat[0] }} | |
strategy: | |
# Ensure that a wheel builder finishes even if another fails | |
fail-fast: false | |
matrix: | |
# Github Actions doesn't support pairing matrix values together, let's improvise | |
# https://github.com/github/feedback/discussions/7835#discussioncomment-1769026 | |
buildplat: | |
- [ubuntu-22.04, manylinux_x86_64, ""] | |
- [ubuntu-22.04, musllinux_x86_64, ""] | |
- [macos-13, macosx_x86_64, openblas] | |
# targeting macos >= 14. Could probably build on macos-14, but it would be a cross-compile | |
- [macos-13, macosx_x86_64, accelerate] | |
- [macos-14, macosx_arm64, accelerate] # always use accelerate | |
- [windows-2019, win_amd64, ""] | |
- [windows-2019, win32, ""] | |
python: ["cp310", "cp311", "cp312", "pp310", "cp313", "cp313t"] | |
exclude: | |
# Don't build PyPy 32-bit windows | |
- buildplat: [windows-2019, win32, ""] | |
python: "pp310" | |
- buildplat: [ ubuntu-22.04, musllinux_x86_64, "" ] | |
python: "pp310" | |
- buildplat: [ macos-14, macosx_arm64, accelerate ] | |
python: "pp310" | |
- buildplat: [ macos13, macosx_x86_64, openblas ] | |
python: "cp313t" | |
env: | |
IS_32_BIT: ${{ matrix.buildplat[1] == 'win32' }} | |
IS_PUSH: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }} | |
IS_SCHEDULE_DISPATCH: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} | |
steps: | |
- name: Checkout numpy | |
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 | |
with: | |
submodules: true | |
- name: Setup MSVC (32-bit) | |
if: ${{ matrix.buildplat[1] == 'win32' }} | |
uses: bus1/cabuild/action/msdevshell@e22aba57d6e74891d059d66501b6b5aed8123c4d # v1 | |
with: | |
architecture: 'x86' | |
- name: pkg-config-for-win | |
run: | | |
choco install -y --no-progress --stoponfirstfailure --checksum 6004DF17818F5A6DBF19CB335CC92702 pkgconfiglite | |
$CIBW = "${{ github.workspace }}/.openblas" | |
# pkgconfig needs a complete path, and not just "./openblas since the | |
# build is run in a tmp dir (?) | |
# It seems somewhere in the env passing, `\` is not | |
# passed through, so convert it to '/' | |
$CIBW = $CIBW.replace("\","/") | |
echo "CIBW_ENVIRONMENT_WINDOWS=PKG_CONFIG_PATH=$CIBW" >> $env:GITHUB_ENV | |
if: runner.os == 'windows' | |
# Used to push the built wheels | |
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 | |
with: | |
python-version: "3.x" | |
- name: Setup macOS | |
if: matrix.buildplat[0] == 'macos-13' || matrix.buildplat[0] == 'macos-14' | |
run: | | |
# Needed due to https://github.com/actions/runner-images/issues/3371 | |
# Supported versions: https://github.com/actions/runner-images/blob/main/images/macos/macos-14-arm64-Readme.md | |
echo "FC=gfortran-13" >> "$GITHUB_ENV" | |
echo "F77=gfortran-13" >> "$GITHUB_ENV" | |
echo "F90=gfortran-13" >> "$GITHUB_ENV" | |
if [[ ${{ matrix.buildplat[2] }} == 'accelerate' ]]; then | |
# macosx_arm64 and macosx_x86_64 with accelerate | |
# only target Sonoma onwards | |
CIBW="MACOSX_DEPLOYMENT_TARGET=14.0 INSTALL_OPENBLAS=false RUNNER_OS=macOS" | |
echo "CIBW_ENVIRONMENT_MACOS=$CIBW" >> "$GITHUB_ENV" | |
# the macos-13 image that's used for building the x86_64 wheel can't test | |
# a wheel with deployment target >= 14 without further work | |
echo "CIBW_TEST_SKIP=*-macosx_x86_64" >> "$GITHUB_ENV" | |
else | |
# macosx_x86_64 with OpenBLAS | |
# if INSTALL_OPENBLAS isn't specified then scipy-openblas is automatically installed | |
CIBW="RUNNER_OS=macOS" | |
PKG_CONFIG_PATH="$PWD/.openblas" | |
DYLD="$DYLD_LIBRARY_PATH:/$PWD/.openblas/lib" | |
echo "CIBW_ENVIRONMENT_MACOS=$CIBW PKG_CONFIG_PATH=$PKG_CONFIG_PATH DYLD_LIBRARY_PATH=$DYLD" >> "$GITHUB_ENV" | |
fi | |
- name: Set up free-threaded build | |
if: matrix.python == 'cp313t' | |
shell: bash -el {0} | |
run: | | |
echo "CIBW_BUILD_FRONTEND=pip; args: --no-build-isolation" >> "$GITHUB_ENV" | |
- name: Build wheels | |
uses: pypa/cibuildwheel@7940a4c0e76eb2030e473a5f864f291f63ee879b # v2.21.3 | |
env: | |
CIBW_PRERELEASE_PYTHONS: True | |
CIBW_FREE_THREADED_SUPPORT: True | |
CIBW_BUILD: ${{ matrix.python }}-${{ matrix.buildplat[1] }} | |
- uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 | |
with: | |
name: ${{ matrix.python }}-${{ matrix.buildplat[1] }}-${{ matrix.buildplat[2] }} | |
path: ./wheelhouse/*.whl | |
- uses: mamba-org/setup-micromamba@617811f69075e3fd3ae68ca64220ad065877f246 | |
with: | |
# for installation of anaconda-client, required for upload to | |
# anaconda.org | |
# Note that this step is *after* specific pythons have been used to | |
# build and test the wheel | |
# for installation of anaconda-client, for upload to anaconda.org | |
# environment will be activated after creation, and in future bash steps | |
init-shell: bash | |
environment-name: upload-env | |
create-args: >- | |
anaconda-client | |
- name: Upload wheels | |
if: success() | |
shell: bash -el {0} | |
# see https://github.com/marketplace/actions/setup-miniconda for why | |
# `-el {0}` is required. | |
env: | |
NUMPY_STAGING_UPLOAD_TOKEN: ${{ secrets.NUMPY_STAGING_UPLOAD_TOKEN }} | |
NUMPY_NIGHTLY_UPLOAD_TOKEN: ${{ secrets.NUMPY_NIGHTLY_UPLOAD_TOKEN }} | |
run: | | |
source tools/wheels/upload_wheels.sh | |
set_upload_vars | |
# trigger an upload to | |
# https://anaconda.org/scientific-python-nightly-wheels/numpy | |
# for cron jobs or "Run workflow" (restricted to main branch). | |
# Tags will upload to | |
# https://anaconda.org/multibuild-wheels-staging/numpy | |
# The tokens were originally generated at anaconda.org | |
upload_wheels | |
build_sdist: | |
name: Build sdist | |
needs: get_commit_message | |
if: >- | |
contains(needs.get_commit_message.outputs.message, '[wheel build]') || | |
github.event_name == 'schedule' || | |
github.event_name == 'workflow_dispatch' || | |
(github.event_name == 'pull_request' && | |
(contains(github.event.pull_request.labels.*.name, '36 - Build') || | |
contains(github.event.pull_request.labels.*.name, '14 - Release'))) || | |
(github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') && ( ! endsWith(github.ref, 'dev0'))) | |
runs-on: ubuntu-latest | |
env: | |
IS_PUSH: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }} | |
# commented out so the sdist doesn't upload to nightly | |
# IS_SCHEDULE_DISPATCH: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} | |
steps: | |
- name: Checkout numpy | |
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 | |
with: | |
submodules: true | |
# Used to push the built wheels | |
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 | |
with: | |
# Build sdist on lowest supported Python | |
python-version: "3.10" | |
- name: Build sdist | |
run: | | |
python -m pip install -U pip build | |
python -m build --sdist -Csetup-args=-Dallow-noblas=true | |
- name: Test the sdist | |
run: | | |
# TODO: Don't run test suite, and instead build wheels from sdist | |
# Depends on pypa/cibuildwheel#1020 | |
python -m pip install dist/*.gz -Csetup-args=-Dallow-noblas=true | |
pip install -r requirements/test_requirements.txt | |
cd .. # Can't import numpy within numpy src directory | |
python -c "import numpy, sys; print(numpy.__version__); sys.exit(numpy.test() is False)" | |
- name: Check README rendering for PyPI | |
run: | | |
python -mpip install twine | |
twine check dist/* | |
- uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 | |
with: | |
name: sdist | |
path: ./dist/* | |
- uses: conda-incubator/setup-miniconda@a4260408e20b96e80095f42ff7f1a15b27dd94ca # v3.0.4 | |
with: | |
# for installation of anaconda-client, required for upload to | |
# anaconda.org | |
# default (and activated) environment name is test | |
# Note that this step is *after* specific pythons have been used to | |
# build and test | |
auto-update-conda: true | |
python-version: "3.10" | |
- name: Upload sdist | |
if: success() | |
shell: bash -el {0} | |
env: | |
NUMPY_STAGING_UPLOAD_TOKEN: ${{ secrets.NUMPY_STAGING_UPLOAD_TOKEN }} | |
# commented out so the sdist doesn't upload to nightly | |
# NUMPY_NIGHTLY_UPLOAD_TOKEN: ${{ secrets.NUMPY_NIGHTLY_UPLOAD_TOKEN }} | |
run: | | |
conda install -y anaconda-client | |
source tools/wheels/upload_wheels.sh | |
set_upload_vars | |
# trigger an upload to | |
# https://anaconda.org/scientific-python-nightly-wheels/numpy | |
# for cron jobs or "Run workflow" (restricted to main branch). | |
# Tags will upload to | |
# https://anaconda.org/multibuild-wheels-staging/numpy | |
# The tokens were originally generated at anaconda.org | |
upload_wheels |