From cfe6527840624ec6812690bd5fd58ab5ee410147 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Tue, 13 Oct 2026 14:06:31 +0000 Subject: [PATCH 1/2] Add riscv64 wheel build for zuvloop 0.0.13 zuvloop is a PyO3-free, Zig-built libuv event loop for asyncio (cp314/cp315 only). Its build toolchain (ziglang 0.16.0) publishes a native riscv64 wheel on PyPI, hatch-ziglang does not special-case the Linux target arch, libuv itself already supports riscv64 upstream, and the test-requires set (aiohttp, httptools, hypothesis, etc.) all resolve riscv64 wheels. No patch is needed. --- .github/workflows/build-zuvloop.yml | 94 +++++++++++++++++++++++++++++ docs/packages/zuvloop.yaml | 5 ++ 2 files changed, 99 insertions(+) create mode 100644 .github/workflows/build-zuvloop.yml create mode 100644 docs/packages/zuvloop.yaml diff --git a/.github/workflows/build-zuvloop.yml b/.github/workflows/build-zuvloop.yml new file mode 100644 index 000000000000..c845ec464222 --- /dev/null +++ b/.github/workflows/build-zuvloop.yml @@ -0,0 +1,94 @@ +# SPDX-FileCopyrightText: 2026 The RISE Project +# SPDX-License-Identifier: MIT +--- +# Based on upstream's own wheel-building job: +# https://github.com/Kludex/zuvloop/blob/v0.0.13/.github/workflows/publish.yml +name: Build zuvloop wheels (riscv64) + +on: + workflow_dispatch: + inputs: + version: + description: 'Version glob to (re)build; empty builds every version of docs/packages/zuvloop.yaml not released yet' + required: false + default: '' + pull_request: + branches: [main] + paths: + - '.github/workflows/build-zuvloop.yml' + - 'docs/packages/zuvloop.yaml' + push: + branches: [main] + paths: + - '.github/workflows/build-zuvloop.yml' + - 'docs/packages/zuvloop.yaml' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read # to fetch code (actions/checkout) + +env: + MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64 + +jobs: + setup: + uses: $/.github/workflows/_setup.yml + with: + package: zuvloop + version: ${{ inputs.version }} + + build_wheels: + needs: [setup] + if: needs.setup.outputs.versions != '[]' + name: Build zuvloop ${{ matrix.version }} ${{ matrix.python }}-manylinux_riscv64 + runs-on: ubuntu-24.04-riscv + timeout-minutes: 90 + strategy: + fail-fast: false + matrix: + version: ${{ fromJSON(needs.setup.outputs.versions) }} + python: ["cp314", "cp314t", "cp315", "cp315t"] + + env: + ZUVLOOP_VERSION: ${{ matrix.version }} + + steps: + - name: Checkout zuvloop v${{ env.ZUVLOOP_VERSION }} + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + repository: Kludex/zuvloop + ref: v${{ env.ZUVLOOP_VERSION }} + persist-credentials: false + + - name: Build wheels + uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0 + with: + only: ${{ matrix.python }}-manylinux_riscv64 + env: + CIBW_MANYLINUX_RISCV64_IMAGE: ${{ env.MANYLINUX_RISCV64_IMAGE }} + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: zuvloop-${{ env.ZUVLOOP_VERSION }}-${{ matrix.python }}-manylinux_riscv64 + path: ./wheelhouse/*.whl + if-no-files-found: error + + publish: + name: Publish zuvloop ${{ matrix.version }} + needs: [setup, build_wheels] + if: needs.setup.outputs.versions != '[]' + strategy: + fail-fast: false + matrix: + version: ${{ fromJSON(needs.setup.outputs.versions) }} + permissions: + contents: write + pull-requests: write + uses: $/.github/workflows/_publish-wheel.yml + secrets: + app-private-key: ${{ secrets.RISEPROJECT_APP_PRIVATE_KEY }} + with: + artifact-pattern: zuvloop-${{ matrix.version }}-*-manylinux_riscv64 diff --git a/docs/packages/zuvloop.yaml b/docs/packages/zuvloop.yaml new file mode 100644 index 000000000000..6a0453d59881 --- /dev/null +++ b/docs/packages/zuvloop.yaml @@ -0,0 +1,5 @@ +package-name: zuvloop +source-code: https://github.com/Kludex/zuvloop +license: MIT +versions: +- version: 0.0.13 From 4a23ee5431c41d6b3a1877f2bc7fa08ab136c35e Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Fri, 16 Oct 2026 01:16:37 +0000 Subject: [PATCH 2/2] Fix manylinux_riscv64 build: define RISC-V float ABI macros for Zig cImport All four riscv64 legs (cp314, cp314t, cp315, cp315t) failed identically while compiling zig/c.zig's @cImport of python_shim.h: zig/c.zig:1:15: error: C import failed /usr/include/bits/setjmp.h:35:3: error: unsupported FLEN Zig 0.16's translate-c (Aro) predefines no RISC-V float-ABI macros (__riscv_flen, __riscv_float_abi_double), which glibc's riscv bits/setjmp.h requires when pulled in via pthread.h from Python.h. This is the porting playbook's gotcha 634, previously hit and fixed the same way for zttp (same upstream family, same ziglang==0.16.0 pin). Add a patch that defines both macros inside the @cImport block when targeting riscv64 with the d extension, and wire it into the workflow the same way build-zttp.yml does: checkout python-wheels alongside the upstream source and `git apply` the patch before cibuildwheel runs. Reproduced and verified the fix in isolation with `zig translate-c -target riscv64-linux-gnu.2.39`, which hits the same glibc setjmp.h check with no riscv64 runner needed. --- .github/workflows/build-zuvloop.yml | 9 ++++ ...-RISC-V-float-ABI-macros-for-cImport.patch | 51 +++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 patches/zuvloop/0.0.13/0001-zig-c.zig-define-RISC-V-float-ABI-macros-for-cImport.patch diff --git a/.github/workflows/build-zuvloop.yml b/.github/workflows/build-zuvloop.yml index c845ec464222..4f11a754bcd8 100644 --- a/.github/workflows/build-zuvloop.yml +++ b/.github/workflows/build-zuvloop.yml @@ -63,6 +63,15 @@ jobs: ref: v${{ env.ZUVLOOP_VERSION }} persist-credentials: false + - name: Checkout python-wheels + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + path: python-wheels + persist-credentials: false + + - name: Patch zuvloop source + run: git apply python-wheels/patches/zuvloop/${{ env.ZUVLOOP_VERSION }}/*.patch + - name: Build wheels uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0 with: diff --git a/patches/zuvloop/0.0.13/0001-zig-c.zig-define-RISC-V-float-ABI-macros-for-cImport.patch b/patches/zuvloop/0.0.13/0001-zig-c.zig-define-RISC-V-float-ABI-macros-for-cImport.patch new file mode 100644 index 000000000000..46ea35edda14 --- /dev/null +++ b/patches/zuvloop/0.0.13/0001-zig-c.zig-define-RISC-V-float-ABI-macros-for-cImport.patch @@ -0,0 +1,51 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ludovic Henry +Date: Fri, 16 Oct 2026 00:00:00 +0200 +Subject: [PATCH] zig/c.zig: define RISC-V float ABI macros for @cImport + +Zig 0.16's translate-c runs on Aro, whose predefined macros for RISC-V +stop at `__riscv` and `__riscv_xlen`: it never emits `__riscv_flen` or +`__riscv_float_abi_double`, which clang and GCC define for an lp64d +target. glibc's riscv `bits/setjmp.h`, pulled in by Python.h through +pthread.h, requires one of the `__riscv_float_abi_*` macros: + + /usr/include/bits/setjmp.h:35:3: error: unsupported FLEN + +so the @cImport of python_shim.h fails and no manylinux_riscv64 wheel +can be built (reproduced identically on cp314 and cp314t; musl's +headers do not test these macros, so a musllinux_riscv64 leg of this +matrix would be unaffected, same as the zttp case this mirrors - see +CLAUDE.md gotcha 634). + +Zig master already emits these macros from Aro (ziglang/zig commit +b46a7f3a25a6, "sync aro & translate-c"); this is unnecessary once +zuvloop moves to a Zig release that contains it (zuvloop currently +pins ziglang==0.16.0). + +Upstream-Status: To upstream [not yet submitted; workaround for Zig 0.16, fixed by ziglang/zig b46a7f3a25a6 on master] +--- + zig/c.zig | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/zig/c.zig b/zig/c.zig +index 1c610ab..d7df92b 100644 +--- a/zig/c.zig ++++ b/zig/c.zig +@@ -1,5 +1,15 @@ ++const builtin = @import("builtin"); ++ + pub const c = @cImport({ + @cDefine("PY_SSIZE_T_CLEAN", {}); ++ // Zig 0.16's translate-c (Aro) predefines no RISC-V floating-point macros, ++ // so glibc's riscv bits/setjmp.h (reached via pthread.h from python_shim.h) ++ // hits `#error unsupported FLEN`. Define what clang does for an lp64d ++ // target; Zig master already emits these itself. ++ if (builtin.target.cpu.arch.isRISCV() and builtin.target.cpu.has(.riscv, .d)) { ++ @cDefine("__riscv_flen", "64"); ++ @cDefine("__riscv_float_abi_double", "1"); ++ } + @cInclude("python_shim.h"); + @cInclude("context_shim.h"); + }); +-- +2.43.0