Repository navigation
271 lines (227 loc) · 11.8 KB
/
Copy pathwheels.yml
File metadata and controls
271 lines (227 loc) · 11.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
name: Python wheel package build and publish
on:
release:
types: [published]
# Enable Run Workflow button in GitHub UI
workflow_dispatch:
inputs:
# Manual dispatch allows optional upload of wheels to PyPI
upload_dest:
type: choice
description: Upload wheels to
options:
- No Upload
- PyPI
- Test PyPI
push:
branches: [ main ]
pull_request:
# Cancel superseded runs of a PR only. Keying on `github.ref` would also let a
# push to main cancel a running release or manual (workflow_dispatch) upload.
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true
permissions:
contents: read
jobs:
build_sdist:
name: Build SDist
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false
- name: Build SDist
run: pipx run build --sdist
- name: Check metadata
run: pipx run twine check dist/*
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: sdist
path: dist/*.tar.gz
build_wheels:
name: Wheels - ${{ matrix.cibw_archs }} ${{ matrix.arch_note}} - ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: windows-latest
cibw_archs: "auto64"
# No PyPy: NumPy has no wheels for PyPy 8.0, and a NumPy built from source here
# uses MinGW, which warns on import that it is experimental ("CRASHES ARE TO BE
# EXPECTED"), failing the tests.
cibw_skip: "pp*"
# Linux x86_64 manylinux
- os: ubuntu-latest
cibw_archs: "x86_64"
# manylinux_2_28 uses dnf (not yum). libffi-devel needed for Python 3.12+ cffi.
cibw_before_build_linux: "dnf install -y libffi-devel || yum install -y libffi-devel || true"
# skip musllinux
cibw_skip: "*musl*"
# Linux x86_64 musllinux
# Separate runner for a Musl build of graphblas. The glibc build is not guaranteed to be compatible.
- os: ubuntu-latest
cibw_archs: "x86_64"
arch_note: "musl"
# skip manylinux (built elsewhere)
cibw_skip: "*many*"
# Linux aarch64 — native ARM runner (no QEMU emulation needed)
- os: ubuntu-24.04-arm
cibw_archs: "auto"
# numpy wheels not available for aarch64 musllinux
cibw_skip: "*musl*"
# macOS x86_64 — macos-15-intel is the last Intel macOS runner.
# libomp from Homebrew determines the minimum supported macOS version.
- os: macos-15-intel
cibw_archs: "x86_64"
# macOS Apple Silicon
# Keep runner version as old as possible: libomp determines minimum macOS version.
# macos-14 is retired on 2026-11-02 (and fails jobs during brownouts before then).
- os: macos-15
cibw_archs: "arm64"
# WebAssembly for Pyodide (PEP 783 `pyemscripten_*` wheels). GraphBLAS is built in
# before-build (see CIBW_*_PYODIDE below).
- os: ubuntu-latest
cibw_platform: "pyodide"
cibw_archs: "wasm32"
arch_note: "pyodide"
# Pyodide for 3.15 is an alpha, and building for it names the cffi module with
# the build machine's abi3 suffix (e.g., `_graphblas.abi3-x86_64-linux-gnu.so`),
# which Pyodide can't import.
cibw_skip: "cp315-*"
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false
- name: Setup for testing
if: github.event_name == 'push' || github.event_name == 'pull_request'
# Ask suitesparse.sh to compile in the fastest way possible and provide a GB version to build
run: |
echo "SUITESPARSE_FASTEST_BUILD=1" >> "$GITHUB_ENV"
shell: bash
- name: Setup GraphBLAS version from GB_VERSION.txt
# Use GraphBLAS version specified in GB_VERSION.txt unless specified in a git tag (next workflow step).
# Git tag method required for uploads to PyPI.
if: github.event_name != 'release' && github.event.inputs.upload_dest != 'PyPI'
run: echo "GB_VERSION_REF=refs/tags/$(cat GB_VERSION.txt).0" >> "$GITHUB_ENV"
shell: bash
- name: Setup GraphBLAS version from git tag
if: ${{ startsWith(github.ref, 'refs/tags/') }}
# If this is a tagged ref, like a release, then use the tag for the graphblas version
run: echo "GB_VERSION_REF=$GITHUB_REF" >> "$GITHUB_ENV"
shell: bash
- name: Install tools (macOS)
if: contains(matrix.os, 'macos')
# Install coreutils which includes `nproc` used by `make -j` in suitesparse.sh
#
# Explicitly install libomp to be clear about the dependency.
#
# libomp determines the minimum macOS version that we can build for
run: |
brew fetch --retry coreutils && brew install coreutils
brew fetch --retry libomp && brew reinstall libomp
echo "MACOSX_DEPLOYMENT_TARGET=$(otool -l "$(brew --prefix libomp)/lib/libomp.dylib" | grep minos | awk '{print $2}')" >> "$GITHUB_ENV"
- uses: pypa/cibuildwheel@b3395e271a35f73dad77f21802abe9b986dfe299 # v4.3.1
with:
output-dir: wheelhouse
env:
# very verbose
CIBW_BUILD_VERBOSITY: 3
# PyPy is not built by default (since cibuildwheel v3); enable explicitly.
# cibuildwheel v4.3 builds PyPy 8.0, whose ABI tag (`pypy311_pp80`) PyPy 7.3 can't
# install, and NumPy has no wheels for it, so building and testing compile NumPy.
# Free-threaded wheels (cp314t, cp315t) are built and tested by default.
# cibuildwheel v4 dropped cp313t (and its "cpython-freethreading"
# enable option) entirely.
CIBW_ENABLE: "pypy"
CIBW_PLATFORM: ${{ matrix.cibw_platform || 'auto' }}
# Build SuiteSparse
CIBW_BEFORE_ALL: bash suitesparse.sh ${{ env.GB_VERSION_REF }}
CIBW_BEFORE_BUILD_LINUX: ${{ matrix.cibw_before_build_linux }}
# Pyodide: cibuildwheel sets up Emscripten for each Python version (each Pyodide
# version has its own) after before-all, so build GraphBLAS in before-build instead.
# SUITESPARSE_EMSCRIPTEN=1 asks suitesparse.sh for a static library to link into the
# extension module. The empty before-all overrides the one above.
# EMCC_CFLAGS=-O2: Pyodide links with -Oz, and binaryen's wasm-opt -Oz had not
# finished with GraphBLAS after 30 CPU-minutes; -O2 takes about a minute. emcc
# appends EMCC_CFLAGS to every command, so its -O2 is the one that counts (also for
# compiling GraphBLAS, which is then smaller and no slower).
CIBW_BEFORE_ALL_PYODIDE: ""
CIBW_BEFORE_BUILD_PYODIDE: bash suitesparse.sh ${{ env.GB_VERSION_REF }}
CIBW_ENVIRONMENT_PYODIDE: SUITESPARSE_EMSCRIPTEN=1 GRAPHBLAS_PREFIX=/tmp/graphblas-wasm GraphBLAS_ROOT=/tmp/graphblas-wasm EMCC_CFLAGS=-O2
CIBW_ENVIRONMENT_PASS_LINUX: SUITESPARSE_FASTEST_BUILD
# CMAKE_GNUtoMS=ON asks suitesparse.sh to build libraries in MSVC style on Windows.
CIBW_ENVIRONMENT_WINDOWS: CMAKE_GNUtoMS=ON GRAPHBLAS_PREFIX="C:/GraphBLAS"
# macOS libomp requires special configs. BREW_LIBOMP=1 asks suitesparse.sh to include them.
# SUITESPARSE_MACOS_ARCH asks to build a particular architecture. Either x86 or arm64.
CIBW_ENVIRONMENT_MACOS: BREW_LIBOMP="1" SUITESPARSE_MACOS_ARCH=${{ matrix.cibw_archs }}
# Uncomment to only build CPython wheels
# CIBW_BUILD: "cp*"
# Architectures to build specified in matrix
CIBW_ARCHS: ${{ matrix.cibw_archs }}
# Skip PyPy 3.12 everywhere: no NumPy release builds on it yet (NumPy's bundled
# pythoncapi_compat.h redefines functions that PyPy 3.12 v8.0's headers declare).
CIBW_SKIP: "pp312-* ${{ matrix.cibw_skip }}"
# Use delvewheel on Windows.
# This copies graphblas.dll into the wheel. "repair" in cibuildwheel parlance includes copying any shared
# libraries from the build host into the wheel to make the wheel self-contained.
# cibuildwheel v4 installs delvewheel and uses it by default; this overrides its command so it can
# find graphblas.dll and to apply a workaround: --no-mangle instead of stripping graphblas.dll
# see https://github.com/adang1345/delvewheel/issues/33
CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: "delvewheel repair --add-path \"C:\\GraphBLAS\\bin\" --no-mangle \"libgomp-1.dll;libgcc_s_seh-1.dll\" -w {dest_dir} {wheel}"
# make cibuildwheel install test dependencies from pyproject.toml
CIBW_TEST_EXTRAS: "test"
# run tests. They run from a temporary directory, so pyproject.toml's pytest
# config doesn't apply; -W error restores its `filterwarnings = ["error"]`.
# `python -m pytest`, because the `pytest` script doesn't work in a Pyodide venv.
CIBW_TEST_COMMAND: "python -m pytest --pyargs suitesparse_graphblas -s -k test_print_jit_config && python -m pytest -v -W error --pyargs suitesparse_graphblas"
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: wheels-${{ matrix.os }}-${{ matrix.cibw_archs }}${{ matrix.arch_note}}
path: wheelhouse/*.whl
if-no-files-found: error
# Uploads use PyPI Trusted Publishing (no API token). Each index trusts this workflow
# (wheels.yml) only when it runs in the GitHub environment registered with it.
upload_pypi:
name: Upload to PyPI
needs: [build_wheels, build_sdist]
runs-on: ubuntu-latest
# only upload releases (or an explicit manual request) to PyPI
if: github.repository == 'GraphBLAS/python-suitesparse-graphblas' && ((github.event_name == 'release' && github.event.action == 'published') || (github.event_name == 'workflow_dispatch' && github.event.inputs.upload_dest == 'PyPI'))
environment:
name: pypi
url: https://pypi.org/p/suitesparse-graphblas
permissions:
id-token: write # for Trusted Publishing (and its attestations)
steps:
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
path: dist
merge-multiple: true
- uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
with:
# PyPI does not allow replacing a file. Without this flag the entire action fails if even a single duplicate exists.
skip-existing: true
upload_test_pypi:
name: Upload to Test PyPI
needs: [build_wheels, build_sdist]
runs-on: ubuntu-latest
if: github.repository == 'GraphBLAS/python-suitesparse-graphblas' && github.event_name == 'workflow_dispatch' && github.event.inputs.upload_dest == 'Test PyPI'
environment:
name: test-pypi
url: https://test.pypi.org/p/suitesparse-graphblas
permissions:
id-token: write # for Trusted Publishing (and its attestations)
steps:
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
path: dist
merge-multiple: true
- uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
with:
repository-url: https://test.pypi.org/legacy/
# PyPI does not allow replacing a file. Without this flag the entire action fails if even a single duplicate exists.
skip-existing: true