Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 114 additions & 0 deletions .github/workflows/build-pillow.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
---
name: Build pillow wheels (riscv64)

on:
workflow_dispatch:
inputs:
version:
description: 'pillow version to build (git tag without leading v, e.g. 12.3.0)'
required: true
default: '12.3.0'
pull_request:
paths:
- '.github/workflows/build-pillow.yml'
- '.github/workflows/test-pillow.yml'
- 'patches/pillow/**'

concurrency:
group: ${{ github.workflow }}-${{ inputs.version || '12.3.0' }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

permissions:
contents: read # to fetch code (actions/checkout)

env:
PILLOW_VERSION: ${{ inputs.version || '12.3.0' }}
UV_EXTRA_INDEX_URL: https://pypi.riseproject.dev/simple/
UV_INDEX_STRATEGY: unsafe-best-match
UV_ONLY_BINARY: ':all:'
MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64

jobs:
build_wheels:
name: Build pillow ${{ inputs.version || '12.3.0' }} ${{ matrix.python }}-manylinux_riscv64
runs-on: ubuntu-24.04-riscv
strategy:
fail-fast: false
matrix:
python: ["cp312", "cp313", "cp314", "cp314t"]

steps:
- name: Checkout pillow v${{ env.PILLOW_VERSION }}
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
repository: python-pillow/Pillow
ref: ${{ env.PILLOW_VERSION }}
submodules: true
persist-credentials: false

- name: Checkout python-wheels
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
path: python-wheels
persist-credentials: false

# Works around a GCC LTO bug (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110812)
# hit when building libavif as a Pillow wheel dependency on riscv64.
- name: Patch pillow source
run: |
git apply python-wheels/patches/pillow/${{ env.PILLOW_VERSION }}/00*.patch

- name: Install Python
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
with:
python-version: '3.12'
activate-environment: true
enable-cache: false

- name: Build wheels
uses: pypa/cibuildwheel@294735312765b09d24a2fbec22660ce817587d55 # v4.1.0
env:
CIBW_BUILD: ${{ matrix.python }}-manylinux_riscv64
CIBW_MANYLINUX_RISCV64_IMAGE: ${{ env.MANYLINUX_RISCV64_IMAGE }}
# libjpeg-turbo doesn't provide riscv64 SIMD before v3.2, and the
# version vendored by Pillow's wheel build is older than that; also
# disable arch-specific AOM optimization, see
# https://aomedia.issues.chromium.org/issues/492439207. Passed as
# cmake flags (picked up by the libavif build) rather than patching
# Pillow sources, matching the fix proven previously in
# wheel_builder/wheel_builder/Pillow/gitlab-ci.yml.
HOST_CMAKE_FLAGS: "-DWITH_SIMD=0 -DAOM_TARGET_CPU=generic"
CIBW_ENVIRONMENT_PASS_LINUX: HOST_CMAKE_FLAGS
CIBW_BUILD_FRONTEND: "build[uv]"
CIBW_ENVIRONMENT: >-
UV_EXTRA_INDEX_URL=https://pypi.riseproject.dev/simple/
UV_INDEX_STRATEGY=unsafe-best-match
UV_ONLY_BINARY=:all:

- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: pillow-${{ env.PILLOW_VERSION }}-${{ matrix.python }}-manylinux_riscv64
path: ./wheelhouse/*.whl
if-no-files-found: error

publish:
name: Publish pillow ${{ inputs.version || '12.3.0' }} to GitLab
needs: [build_wheels]
# Only publish when the workflow was triggered from main with a specific
# version. Manual trigger is the only entry point, so checking the ref is
# enough to gate uploads.
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write

steps:
- name: Publish wheels and open docs PR
uses: riseproject-dev/python-wheels/actions/publish-wheels@main
with:
artifact-pattern: pillow-${{ env.PILLOW_VERSION }}-*-manylinux_riscv64
gitlab-username: ${{ vars.GITLAB_DEPLOY_USER }}
gitlab-token: ${{ secrets.GITLAB_DEPLOY_TOKEN }}
gitlab-project-id: ${{ vars.GITLAB_PROJECT_ID }}
gh-token: ${{ secrets.GITHUB_TOKEN }}
94 changes: 94 additions & 0 deletions .github/workflows/test-pillow.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
---
name: Test pillow (riscv64)

on:
workflow_dispatch:
inputs:
version:
description: 'pillow version to test (git tag without leading v, e.g. 12.3.0)'
required: true
default: '12.3.0'
pull_request:
paths:
- '.github/workflows/test-pillow.yml'

concurrency:
group: ${{ github.workflow }}-${{ inputs.version || '12.3.0' }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

permissions:
contents: read # to fetch code (actions/checkout)

env:
FORCE_COLOR: 1
PIP_DISABLE_PIP_VERSION_CHECK: 1
PILLOW_VERSION: ${{ inputs.version || '12.3.0' }}

jobs:
test:
permissions:
contents: read
name: "Test pillow ${{ inputs.version || '12.3.0' }} — Python ${{ matrix.python-version }} on ${{ matrix.os }}"
runs-on: ${{ matrix.os }}

strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-24.04-riscv
python-version: '3.12'

steps:
- name: Checkout pillow v${{ env.PILLOW_VERSION }}
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
repository: python-pillow/Pillow
ref: ${{ env.PILLOW_VERSION }}
submodules: true
persist-credentials: false

- name: Checkout python-wheels
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
path: python-wheels
persist-credentials: false

# Works around a GCC LTO bug (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110812)
# hit when building libavif as a Pillow wheel dependency on riscv64.
- name: Patch pillow source
run: |
git apply python-wheels/patches/pillow/${{ env.PILLOW_VERSION }}/00*.patch

- name: Set up Python ${{ matrix.python-version }}
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
with:
python-version: ${{ matrix.python-version }}
activate-environment: true
enable-cache: false

- name: Install Linux dependencies
run: |
.ci/install.sh
env:
GHA_PYTHON_VERSION: ${{ matrix.python-version }}

- name: Build
run: |
.ci/build.sh

- name: Test
run: |
xvfb-run -s '-screen 0 1024x768x24' sway&
export WAYLAND_DISPLAY=wayland-1
.ci/test.sh

- name: Prepare to upload errors
if: failure()
run: |
mkdir -p Tests/errors

- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: failure()
with:
name: "pillow-${{ env.PILLOW_VERSION }}-py${{ matrix.python-version }}-${{ matrix.os }}-errors"
path: Tests/errors
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
From 1bbab6afa8f1bf6d64d3db7b977975e45235c80d Mon Sep 17 00:00:00 2001
From: Trevor Gamblin <tgamblin@baylibre.com>
Date: Thu, 23 Jul 2026 13:20:47 -0400
Subject: [PATCH] .ci: test.sh: skip test_grabclipboard_wl_clipboard

This test depends on a Wayland server and XDG_RUNTIME_DIR to be set. We
don't want to rely on a graphical configuration on the runners, so skip
it.

Upstream-Status: Inappropriate [workaround for RISC-V runner builds]

Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
---
.ci/test.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.ci/test.sh b/.ci/test.sh
index 87a605d84..910e7094e 100755
--- a/.ci/test.sh
+++ b/.ci/test.sh
@@ -4,4 +4,4 @@ set -e

python3 -c "from PIL import Image"

-python3 -bb -m pytest -vv -x -W always --cov PIL --cov Tests --cov-report term --cov-report xml Tests $REVERSE
+python3 -bb -m pytest -vv -x -k "not test_grabclipboard_wl_clipboard" -W always --cov PIL --cov Tests --cov-report term --cov-report xml Tests $REVERSE
--
2.55.0

71 changes: 71 additions & 0 deletions patches/pillow/12.3.0/0001-Pillow-.ci-use-uv-pip.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
From de055b09de48b863c8c779fa6ac9cca59cbba07f Mon Sep 17 00:00:00 2001
From: Trevor Gamblin <tgamblin@baylibre.com>
Date: Thu, 23 Jul 2026 08:54:31 -0400
Subject: [PATCH] Pillow: .ci: use 'uv pip'

We use uv in our workflows, so replace 'python3 -m pip' with 'uv pip' in
the .ci scripts run by the Pillow pipelines.

Upstream-Status: Inappropriate [different Python management tooling]

Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
---
.ci/after_success.sh | 2 +-
.ci/install.sh | 24 ++++++++++++------------
2 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/.ci/after_success.sh b/.ci/after_success.sh
index 6da27b975..daacfd20d 100755
--- a/.ci/after_success.sh
+++ b/.ci/after_success.sh
@@ -1,5 +1,5 @@
#!/bin/bash

# gather the coverage data
-python3 -m pip install coverage
+uv pip install coverage
python3 -m coverage xml
diff --git a/.ci/install.sh b/.ci/install.sh
index db680db96..f96e8d99a 100755
--- a/.ci/install.sh
+++ b/.ci/install.sh
@@ -22,24 +22,24 @@ sudo apt-get -qq install libfreetype6-dev liblcms2-dev libtiff-dev python3-tk\
cmake meson imagemagick libharfbuzz-dev libfribidi-dev\
sway wl-clipboard libopenblas-dev nasm

-python3 -m pip install --upgrade pip
-python3 -m pip install --upgrade wheel
-python3 -m pip install coverage
-python3 -m pip install defusedxml
-python3 -m pip install ipython
-python3 -m pip install olefile
-python3 -m pip install -U pytest
-python3 -m pip install -U pytest-cov
-python3 -m pip install -U pytest-timeout
+uv pip install --upgrade pip
+uv pip install --upgrade wheel
+uv pip install coverage
+uv pip install defusedxml
+uv pip install ipython
+uv pip install olefile
+uv pip install -U pytest
+uv pip install -U pytest-cov
+uv pip install -U pytest-timeout
# optional test dependencies, only install if there's a binary package.
-python3 -m pip install --only-binary=:all: numpy || true
-python3 -m pip install --only-binary=:all: pyarrow || true
+uv pip install --only-binary=:all: numpy || true
+uv pip install --only-binary=:all: pyarrow || true

# PyQt6 doesn't support PyPy3
if [[ $GHA_PYTHON_VERSION == 3.* ]]; then
sudo apt-get -qq install libegl1 libxcb-cursor0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-shape0 libxkbcommon-x11-0
# pyqt6 doesn't yet support free-threading; only install if a wheel is available
- python3 -m pip install --only-binary=:all: pyqt6 || true
+ uv pip install --only-binary=:all: pyqt6 || true
fi

# webp
--
2.55.0

Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
From 672262c8715b24485f82e18580fe33786dbce2b9 Mon Sep 17 00:00:00 2001
From: Trevor Gamblin <tgamblin@baylibre.com>
Date: Thu, 23 Jul 2026 10:57:00 -0400
Subject: [PATCH] depends: install_libavif.sh: fix cache LIBDIR for non-x86_64
hosts

The GitHub Actions cache restore/save paths hardcode
LIBDIR=/usr/lib/x86_64-linux-gnu, but on riscv64 the multiarch install
path is /usr/lib/riscv64-linux-gnu. The cache-save cp then fails:

cp: cannot stat '/usr/lib/x86_64-linux-gnu/libavif.so*': No such file or directory

Because that cp isn't the last command in an && list, `set -e`
doesn't stop the script there either, so it falls through with a
stale working directory and breaks the next dependency's `pushd
depends` in .ci/install.sh:

.ci/install.sh: line 58: pushd: depends: No such file or directory

Derive LIBDIR from `uname -m` instead of hardcoding the triplet.

Upstream-Status: To upstream [relevant for non-x86_64 CI runners]

Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
---
depends/install_libavif.sh | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/depends/install_libavif.sh b/depends/install_libavif.sh
index b837f6d65..ae4d7f87a 100755
--- a/depends/install_libavif.sh
+++ b/depends/install_libavif.sh
@@ -5,7 +5,7 @@ version=1.4.2

if [[ "$GHA_LIBAVIF_CACHE_HIT" == "true" ]]; then

- LIBDIR=/usr/lib/x86_64-linux-gnu
+ LIBDIR=/usr/lib/$(uname -m)-linux-gnu

# Copy cached files into place
sudo cp ~/cache-libavif/lib/* $LIBDIR/
@@ -80,7 +80,7 @@ else

if [ -n "$GITHUB_ACTIONS" ] && [ "$(uname)" != "Darwin" ]; then
# Copy to cache
- LIBDIR=/usr/lib/x86_64-linux-gnu
+ LIBDIR=/usr/lib/$(uname -m)-linux-gnu
rm -rf ~/cache-libavif
mkdir -p ~/cache-libavif/lib
mkdir -p ~/cache-libavif/include
--
2.55.0

Loading
Loading