feat: add riscv64 to Linux wheel build matrix#987
feat: add riscv64 to Linux wheel build matrix#987gounthar wants to merge 10 commits intojcrist:mainfrom
Conversation
Add QEMU emulation for riscv64 and include riscv64 in the build matrix so that linux_riscv64 wheels are built alongside existing architectures.
|
Native build verified on riscv64 hardware (BananaPi F3, SpacemiT K1, rv64gc, GCC 14.2.0): SUCCESS. |
Signed-off-by: Bruno Verachten <gounthar@gmail.com>
|
Updated |
.github/workflows/build-wheels.yml
Outdated
| - name: Set up QEMU | ||
| if: matrix.archs == 'riscv64' | ||
| uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0 | ||
| with: | ||
| platforms: riscv64 |
There was a problem hiding this comment.
Small thing here: the if: matrix.archs == 'riscv64' condition will never match, because there's no riscv64 entry in strategy.matrix.include above (only aarch64/x86_64/arm64/AMD64). The matrix entry mentioned in the PR description seems to have been lost from the patch. Without it this step is always skipped and no riscv64 wheels get built. I think you also need to add:
- os: ubuntu-latest
archs: riscv64to the matrix above.
There was a problem hiding this comment.
Good catch, thanks. Fixed in the latest push.
Two changes beyond just adding the matrix entry:
-
Replaced QEMU emulation with a native
ubuntu-24.04-riscvrunner (RISE Project free runners). Native is faster and more representative than emulation. -
The
pypa/cibuildwheelaction callsactions/setup-pythoninternally, which has no riscv64 binaries. Added a dedicated riscv64 step that installs cibuildwheel viapipand runs it directly — this is the established workaround for native riscv64 CI.
|
Thanks for putting this together @gounthar, and for the detailed evidence and ecosystem context in the description - it really helps to see the bigger picture here. RISC-V wheels would be a nice addition for msgspec. I left an inline note on the QEMU step - looks like the matrix entry from the PR description didn't make it into the patch, and without it the step never runs. That's a blocker for the functional part. Good news on the compatibility side: cibuildwheel has had riscv64 enabled by default since v3.1.2 for anyone targeting it (changelog #2509), and we're already pinned to v3.2.1, so no extra A few things on my mind, mostly around CI cost:
Happy to help with any of the above if it's easier, just let me know. |
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 <gounthar@gmail.com>
|
Thanks for the review, @Siyet. On the QEMU / build time question: the latest push drops QEMU and uses native On tests: with a native runner I'd lean toward leaving them enabled rather than skipping, but if the per-wheel time turns out to be too long in practice, adding On current main: I believe the branch is already based on 0.21.0 (0 commits behind upstream), the 5 commits ahead are CI-only. I should have a CI run to point at shortly. I'll follow up once that's done rather than asking you to take my word for it. Happy to rework any of this if the direction isn't right. |
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 <gounthar@gmail.com>
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 <gounthar@gmail.com>
|
Fork CI numbers are in: native build on The fork is 0 commits behind On tests: with native completing in under 30 minutes with tests on, I'd leave them enabled for now. Easy to add Happy to adjust if the direction isn't right. |
|
Thanks @gounthar for the fast turnaround, and especially for putting together the benchmark workflow for timing - that's exactly what I asked for. Switching from QEMU to native RISE Project runners is the right call, and a better one than I had suggested myself. I also saw your follow-up note saying the benchmark covers all 7 interpreters with tests included - my close read of the run logs actually disagrees with both points (details in the first section below). I think there's a config-loading issue at play that's quietly hiding it. I went through the benchmark run and found a few things we need to talk about before this PR can land. Critical:
|
| Job | Time |
|---|---|
| macos arm64 | 2:47 |
| windows AMD64 | 4:04 |
| macos x86_64 | 4:06 |
| windows ARM64 | 4:52 |
| ubuntu x86_64 | 5:56 |
| ubuntu aarch64 (longest) | 6:15 |
| riscv64 (no tests, from benchmark) | ~27:00 |
| riscv64 (with tests, estimate) | likely 35-45 min |
That means release CI grows from ~6 minutes to ~30-45 minutes on the longest path. And this isn't just release CI - build-wheels also runs on every PR that touches src/msgspec/**, pyproject.toml, or .cibuildwheel.toml (see the paths filter in ci.yml). On PRs build-all=false, musllinux is skipped, leaving 6 wheels - so PR CI grows from ~3-4 minutes to ~13-20 minutes on the longest path, on every PR that touches C code or build config.
I'm a new collaborator on this project and a CI duration increase of this size isn't a decision I'm comfortable making on my own. It needs explicit sign-off from @jcrist or @ofek. I'd like to hear from one of you whether the project is OK with this kind of feedback-loop slowdown for riscv64 wheels, or whether we should look for ways to reduce it - for example, building only the latest stable Python for riscv64 on PRs (with the full set only on release)? Skipping tests on riscv64 in PRs? Open to ideas, but the final "yes" on this isn't mine to give.
Blocker: RISE GitHub App and timing with the org migration
The ubuntu-24.04-riscv runner label is only available after installing the RISE GitHub App on a repo or org. Installation requires admin permissions - as a collaborator I can't do this myself.
There's also a timing wrinkle: in #1015 we're planning to migrate msgspec into a dedicated organization. If we install RISE on jcrist/msgspec now, we'll have to reinstall it on the new org after the transfer. Cleaner: finish the org migration first, install RISE on the new org, then merge this PR. That's probably one to two weeks out.
None of this reflects on the quality of your work - it's purely coordination. I'll ping you as soon as the org is ready and RISE is installed.
Smaller things
-
cibuildwheel version is duplicated - currently
pypa/cibuildwheel@v3.2.1(the action) andpip install cibuildwheel==3.2.1(the riscv64 step). When we bump the version, both places need to be remembered. Could be lifted into an env var / matrix value, or stick to just one of the two strategies rather than both. -
/opt/python-3.12/bin/hardcoded path - this assumes a specific RISE image layout. If RISE updates the image to 3.13, this breaks silently. At minimum, a comment with the date / image version it was tested against. Better, look uppython3viacommand -v python3or similar. -
.github/workflows/benchmark-riscv64.yml- is this benchmark workflow meant to land in main, or be removed before merge? From the description ("for upstream discussion") it looks one-off, but it would be good to confirm explicitly.
Summing up
Two independent blockers:
-
Technical (on you): fix the
.cibuildwheel.tomlloading and re-run the benchmark to get real numbers with tests. Without that we'd be publishing untested wheels, and the timings we're discussing here are incomplete. -
Coordination (on me and the senior maintainers):
- Sign-off on this CI wall-time increase from @jcrist (see the section above) - this isn't a call I can make on my own.
- Installing the RISE GitHub App after the org migration (Migrate msgspec to a dedicated GitHub organization #1015) - also not my button to push.
Thanks again for the fast iteration and the right direction. I don't want this to read as a "no" - the PR is going the right way; it's just that decisions of this scale need time and input from people who've been around the project longer than I have.
cc @jcrist - I'd really like your read on growing wall-time CI from ~6 minutes to ~30-45 minutes on the longest path in exchange for riscv64 wheels. If you're OK with it, we move forward after the config fix and the org migration. If you'd like to trim it, let's discuss strategies (e.g. building only a limited set of Python versions for riscv64 on PRs).
- 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 <gounthar@gmail.com>
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 <gounthar@gmail.com>
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 <gounthar@gmail.com>
Summary
Add
linux_riscv64wheels to the build matrix.Changes
ubuntu-latest) tobuild-wheels.ymlEvidence
Context
manylinux_2_28_riscv64is available in pypa/manylinuxRef: #986
Note: this work is part of the RISE Project effort to improve Python ecosystem support on riscv64 platforms. Native riscv64 CI runners are available for free via RISE RISC-V runners.