Skip to content

Commit 26e0513

Browse files
committed
matplotlib: add build, test workflows for riscv64
Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
1 parent 1887a91 commit 26e0513

2 files changed

Lines changed: 365 additions & 0 deletions

File tree

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
---
2+
name: Build matplotlib wheels (riscv64)
3+
4+
on:
5+
workflow_dispatch:
6+
push:
7+
branches:
8+
- main
9+
pull_request:
10+
11+
permissions: {}
12+
13+
jobs:
14+
build_sdist:
15+
name: Build sdist
16+
runs-on: ubuntu-24.04-riscv
17+
permissions:
18+
contents: read
19+
outputs:
20+
SDIST_NAME: ${{ steps.sdist.outputs.SDIST_NAME }}
21+
22+
steps:
23+
- name: Checkout python-wheels
24+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
25+
with:
26+
persist-credentials: false
27+
28+
- name: Checkout matplotlib
29+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
30+
with:
31+
repository: matplotlib/matplotlib
32+
path: upstream
33+
fetch-depth: 0
34+
persist-credentials: false
35+
36+
- uses: actions/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
37+
name: Install Python
38+
with:
39+
python-version: '3.12'
40+
activate-environment: true
41+
enable-cache: false
42+
43+
# Something changed somewhere that prevents the downloaded-at-build-time
44+
# licenses from being included in built wheels, so pre-download them so
45+
# that they exist before the build and are included.
46+
- name: Pre-download bundled licenses
47+
working-directory: upstream
48+
run: >
49+
curl -Lo LICENSE/LICENSE_QHULL
50+
https://github.com/qhull/qhull/raw/2020.2/COPYING.txt
51+
52+
- name: Install dependencies
53+
run: python -m pip install build twine
54+
55+
- name: Build sdist
56+
id: sdist
57+
working-directory: upstream
58+
run: |
59+
python -m build --sdist
60+
python ci/export_sdist_name.py
61+
62+
- name: Check README rendering for PyPI
63+
working-directory: upstream
64+
run: twine check dist/*
65+
66+
- name: Upload sdist result
67+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
68+
with:
69+
name: cibw-sdist
70+
path: upstream/dist/*.tar.gz
71+
if-no-files-found: error
72+
73+
build_wheels:
74+
needs: build_sdist
75+
name: Build wheels on ubuntu-24.04-riscv for riscv64
76+
permissions:
77+
contents: read
78+
runs-on: ubuntu-24.04-riscv
79+
80+
steps:
81+
- name: Checkout python-wheels
82+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
83+
with:
84+
persist-credentials: false
85+
86+
- name: Download sdist
87+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
88+
with:
89+
name: cibw-sdist
90+
path: dist/
91+
92+
- name: Build wheels for CPython 3.14
93+
uses: pypa/cibuildwheel@8d2b08b68458a16aeb24b64e68a09ab1c8e82084 # v3.4.1
94+
with:
95+
package-dir: dist/${{ needs.build_sdist.outputs.SDIST_NAME }}
96+
env:
97+
CIBW_BUILD: "cp314-* cp314t-*"
98+
CIBW_ARCHS: "riscv64"
99+
CIBW_ENVIRONMENT: 'PIP_PREFER_BINARY=1 PIP_EXTRA_INDEX_URL=https://gitlab.com/api/v4/projects/riseproject%2Fpython%2Fwheel_builder/packages/pypi/simple'
100+
101+
- name: Build wheels for CPython 3.13
102+
uses: pypa/cibuildwheel@8d2b08b68458a16aeb24b64e68a09ab1c8e82084 # v3.4.1
103+
with:
104+
package-dir: dist/${{ needs.build_sdist.outputs.SDIST_NAME }}
105+
env:
106+
CIBW_BUILD: "cp313-*"
107+
CIBW_ARCHS: "riscv64"
108+
CIBW_ENVIRONMENT: 'PIP_PREFER_BINARY=1 PIP_EXTRA_INDEX_URL=https://gitlab.com/api/v4/projects/riseproject%2Fpython%2Fwheel_builder/packages/pypi/simple'
109+
110+
- name: Build wheels for CPython 3.12
111+
uses: pypa/cibuildwheel@8d2b08b68458a16aeb24b64e68a09ab1c8e82084 # v3.4.1
112+
with:
113+
package-dir: dist/${{ needs.build_sdist.outputs.SDIST_NAME }}
114+
env:
115+
CIBW_BUILD: "cp312-*"
116+
CIBW_ARCHS: "riscv64"
117+
CIBW_ENVIRONMENT: 'PIP_PREFER_BINARY=1 PIP_EXTRA_INDEX_URL=https://gitlab.com/api/v4/projects/riseproject%2Fpython%2Fwheel_builder/packages/pypi/simple'
118+
119+
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
120+
with:
121+
name: cibw-wheels-${{ runner.os }}-riscv64
122+
path: ./wheelhouse/*.whl
123+
if-no-files-found: error
Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
---
2+
name: Test matplotlib (riscv64)
3+
concurrency:
4+
group: ${{ github.workflow }}-${{ github.event.number }}-${{ github.event.ref }}
5+
cancel-in-progress: true
6+
7+
on:
8+
workflow_dispatch:
9+
push:
10+
branches:
11+
- main
12+
pull_request:
13+
14+
permissions: {}
15+
16+
env:
17+
NO_AT_BRIDGE: 1 # Necessary for GTK3 interactive test.
18+
OPENBLAS_NUM_THREADS: 1
19+
PYTHONFAULTHANDLER: 1
20+
21+
jobs:
22+
test:
23+
permissions:
24+
contents: read
25+
name: "Python ${{ matrix.python-version }} on ${{ matrix.os }}"
26+
runs-on: ${{ matrix.os }}
27+
defaults:
28+
run:
29+
working-directory: upstream
30+
31+
strategy:
32+
fail-fast: false
33+
matrix:
34+
include:
35+
- os: ubuntu-24.04-riscv
36+
python-version: '3.12'
37+
38+
steps:
39+
- name: Checkout python-wheels
40+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
41+
with:
42+
persist-credentials: false
43+
44+
- name: Checkout matplotlib
45+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
46+
with:
47+
repository: matplotlib/matplotlib
48+
path: upstream
49+
fetch-depth: 0
50+
persist-credentials: false
51+
52+
- name: Set up Python ${{ matrix.python-version }}
53+
uses: actions/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
54+
with:
55+
python-version: ${{ matrix.python-version }}
56+
allow-prereleases: true
57+
activate-environment: true
58+
enable-cache: false
59+
60+
- name: Install OS dependencies
61+
run: |
62+
echo 'Acquire::Retries "3";' | sudo tee /etc/apt/apt.conf.d/80-retries
63+
sudo apt-get update -yy
64+
sudo apt-get install -yy --no-install-recommends \
65+
ccache \
66+
cm-super \
67+
dvipng \
68+
fonts-freefont-otf \
69+
fonts-noto-cjk \
70+
fonts-wqy-zenhei \
71+
gdb \
72+
gir1.2-gtk-3.0 \
73+
gir1.2-gtk-4.0 \
74+
graphviz \
75+
inkscape \
76+
language-pack-de \
77+
lcov \
78+
libcairo2 \
79+
libcairo2-dev \
80+
libffi-dev \
81+
libgeos-dev \
82+
libnotify4 \
83+
libsdl2-2.0-0 \
84+
libxkbcommon-x11-0 \
85+
libxcb-cursor0 \
86+
libxcb-icccm4 \
87+
libxcb-image0 \
88+
libxcb-keysyms1 \
89+
libxcb-randr0 \
90+
libxcb-render-util0 \
91+
libxcb-xinerama0 \
92+
lmodern \
93+
ninja-build \
94+
pkg-config \
95+
qtbase5-dev \
96+
texlive-fonts-recommended \
97+
texlive-latex-base \
98+
texlive-latex-extra \
99+
texlive-latex-recommended \
100+
texlive-luatex \
101+
texlive-pictures \
102+
texlive-xetex
103+
sudo apt-get install -yy --no-install-recommends ffmpeg poppler-utils
104+
sudo apt-get install -yy --no-install-recommends libgirepository-2.0-dev
105+
106+
- name: Cache pip
107+
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
108+
with:
109+
path: ~/.cache/pip
110+
key: |
111+
${{ matrix.os }}-py${{ matrix.python-version }}-pip-${{
112+
hashFiles('upstream/pyproject.toml', 'upstream/ci/minver-requirements.txt') }}
113+
restore-keys: |
114+
${{ matrix.os }}-py${{ matrix.python-version }}-pip-
115+
- name: Cache ccache
116+
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
117+
with:
118+
path: |
119+
~/.ccache
120+
key: ${{ matrix.os }}-py${{ matrix.python-version }}-ccache-${{ hashFiles('upstream/src/*') }}
121+
restore-keys: |
122+
${{ matrix.os }}-py${{ matrix.python-version }}-ccache-
123+
- name: Cache Matplotlib
124+
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
125+
with:
126+
path: |
127+
~/.cache/matplotlib
128+
!~/.cache/matplotlib/tex.cache
129+
!~/.cache/matplotlib/test_cache
130+
key: 6-${{ matrix.os }}-py${{ matrix.python-version }}-mpl-${{ github.ref }}-${{ github.sha }}
131+
restore-keys: |
132+
6-${{ matrix.os }}-py${{ matrix.python-version }}-mpl-${{ github.ref }}-
133+
6-${{ matrix.os }}-py${{ matrix.python-version }}-mpl-
134+
135+
- name: Install Python dependencies
136+
run: |
137+
# Upgrade pip and setuptools and wheel to get as clean an install as
138+
# possible.
139+
python -m pip install --upgrade pip setuptools wheel
140+
141+
# Install dependencies from PyPI.
142+
# Preinstall build requirements to enable no-build-isolation builds.
143+
python -m pip install --upgrade --prefer-binary \
144+
--group build --group test
145+
146+
# Install optional dependencies from PyPI.
147+
# Sphinx is needed to run sphinxext tests
148+
python -m pip install --upgrade sphinx!=6.1.2
149+
150+
# GUI toolkits are pip-installable only for some versions of Python
151+
# so don't fail if we can't install them. Make it easier to check
152+
# whether the install was successful by trying to import the toolkit
153+
# (sometimes, the install appears to be successful but shared
154+
# libraries cannot be loaded at runtime, so an actual import is a
155+
# better check).
156+
python -m pip install --upgrade pycairo 'cairocffi>=0.8' 'PyGObject' &&
157+
(
158+
python -c 'import gi; gi.require_version("Gtk", "4.0"); from gi.repository import Gtk' &&
159+
echo 'PyGObject 4 is available' || echo 'PyGObject 4 is not available'
160+
) && (
161+
python -c 'import gi; gi.require_version("Gtk", "3.0"); from gi.repository import Gtk' &&
162+
echo 'PyGObject 3 is available' || echo 'PyGObject 3 is not available'
163+
)
164+
165+
# PyQt5 has no riscv64 wheels; skip.
166+
python -mpip install --upgrade --only-binary :all: pyqt6 &&
167+
python -c 'import PyQt6.QtCore' &&
168+
echo 'PyQt6 is available' ||
169+
echo 'PyQt6 is not available'
170+
python -mpip install --upgrade --only-binary :all: pyside6 &&
171+
python -c 'import PySide6.QtCore' &&
172+
echo 'PySide6 is available' ||
173+
echo 'PySide6 is not available'
174+
175+
- name: Install Matplotlib
176+
run: |
177+
ccache -s
178+
git describe
179+
180+
export CPPFLAGS='--coverage -fprofile-abs-path'
181+
182+
python -m pip install --no-deps --no-build-isolation --verbose \
183+
--config-settings=setup-args="-DrcParams-backend=Agg" \
184+
--editable .[dev]
185+
186+
unset CPPFLAGS
187+
188+
- name: Run pytest
189+
run: |
190+
pytest -rfEsXR -n auto \
191+
--maxfail=50 --timeout=300 --durations=25 \
192+
--cov-report=xml --cov=lib --log-level=DEBUG --color=yes
193+
194+
- name: Cleanup non-failed image files
195+
if: failure()
196+
run: |
197+
find ./result_images -name "*-expected*.png" | while read file; do
198+
if [[ $file == *-expected_???.png ]]; then
199+
extension=${file: -7:3}
200+
base=${file%*-expected_$extension.png}_$extension
201+
else
202+
extension="png"
203+
base=${file%-expected.png}
204+
fi
205+
if [[ ! -e ${base}-failed-diff.png ]]; then
206+
indent=""
207+
list=($file $base.png)
208+
if [[ $extension != "png" ]]; then
209+
list+=(${base%_$extension}-expected.$extension ${base%_$extension}.$extension)
210+
fi
211+
for to_remove in "${list[@]}"; do
212+
if [[ -e $to_remove ]]; then
213+
rm $to_remove
214+
echo "${indent}Removed $to_remove"
215+
fi
216+
indent+=" "
217+
done
218+
fi
219+
done
220+
221+
if [ "$(find ./result_images -mindepth 1 -type d)" ]; then
222+
find ./result_images/* -type d -empty -delete
223+
fi
224+
225+
- name: Filter C coverage
226+
if: ${{ !cancelled() }}
227+
run: |
228+
LCOV_IGNORE_ERRORS='mismatch'
229+
lcov --rc lcov_branch_coverage=1 --ignore-errors $LCOV_IGNORE_ERRORS \
230+
--capture --directory . --exclude $PWD/subprojects --exclude $PWD/build \
231+
--output-file coverage.info
232+
lcov --rc lcov_branch_coverage=1 --ignore-errors $LCOV_IGNORE_ERRORS \
233+
--output-file coverage.info --extract coverage.info $PWD/src/'*'
234+
lcov --rc lcov_branch_coverage=1 --ignore-errors $LCOV_IGNORE_ERRORS \
235+
--list coverage.info
236+
find . -name '*.gc*' -delete
237+
238+
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
239+
if: failure()
240+
with:
241+
name: "${{ matrix.python-version }} ${{ matrix.os }} result images"
242+
path: upstream/result_images

0 commit comments

Comments
 (0)