From f2ae5dfc010ceef52cc2f579da682698b1336ace Mon Sep 17 00:00:00 2001 From: Bruno Verachten Date: Thu, 12 Mar 2026 10:00:17 +0100 Subject: [PATCH 1/8] feat: add riscv64 to Linux wheel build matrix Add QEMU emulation for riscv64 and include riscv64 in the build matrix so that linux_riscv64 wheels are built alongside existing architectures. --- .github/workflows/build-wheels.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/build-wheels.yml b/.github/workflows/build-wheels.yml index e0092df2..d4950c3f 100644 --- a/.github/workflows/build-wheels.yml +++ b/.github/workflows/build-wheels.yml @@ -36,6 +36,12 @@ jobs: CIBW_SKIP: "${{ !inputs.build-all && '*-musllinux_*' || '' }}" steps: + - name: Set up QEMU + if: matrix.archs == 'riscv64' + uses: docker/setup-qemu-action@v3 + with: + platforms: riscv64 + - name: Checkout code uses: actions/checkout@v5 From 1dab4f5583921677e19c0eeedbe62cf322dd1ec6 Mon Sep 17 00:00:00 2001 From: Bruno Verachten Date: Sun, 5 Apr 2026 12:22:00 +0200 Subject: [PATCH 2/8] ci: upgrade setup-qemu-action v3 to v4 Signed-off-by: Bruno Verachten --- .github/workflows/build-wheels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-wheels.yml b/.github/workflows/build-wheels.yml index d4950c3f..cdb1c89b 100644 --- a/.github/workflows/build-wheels.yml +++ b/.github/workflows/build-wheels.yml @@ -38,7 +38,7 @@ jobs: steps: - name: Set up QEMU if: matrix.archs == 'riscv64' - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0 with: platforms: riscv64 From deb46b3d2553b25435c37525d28db38e2861bce0 Mon Sep 17 00:00:00 2001 From: Bruno Verachten Date: Sat, 11 Apr 2026 21:44:01 +0200 Subject: [PATCH 3/8] ci: fix riscv64 matrix entry and use native RISE runner The QEMU setup step was present but the riscv64 matrix entry was missing, so it never triggered. Replace the QEMU approach with a native ubuntu-24.04-riscv runner (RISE Project). The pypa/cibuildwheel action calls actions/setup-python internally, which has no riscv64 binaries. Add a dedicated riscv64 step that installs cibuildwheel via pip and runs it directly, consistent with how other projects handle native riscv64 CI with RISE runners. Signed-off-by: Bruno Verachten --- .github/workflows/build-wheels.yml | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-wheels.yml b/.github/workflows/build-wheels.yml index cdb1c89b..a2f72167 100644 --- a/.github/workflows/build-wheels.yml +++ b/.github/workflows/build-wheels.yml @@ -23,6 +23,8 @@ jobs: archs: aarch64 - os: ubuntu-latest archs: x86_64 + - os: ubuntu-24.04-riscv + archs: riscv64 - os: macos-latest archs: arm64 - os: macos-15-intel @@ -36,12 +38,6 @@ jobs: CIBW_SKIP: "${{ !inputs.build-all && '*-musllinux_*' || '' }}" steps: - - name: Set up QEMU - if: matrix.archs == 'riscv64' - uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0 - with: - platforms: riscv64 - - name: Checkout code uses: actions/checkout@v5 @@ -57,7 +53,21 @@ jobs: if: runner.os != 'Linux' uses: astral-sh/setup-uv@v7 + # On riscv64 the pypa/cibuildwheel action calls actions/setup-python + # internally, which has no riscv64 binaries. Install and run cibuildwheel + # directly via pip instead. + - name: Build & Test Wheels (riscv64 native) + if: matrix.archs == 'riscv64' + run: | + export PATH="/opt/python-3.12/bin:$PATH" + pip install cibuildwheel==3.2.1 + python3 -m cibuildwheel --output-dir wheelhouse dist/${{ inputs.sdist-name }} + env: + CIBW_ARCHS: riscv64 + CIBW_CONFIG_FILE: .cibuildwheel.toml + - name: Build & Test Wheels + if: matrix.archs != 'riscv64' uses: pypa/cibuildwheel@v3.2.1 with: config-file: .cibuildwheel.toml From fa85a5786adf3769036623a111f0beb8f5902940 Mon Sep 17 00:00:00 2001 From: Bruno Verachten Date: Sat, 11 Apr 2026 21:52:25 +0200 Subject: [PATCH 4/8] ci: add standalone riscv64 benchmark workflow workflow_dispatch trigger that builds the sdist then runs cibuildwheel on the native ubuntu-24.04-riscv runner. Bypasses the full CI pipeline which requires a fork release to exist. Produces real build times for upstream discussion. Signed-off-by: Bruno Verachten --- .github/workflows/benchmark-riscv64.yml | 58 +++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 .github/workflows/benchmark-riscv64.yml diff --git a/.github/workflows/benchmark-riscv64.yml b/.github/workflows/benchmark-riscv64.yml new file mode 100644 index 00000000..39ad9ef1 --- /dev/null +++ b/.github/workflows/benchmark-riscv64.yml @@ -0,0 +1,58 @@ +name: Benchmark riscv64 wheel build + +on: + workflow_dispatch: + +# Standalone riscv64-only wheel build for timing purposes. +# Bypasses the full CI pipeline (which requires a release to exist on the fork). +# Produces real build times on ubuntu-24.04-riscv (RISE native runner) for +# upstream discussion at jcrist/msgspec#987. + +permissions: + contents: read + +jobs: + sdist: + name: Build source distribution + runs-on: ubuntu-latest + outputs: + sdist-name: ${{ steps.build.outputs.sdist-name }} + steps: + - uses: actions/checkout@v5 + - uses: astral-sh/setup-uv@v7 + - name: Build sdist + id: build + run: | + uv build --sdist + sdist_name=$(basename dist/*.tar.gz) + echo "sdist-name=${sdist_name}" >> "$GITHUB_OUTPUT" + - uses: actions/upload-artifact@v5 + with: + name: artifact-sdist + path: dist/${{ steps.build.outputs.sdist-name }} + if-no-files-found: error + + build-riscv64: + name: Build wheels on ubuntu-24.04-riscv for riscv64 + needs: sdist + runs-on: ubuntu-24.04-riscv + steps: + - uses: actions/checkout@v5 + - name: Download source distribution + uses: actions/download-artifact@v6 + with: + name: artifact-sdist + path: dist + - name: Build & Test Wheels (riscv64 native) + run: | + export PATH="/opt/python-3.12/bin:$PATH" + pip install cibuildwheel==3.2.1 + python3 -m cibuildwheel --output-dir wheelhouse dist/${{ needs.sdist.outputs.sdist-name }} + env: + CIBW_ARCHS: riscv64 + CIBW_CONFIG_FILE: .cibuildwheel.toml + - uses: actions/upload-artifact@v5 + with: + name: artifact-wheels-riscv64 + path: wheelhouse/*.whl + if-no-files-found: error From 08b9b9cf8d14b285f0de9f72dbbaa691f2e9f5ae Mon Sep 17 00:00:00 2001 From: Bruno Verachten Date: Sat, 11 Apr 2026 21:59:32 +0200 Subject: [PATCH 5/8] ci: fix pip path on RISE riscv64 runner Use /opt/python-3.12/bin/python3.12 -m pip directly. No python3/pip symlink in PATH on ubuntu-24.04-riscv by default. Also pass sdist name via env var instead of inline expression. Signed-off-by: Bruno Verachten --- .github/workflows/benchmark-riscv64.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/benchmark-riscv64.yml b/.github/workflows/benchmark-riscv64.yml index 39ad9ef1..7f31d6fc 100644 --- a/.github/workflows/benchmark-riscv64.yml +++ b/.github/workflows/benchmark-riscv64.yml @@ -36,6 +36,8 @@ jobs: name: Build wheels on ubuntu-24.04-riscv for riscv64 needs: sdist runs-on: ubuntu-24.04-riscv + env: + SDIST_NAME: ${{ needs.sdist.outputs.sdist-name }} steps: - uses: actions/checkout@v5 - name: Download source distribution @@ -45,9 +47,8 @@ jobs: path: dist - name: Build & Test Wheels (riscv64 native) run: | - export PATH="/opt/python-3.12/bin:$PATH" - pip install cibuildwheel==3.2.1 - python3 -m cibuildwheel --output-dir wheelhouse dist/${{ needs.sdist.outputs.sdist-name }} + /opt/python-3.12/bin/python3.12 -m pip install cibuildwheel==3.2.1 + /opt/python-3.12/bin/python3.12 -m cibuildwheel --output-dir wheelhouse "dist/${SDIST_NAME}" env: CIBW_ARCHS: riscv64 CIBW_CONFIG_FILE: .cibuildwheel.toml From 3417994bf5e5bbadad3d1531564429afb4444ce7 Mon Sep 17 00:00:00 2001 From: Bruno Verachten Date: Sun, 12 Apr 2026 11:07:22 +0200 Subject: [PATCH 6/8] ci: fix cibuildwheel config loading and remove hardcoded Python path - Pass CIBW_CONFIG_FILE as an absolute path (${{ github.workspace }}) so the config is loaded correctly when invoking cibuildwheel via uvx (relative path resolution differs from the pypa/cibuildwheel action) - Replace /opt/python-3.12 hardcoded path with uvx cibuildwheel==3.2.1; add astral-sh/setup-uv@v7 step for riscv64 (already used on non-Linux) - Extend the uv install condition to include riscv64 Linux runners Signed-off-by: Bruno Verachten --- .github/workflows/benchmark-riscv64.yml | 7 +++---- .github/workflows/build-wheels.yml | 13 ++++++------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/.github/workflows/benchmark-riscv64.yml b/.github/workflows/benchmark-riscv64.yml index 7f31d6fc..982059ed 100644 --- a/.github/workflows/benchmark-riscv64.yml +++ b/.github/workflows/benchmark-riscv64.yml @@ -40,18 +40,17 @@ jobs: SDIST_NAME: ${{ needs.sdist.outputs.sdist-name }} steps: - uses: actions/checkout@v5 + - uses: astral-sh/setup-uv@v7 - name: Download source distribution uses: actions/download-artifact@v6 with: name: artifact-sdist path: dist - name: Build & Test Wheels (riscv64 native) - run: | - /opt/python-3.12/bin/python3.12 -m pip install cibuildwheel==3.2.1 - /opt/python-3.12/bin/python3.12 -m cibuildwheel --output-dir wheelhouse "dist/${SDIST_NAME}" + run: uvx cibuildwheel==3.2.1 --output-dir wheelhouse "dist/${SDIST_NAME}" env: CIBW_ARCHS: riscv64 - CIBW_CONFIG_FILE: .cibuildwheel.toml + CIBW_CONFIG_FILE: ${{ github.workspace }}/.cibuildwheel.toml - uses: actions/upload-artifact@v5 with: name: artifact-wheels-riscv64 diff --git a/.github/workflows/build-wheels.yml b/.github/workflows/build-wheels.yml index a2f72167..93653508 100644 --- a/.github/workflows/build-wheels.yml +++ b/.github/workflows/build-wheels.yml @@ -50,21 +50,20 @@ jobs: # TODO: Remove this once the action supports specifying extras, see: # https://github.com/pypa/cibuildwheel/pull/2630 - name: Install uv - if: runner.os != 'Linux' + if: runner.os != 'Linux' || matrix.archs == 'riscv64' uses: astral-sh/setup-uv@v7 # On riscv64 the pypa/cibuildwheel action calls actions/setup-python - # internally, which has no riscv64 binaries. Install and run cibuildwheel - # directly via pip instead. + # internally, which has no riscv64 binaries. Run cibuildwheel via uvx + # instead. Keep version in sync with pypa/cibuildwheel@v3.2.1 below. - name: Build & Test Wheels (riscv64 native) if: matrix.archs == 'riscv64' run: | - export PATH="/opt/python-3.12/bin:$PATH" - pip install cibuildwheel==3.2.1 - python3 -m cibuildwheel --output-dir wheelhouse dist/${{ inputs.sdist-name }} + uvx cibuildwheel==3.2.1 --output-dir wheelhouse \ + dist/${{ inputs.sdist-name }} env: CIBW_ARCHS: riscv64 - CIBW_CONFIG_FILE: .cibuildwheel.toml + CIBW_CONFIG_FILE: ${{ github.workspace }}/.cibuildwheel.toml - name: Build & Test Wheels if: matrix.archs != 'riscv64' From 48fe1ba878e2a84e2d11afe3ac22997e96bab3d5 Mon Sep 17 00:00:00 2001 From: Bruno Verachten Date: Sun, 12 Apr 2026 12:01:05 +0200 Subject: [PATCH 7/8] ci: pass --config-file as CLI arg to cibuildwheel The CIBW_CONFIG_FILE env var was not being picked up when cibuildwheel runs against an sdist (it finds pyproject.toml in the extracted source tree and uses that instead). Pass the config path explicitly via the --config-file CLI argument so it takes precedence regardless of what files are present in the build working directory. Drop CIBW_CONFIG_FILE from env since --config-file supersedes it. Signed-off-by: Bruno Verachten --- .github/workflows/benchmark-riscv64.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/benchmark-riscv64.yml b/.github/workflows/benchmark-riscv64.yml index 982059ed..f224df32 100644 --- a/.github/workflows/benchmark-riscv64.yml +++ b/.github/workflows/benchmark-riscv64.yml @@ -47,10 +47,13 @@ jobs: name: artifact-sdist path: dist - name: Build & Test Wheels (riscv64 native) - run: uvx cibuildwheel==3.2.1 --output-dir wheelhouse "dist/${SDIST_NAME}" + run: | + uvx cibuildwheel==3.2.1 \ + --config-file "$GITHUB_WORKSPACE/.cibuildwheel.toml" \ + --output-dir wheelhouse \ + "dist/${SDIST_NAME}" env: CIBW_ARCHS: riscv64 - CIBW_CONFIG_FILE: ${{ github.workspace }}/.cibuildwheel.toml - uses: actions/upload-artifact@v5 with: name: artifact-wheels-riscv64 From 16ae63bb07dbfcfdf42b797b5d342c2659065b23 Mon Sep 17 00:00:00 2001 From: Bruno Verachten Date: Sun, 12 Apr 2026 14:03:48 +0200 Subject: [PATCH 8/8] ci: override build frontend to pip for riscv64 benchmark build[uv] from .cibuildwheel.toml requires uv to be pre-installed inside the container. The musllinux_1_2_riscv64 image does not ship uv, causing 'which uv' to fail during environment setup. Override via CIBW_BUILD_FRONTEND=pip which works without uv in the container and is sufficient for the benchmark timing goal. Signed-off-by: Bruno Verachten --- .github/workflows/benchmark-riscv64.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/benchmark-riscv64.yml b/.github/workflows/benchmark-riscv64.yml index f224df32..a9e2031b 100644 --- a/.github/workflows/benchmark-riscv64.yml +++ b/.github/workflows/benchmark-riscv64.yml @@ -54,6 +54,9 @@ jobs: "dist/${SDIST_NAME}" env: CIBW_ARCHS: riscv64 + # build[uv] from .cibuildwheel.toml requires uv inside the container, + # which is not pre-installed in the musllinux image. Override to pip. + CIBW_BUILD_FRONTEND: pip - uses: actions/upload-artifact@v5 with: name: artifact-wheels-riscv64