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
name: Publish Python package
on:
release:
types:
permissions:
contents: read
jobs:
build-wheels:
name: Build wheels (${{ matrix.target.label }})
runs-on: ${{ matrix.target.runner }}
strategy:
fail-fast: false
matrix:
target:
# `triple` is the canonical Rust target triple; `label` is the
# human-readable artifact suffix. Rust uses `aarch64-…`, not
# `arm64-…`, so the label and the triple disagree on macOS arm.
- label: linux-x86_64
os: linux
runner: ubuntu-latest
triple: x86_64-unknown-linux-gnu
# Native ARM Linux hosted runner — free for public repos. If this
# repo ever moves private, swap `ubuntu-24.04-arm` back to
# `ubuntu-latest` and add `--target aarch64-unknown-linux-gnu` to
# let maturin-action cross-compile via QEMU.
- label: linux-aarch64
os: linux
runner: ubuntu-24.04-arm
triple: aarch64-unknown-linux-gnu
- label: macos-arm64
os: macos
runner: macos-latest
triple: aarch64-apple-darwin
- label: macos-x86_64
os: macos
runner: macos-15-intel
triple: x86_64-apple-darwin
- label: windows-x86_64
os: windows
runner: windows-latest
triple: x86_64-pc-windows-msvc
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
# abi3-py38 means the resulting wheel runs on every Python ≥ 3.8;
# the host Python here only drives maturin and is not encoded in
# the wheel filename.
python-version: "3.12"
- name: Build wheels (linux)
if: matrix.target.os == 'linux'
uses: PyO3/maturin-action@v1
env:
# skia-bindings only supports clang on Linux: it unconditionally
# injects clang-only `--target=<triple>` into Skia's GN cflags.
# AlmaLinux 8's default libstdc++ (GCC 8) lacks C++20 <compare>,
# so point clang at gcc-toolset-13's libstdc++ via --gcc-toolchain.
# Skia's GN build does NOT propagate CFLAGS/CXXFLAGS — we have to
# inject the toolchain flag through SKIA_GN_ARGS (`+=` to preserve
# skia-bindings' own extra_cflags like `-O3` and `--target=...`).
CC: clang
CXX: clang++
CFLAGS: --gcc-toolchain=/opt/rh/gcc-toolset-13/root/usr
CXXFLAGS: --gcc-toolchain=/opt/rh/gcc-toolset-13/root/usr
BINDGEN_EXTRA_CLANG_ARGS: --gcc-toolchain=/opt/rh/gcc-toolset-13/root/usr
# `+=` requires the variable to already exist in the GN scope.
# `extra_cflags` is auto-set by skia-bindings (so `+=` extends it);
# `extra_ldflags` is not, so we'd get "Undefined identifier" on `+=`.
# The Skia build only emits static archives (no link step), so we
# don't need extra_ldflags here — the cdylib link is rustc's job.
SKIA_GN_ARGS: 'extra_cflags+=["--gcc-toolchain=/opt/rh/gcc-toolset-13/root/usr"]'
with:
args: --release --out dist --features python
manylinux: 2_28
before-script-linux: dnf install -y fontconfig-devel clang ninja-build gcc-toolset-13
target: ${{ matrix.target.triple }}
# maturin-action filters env vars by prefix (CC/CXX/CFLAGS pass; SKIA_*
# and BINDGEN_* don't). Forward the two we set above explicitly.
docker-options: -e SKIA_GN_ARGS -e BINDGEN_EXTRA_CLANG_ARGS
- name: Build wheels (macos)
if: matrix.target.os == 'macos'
uses: PyO3/maturin-action@v1
with:
args: --release --out dist --features python
target: ${{ matrix.target.triple }}
- name: Build wheels (windows)
if: matrix.target.os == 'windows'
uses: PyO3/maturin-action@v1
with:
args: --release --out dist --features python
target: ${{ matrix.target.triple }}
- uses: actions/upload-artifact@v4
with:
name: wheels-${{ matrix.target.label }}
path: dist
build-sdist:
name: Build source distribution
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build sdist
uses: PyO3/maturin-action@v1
with:
command: sdist
args: --out dist
- uses: actions/upload-artifact@v4
with:
name: sdist
path: dist
publish:
name: Publish to PyPI
runs-on: ubuntu-latest
needs:
environment: pypi
permissions:
id-token: write
steps:
- uses: actions/download-artifact@v4
with:
path: dist
merge-multiple: true
- name: Publish to PyPI
uses: PyO3/maturin-action@v1
with:
command: upload
args: --non-interactive --skip-existing dist/*
env:
MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }}