Wheel builder #350
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 == 'scipy/scipy' | |
# | |
# in the get_commit_message job include [wheel build] in your commit | |
# message to trigger the build. All files related to wheel building are located | |
# at tools/wheels/ | |
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: "9 9 * * *" | |
push: | |
branches: | |
- maintenance/** | |
pull_request: | |
branches: | |
- main | |
- maintenance/** | |
workflow_dispatch: | |
permissions: | |
contents: read # to fetch code (actions/checkout) | |
concurrency: | |
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} | |
cancel-in-progress: true | |
jobs: | |
get_commit_message: | |
name: Get commit message | |
runs-on: ubuntu-latest | |
if: github.repository == 'scipy/scipy' | |
outputs: | |
message: ${{ steps.commit_message.outputs.message }} | |
steps: | |
- name: Checkout scipy | |
uses: actions/[email protected] | |
# 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) | |
RUN="0" | |
if [[ "$COMMIT_MSG" == *"[wheel build]"* ]]; then | |
RUN="1" | |
fi | |
echo "message=$RUN" >> $GITHUB_OUTPUT | |
echo github.ref ${{ github.ref }} | |
build_wheels: | |
name: Build wheel for ${{ matrix.python[0] }}-${{ matrix.buildplat[1] }} ${{ matrix.buildplat[2] }} | |
needs: get_commit_message | |
if: >- | |
contains(needs.get_commit_message.outputs.message, '1') || | |
github.event_name == 'schedule' || | |
github.event_name == 'workflow_dispatch' | |
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: | |
# should also be able to do multi-archs on a single entry, e.g. | |
# [windows-2019, win*, "AMD64 x86"]. However, those two require a different compiler setup | |
# so easier to separate out here. | |
- [ubuntu-22.04, manylinux, x86_64] | |
- [ubuntu-22.04, musllinux, x86_64] | |
- [macos-11, macosx, x86_64] | |
- [macos-14, macosx, arm64] | |
- [windows-2019, win, AMD64] | |
python: [["cp39", "3.9"], ["cp310", "3.10"], ["cp311", "3.11"], ["cp312", "3.12"]] | |
# python[0] is used to specify the python versions made by cibuildwheel | |
env: | |
IS_32_BIT: ${{ matrix.buildplat[2] == 'x86' }} | |
# upload to staging if it's a push to a maintenance branch and the last | |
# commit message contains '[wheel build]' | |
IS_PUSH: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/heads/maintenance') && contains(needs.get_commit_message.outputs.message, '1') }} | |
IS_SCHEDULE_DISPATCH: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} | |
steps: | |
- name: Checkout scipy | |
uses: actions/[email protected] | |
with: | |
submodules: true | |
fetch-depth: 0 | |
- uses: actions/setup-python@v5 | |
with: | |
python-version: 3.11 | |
- name: win_amd64 - install rtools | |
run: | | |
# mingw-w64 | |
choco install rtools -y --no-progress --force --version=4.0.0.20220206 | |
echo "c:\rtools40\ucrt64\bin;" >> $env:GITHUB_PATH | |
if: ${{ runner.os == 'Windows' && env.IS_32_BIT == 'false' }} | |
# - name: win32 - configure mingw for 32-bit builds | |
# run: | | |
# # taken from numpy wheels.yml script | |
# # Force 32-bit mingw. v 8.1.0 is the current version used to build | |
# # the 32 bit openBLAS library (not sure if that matters) | |
# choco uninstall mingw | |
# choco install -y mingw --forcex86 --force --version=8.1.0 | |
# echo "C:\ProgramData\chocolatey\lib\mingw\tools\install\mingw32\bin;" >> $env:GITHUB_PATH | |
# echo $(gfortran --version) | |
# echo $(gcc --version) | |
# if: ${{ runner.os == 'Windows' && env.IS_32_BIT == 'true' }} | |
- name: Setup macOS | |
if: matrix.buildplat[0] == 'macos-11' || matrix.buildplat[0] == 'macos-14' | |
run: | | |
if [[ ${{ matrix.buildplat[2] }} == 'arm64' ]]; then | |
# macosx_arm64 | |
# use homebrew gfortran | |
sudo xcode-select -s /Applications/Xcode_15.2.app | |
# for some reason gfortran is not on the path | |
GFORTRAN_LOC=$(brew --prefix gfortran)/bin/gfortran | |
ln -s $GFORTRAN_LOC gfortran | |
export PATH=$PWD:$PATH | |
echo "PATH=$PATH" >> "$GITHUB_ENV" | |
# location of the gfortran's libraries | |
GFORTRAN_LIB=$(dirname `gfortran --print-file-name libgfortran.dylib`) | |
CIBW="MACOSX_DEPLOYMENT_TARGET=12.0\ | |
MACOS_DEPLOYMENT_TARGET=12.0\ | |
LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH\ | |
_PYTHON_HOST_PLATFORM=macosx-12.0-arm64\ | |
PIP_PRE=1\ | |
PIP_NO_BUILD_ISOLATION=false\ | |
PKG_CONFIG_PATH=/opt/arm64-builds/lib/pkgconfig\ | |
PIP_EXTRA_INDEX_URL=https://pypi.anaconda.org/scientific-python-nightly-wheels/simple" | |
echo "CIBW_ENVIRONMENT_MACOS=$CIBW" >> "$GITHUB_ENV" | |
CIBW="sudo xcode-select -s /Applications/Xcode_15.2.app" | |
echo "CIBW_BEFORE_ALL=$CIBW" >> $GITHUB_ENV | |
echo "REPAIR_PATH=/opt/arm64-builds/lib" >> "$GITHUB_ENV" | |
CIBW="DYLD_LIBRARY_PATH=$GFORTRAN_LIB:/opt/arm64-builds/lib delocate-listdeps {wheel} &&\ | |
DYLD_LIBRARY_PATH=$GFORTRAN_LIB:/opt/arm64-builds/lib delocate-wheel --require-archs {delocate_archs} -w {dest_dir} {wheel}" | |
echo "CIBW_REPAIR_WHEEL_COMMAND_MACOS=$CIBW" >> "$GITHUB_ENV" | |
else | |
# macosx_x86_64 with OpenBLAS | |
# setting SDKROOT necessary when using the gfortran compiler | |
# installed in cibw_before_build_macos.sh | |
# MACOS_DEPLOYMENT_TARGET is set because of | |
# https://github.com/mesonbuild/meson-python/pull/309. Once | |
# an update is released, then that environment variable can | |
# be removed. | |
CIBW="MACOSX_DEPLOYMENT_TARGET=10.9\ | |
MACOS_DEPLOYMENT_TARGET=10.9\ | |
SDKROOT=/Applications/Xcode_11.7.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk\ | |
LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH\ | |
_PYTHON_HOST_PLATFORM=macosx-10.9-x86_64\ | |
PIP_PRE=1\ | |
PIP_NO_BUILD_ISOLATION=false\ | |
PIP_EXTRA_INDEX_URL=https://pypi.anaconda.org/scientific-python-nightly-wheels/simple" | |
echo "CIBW_ENVIRONMENT_MACOS=$CIBW" >> "$GITHUB_ENV" | |
CIBW="DYLD_LIBRARY_PATH=/usr/local/lib delocate-listdeps {wheel} &&\ | |
DYLD_LIBRARY_PATH=/usr/local/lib delocate-wheel --require-archs {delocate_archs} -w {dest_dir} {wheel}" | |
echo "CIBW_REPAIR_WHEEL_COMMAND_MACOS=$CIBW" >> "$GITHUB_ENV" | |
fi | |
- name: Build wheels | |
uses: pypa/[email protected] | |
env: | |
CIBW_BUILD: ${{ matrix.python[0] }}-${{ matrix.buildplat[1] }}* | |
CIBW_ARCHS: ${{ matrix.buildplat[2] }} | |
CIBW_ENVIRONMENT_PASS_LINUX: RUNNER_OS | |
CIBW_PRERELEASE_PYTHONS: True | |
# TODO remove the CIBW_BEFORE_BUILD_* lines once there are | |
# numpy2.0 wheels available on PyPI. Also remove/comment out the | |
# PIP_NO_BUILD_ISOLATION and PIP_EXTRA_INDEX_URL from CIBW_ENVIRONMENT | |
# (also for _MACOS and _WINDOWS below) | |
CIBW_BEFORE_BUILD_LINUX: "pip install numpy>=2.0.0.dev0 meson-python cython pythran pybind11 ninja; bash {project}/tools/wheels/cibw_before_build_linux.sh {project}" | |
CIBW_BEFORE_BUILD_WINDOWS: "pip install numpy>=2.0.0.dev0 meson-python cython pythran pybind11 ninja && bash {project}/tools/wheels/cibw_before_build_win.sh {project}" | |
CIBW_BEFORE_BUILD_MACOS: "pip install numpy>=2.0.0.dev0 meson-python cython pythran pybind11 ninja; bash {project}/tools/wheels/cibw_before_build_macos.sh {project}" | |
# Allow pip to find install nightly wheels if necessary | |
# Setting PIP_NO_BUILD_ISOLATION=false makes pip use build-isolation. | |
CIBW_ENVIRONMENT: "PIP_NO_BUILD_ISOLATION=false PIP_PRE=1 PIP_EXTRA_INDEX_URL=https://pypi.anaconda.org/scientific-python-nightly-wheels/simple" | |
CIBW_ENVIRONMENT_WINDOWS: > | |
PKG_CONFIG_PATH=c:/opt/64/lib/pkgconfig | |
PIP_PRE=1 | |
PIP_EXTRA_INDEX_URL=https://pypi.anaconda.org/scientific-python-nightly-wheels/simple | |
PIP_NO_BUILD_ISOLATION=false | |
- uses: actions/upload-artifact@v4 | |
with: | |
path: ./wheelhouse/*.whl | |
name: ${{ matrix.python[0] }}-${{ matrix.buildplat[1] }}-${{ matrix.buildplat[2] }} | |
- uses: conda-incubator/setup-miniconda@v3 | |
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 the wheel | |
auto-update-conda: true | |
python-version: "3.10" | |
- name: Upload wheels | |
if: success() | |
shell: bash -el {0} | |
# see https://github.com/marketplace/actions/setup-miniconda for why | |
# `-el {0}` is required. | |
env: | |
SCIPY_STAGING_UPLOAD_TOKEN: ${{ secrets.SCIPY_STAGING_UPLOAD_TOKEN }} | |
SCIPY_NIGHTLY_UPLOAD_TOKEN: ${{ secrets.SCIPY_NIGHTLY_UPLOAD_TOKEN }} | |
run: | | |
conda install -y anaconda-client | |
source tools/wheels/upload_wheels.sh | |
set_upload_vars | |
# For cron jobs (restricted to main branch) or "Run workflow" trigger | |
# an upload to: | |
# | |
# https://anaconda.org/scientific-python-nightly-wheels/scipy | |
# | |
# Pushes to a maintenance branch that contain '[wheel build]' will | |
# cause wheels to be built and uploaded to: | |
# | |
# https://anaconda.org/multibuild-wheels-staging/scipy | |
# | |
# The tokens were originally generated at anaconda.org | |
upload_wheels |