From b399c495a32fc1fde15d96224db4ced7ce218af7 Mon Sep 17 00:00:00 2001 From: Bruno Verachten Date: Sat, 7 Mar 2026 20:04:29 +0100 Subject: [PATCH 01/11] ci: add riscv64 wheel build workflow (#1) --- .github/workflows/build-riscv64.yml | 111 ++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 .github/workflows/build-riscv64.yml diff --git a/.github/workflows/build-riscv64.yml b/.github/workflows/build-riscv64.yml new file mode 100644 index 00000000..db2d4edc --- /dev/null +++ b/.github/workflows/build-riscv64.yml @@ -0,0 +1,111 @@ +name: Build riscv64 wheel + +on: + workflow_dispatch: + inputs: + release_tag: + description: 'Upstream release tag to build from' + required: false + type: string + schedule: + - cron: '0 2 * * 0' + +jobs: + build: + runs-on: [self-hosted, linux, riscv64] + timeout-minutes: 120 + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ inputs.release_tag || github.ref }} + fetch-depth: 0 + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y libffi-dev + + - name: Set up Python + run: | + python3 -m venv /tmp/build-venv + . /tmp/build-venv/bin/activate + pip install --upgrade pip setuptools wheel + + - name: Build wheel + run: | + . /tmp/build-venv/bin/activate + pip wheel --no-deps --wheel-dir /tmp/wheels/ . + + - name: Verify platform tag + run: | + ls /tmp/wheels/*.whl + for whl in /tmp/wheels/*.whl; do + if echo "$whl" | grep -q "linux_riscv64\|manylinux.*riscv64"; then + echo "OK: $whl" + else + echo "FAIL: $whl does not have riscv64 platform tag" + exit 1 + fi + done + + - name: Upload wheel artifact + uses: actions/upload-artifact@v4 + with: + name: wheel-riscv64 + path: /tmp/wheels/*.whl + retention-days: 90 + + - name: Cleanup + if: always() + run: rm -rf /tmp/build-venv /tmp/wheels + + release: + needs: build + runs-on: [self-hosted, linux, riscv64] + if: success() + steps: + - name: Download wheel artifact + uses: actions/download-artifact@v4 + with: + name: wheel-riscv64 + path: /tmp/wheels/ + + - name: Get wheel info + id: wheel_info + run: | + WHL=$(ls /tmp/wheels/*.whl | head -1) + BASENAME=$(basename "$WHL") + VERSION=$(echo "$BASENAME" | sed 's/^[^-]*-\([^-]*\)-.*/\1/') + echo "whl_path=$WHL" >> "$GITHUB_OUTPUT" + echo "whl_name=$BASENAME" >> "$GITHUB_OUTPUT" + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + + - name: Generate checksums + run: | + cd /tmp/wheels + sha256sum *.whl > SHA256SUMS + + - name: Create or update release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + TAG="riscv64-v${{ steps.wheel_info.outputs.version }}" + TITLE="riscv64 wheel v${{ steps.wheel_info.outputs.version }}" + gh release delete "$TAG" --yes 2>/dev/null || true + git tag -d "$TAG" 2>/dev/null || true + git push origin ":refs/tags/$TAG" 2>/dev/null || true + gh release create "$TAG" --title "$TITLE" --notes "Prebuilt riscv64 wheel for $(uname -m) Linux. + + Built on: BananaPi F3 (SpacemiT K1, rv64imafdcv) + Python: $(python3 --version 2>&1) + Wheel: ${{ steps.wheel_info.outputs.whl_name }} + + Install: + \`\`\` + pip install cffi --find-links https://github.com/gounthar/$(basename $PWD)/releases/download/$TAG/ + \`\`\`" /tmp/wheels/*.whl /tmp/wheels/SHA256SUMS + + - name: Cleanup + if: always() + run: rm -rf /tmp/wheels From ce20e1c3511f841312f82c9d1da532d209ff7f69 Mon Sep 17 00:00:00 2001 From: Bruno Verachten Date: Sat, 7 Mar 2026 22:16:12 +0100 Subject: [PATCH 02/11] ci: add index update callback after release (#2) --- .github/workflows/build-riscv64.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.github/workflows/build-riscv64.yml b/.github/workflows/build-riscv64.yml index db2d4edc..67747fcd 100644 --- a/.github/workflows/build-riscv64.yml +++ b/.github/workflows/build-riscv64.yml @@ -109,3 +109,17 @@ jobs: - name: Cleanup if: always() run: rm -rf /tmp/wheels + notify-index: + needs: release + runs-on: ubuntu-latest + if: success() + steps: + - name: Trigger index update + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh api repos/gounthar/riscv64-python-wheels/dispatches \ + -f event_type=fork-release-published \ + -f "client_payload[repo]=${{ github.repository }}" \ + -f "client_payload[tag]=${{ github.ref_name }}" || true + From 35fc11fe2d36d0efc17d17112553902a5eab5dc8 Mon Sep 17 00:00:00 2001 From: Bruno Verachten Date: Sat, 7 Mar 2026 22:29:11 +0100 Subject: [PATCH 03/11] fix: add checkout to release job and use DISPATCH_TOKEN --- .github/workflows/build-riscv64.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-riscv64.yml b/.github/workflows/build-riscv64.yml index 67747fcd..ea851ed1 100644 --- a/.github/workflows/build-riscv64.yml +++ b/.github/workflows/build-riscv64.yml @@ -65,6 +65,9 @@ jobs: runs-on: [self-hosted, linux, riscv64] if: success() steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Download wheel artifact uses: actions/download-artifact@v4 with: @@ -116,10 +119,9 @@ jobs: steps: - name: Trigger index update env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_TOKEN: ${{ secrets.DISPATCH_TOKEN }} run: | gh api repos/gounthar/riscv64-python-wheels/dispatches \ -f event_type=fork-release-published \ -f "client_payload[repo]=${{ github.repository }}" \ - -f "client_payload[tag]=${{ github.ref_name }}" || true - + -f "client_payload[tag]=${{ github.ref_name }}" From ac1538b95ddd6c1bd0ab8e3407d1a27b422ba1df Mon Sep 17 00:00:00 2001 From: Bruno Verachten Date: Sat, 7 Mar 2026 22:37:48 +0100 Subject: [PATCH 04/11] fix: set GH_REPO for gh release commands in release job --- .github/workflows/build-riscv64.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build-riscv64.yml b/.github/workflows/build-riscv64.yml index ea851ed1..23c4d6ed 100644 --- a/.github/workflows/build-riscv64.yml +++ b/.github/workflows/build-riscv64.yml @@ -64,6 +64,8 @@ jobs: needs: build runs-on: [self-hosted, linux, riscv64] if: success() + env: + GH_REPO: ${{ github.repository }} steps: - name: Checkout uses: actions/checkout@v4 From cdace9d10d340dc129af696f4dbaa5fa47b89e31 Mon Sep 17 00:00:00 2001 From: Bruno Verachten Date: Sun, 29 Mar 2026 11:51:50 +0200 Subject: [PATCH 05/11] ci: switch riscv64 build from F3 self-hosted to RISE runners --- .github/workflows/build-riscv64.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-riscv64.yml b/.github/workflows/build-riscv64.yml index 23c4d6ed..8bc46617 100644 --- a/.github/workflows/build-riscv64.yml +++ b/.github/workflows/build-riscv64.yml @@ -12,7 +12,7 @@ on: jobs: build: - runs-on: [self-hosted, linux, riscv64] + runs-on: ubuntu-24.04-riscv timeout-minutes: 120 steps: - name: Checkout @@ -28,6 +28,7 @@ jobs: - name: Set up Python run: | + export PATH="$(ls -d /opt/python-3.1*/bin 2>/dev/null | sort -V | tail -1):$PATH" python3 -m venv /tmp/build-venv . /tmp/build-venv/bin/activate pip install --upgrade pip setuptools wheel @@ -62,7 +63,7 @@ jobs: release: needs: build - runs-on: [self-hosted, linux, riscv64] + runs-on: ubuntu-24.04-riscv if: success() env: GH_REPO: ${{ github.repository }} From c67cb22d8a826a7b3c7ccac6d73671426e9e9262 Mon Sep 17 00:00:00 2001 From: Bruno Verachten Date: Sun, 29 Mar 2026 11:54:08 +0200 Subject: [PATCH 06/11] fix: bootstrap pip in venv (ensurepip not available on RISE runners) --- .github/workflows/build-riscv64.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-riscv64.yml b/.github/workflows/build-riscv64.yml index 8bc46617..439732c4 100644 --- a/.github/workflows/build-riscv64.yml +++ b/.github/workflows/build-riscv64.yml @@ -29,8 +29,9 @@ jobs: - name: Set up Python run: | export PATH="$(ls -d /opt/python-3.1*/bin 2>/dev/null | sort -V | tail -1):$PATH" - python3 -m venv /tmp/build-venv + python3 -m venv --without-pip /tmp/build-venv . /tmp/build-venv/bin/activate + curl -sS https://bootstrap.pypa.io/get-pip.py | python3 pip install --upgrade pip setuptools wheel - name: Build wheel From f3ceff247df6fd38681d0812b7ba3b7d0f69a572 Mon Sep 17 00:00:00 2001 From: Bruno Verachten Date: Sun, 29 Mar 2026 11:56:07 +0200 Subject: [PATCH 07/11] fix: use system python3 with apt-installed venv instead of /opt/python --- .github/workflows/build-riscv64.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-riscv64.yml b/.github/workflows/build-riscv64.yml index 439732c4..c5913485 100644 --- a/.github/workflows/build-riscv64.yml +++ b/.github/workflows/build-riscv64.yml @@ -28,10 +28,9 @@ jobs: - name: Set up Python run: | - export PATH="$(ls -d /opt/python-3.1*/bin 2>/dev/null | sort -V | tail -1):$PATH" - python3 -m venv --without-pip /tmp/build-venv + sudo apt-get install -y python3-venv python3-pip + python3 -m venv /tmp/build-venv . /tmp/build-venv/bin/activate - curl -sS https://bootstrap.pypa.io/get-pip.py | python3 pip install --upgrade pip setuptools wheel - name: Build wheel From 19a9da767bf53e8dede3424465c8390036d3aaa3 Mon Sep 17 00:00:00 2001 From: Bruno Verachten Date: Sun, 29 Mar 2026 12:00:21 +0200 Subject: [PATCH 08/11] fix: use --without-pip venv + get-pip.py (ensurepip broken on RISE runner) --- .github/workflows/build-riscv64.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-riscv64.yml b/.github/workflows/build-riscv64.yml index c5913485..cc1525ec 100644 --- a/.github/workflows/build-riscv64.yml +++ b/.github/workflows/build-riscv64.yml @@ -28,10 +28,11 @@ jobs: - name: Set up Python run: | - sudo apt-get install -y python3-venv python3-pip - python3 -m venv /tmp/build-venv + sudo apt-get install -y python3-venv python3-pip python3-dev + python3 -m venv --without-pip /tmp/build-venv . /tmp/build-venv/bin/activate - pip install --upgrade pip setuptools wheel + curl -sS https://bootstrap.pypa.io/get-pip.py | python3 + pip install --upgrade setuptools wheel - name: Build wheel run: | From db8dfacbb9dc6caf172b55790b7ba7f387ba6a95 Mon Sep 17 00:00:00 2001 From: Bruno Verachten Date: Sun, 29 Mar 2026 12:02:59 +0200 Subject: [PATCH 09/11] fix: strip broken /opt/python from PATH, use /usr/bin/python3 explicitly --- .github/workflows/build-riscv64.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-riscv64.yml b/.github/workflows/build-riscv64.yml index cc1525ec..ef66edb8 100644 --- a/.github/workflows/build-riscv64.yml +++ b/.github/workflows/build-riscv64.yml @@ -28,10 +28,12 @@ jobs: - name: Set up Python run: | + # Remove broken /opt/python from PATH + export PATH=$(echo "$PATH" | tr ':' '\n' | grep -v /opt/python | tr '\n' ':' | sed 's/:$//') sudo apt-get install -y python3-venv python3-pip python3-dev - python3 -m venv --without-pip /tmp/build-venv + /usr/bin/python3 -m venv --without-pip /tmp/build-venv . /tmp/build-venv/bin/activate - curl -sS https://bootstrap.pypa.io/get-pip.py | python3 + curl -sS https://bootstrap.pypa.io/get-pip.py | /usr/bin/python3 pip install --upgrade setuptools wheel - name: Build wheel From abeffd5d0d842738443b90e6e9b159ea5b4671f5 Mon Sep 17 00:00:00 2001 From: Bruno Verachten Date: Sun, 29 Mar 2026 17:32:00 +0200 Subject: [PATCH 10/11] ci: switch fork build to uvx pattern --- .github/workflows/build-riscv64.yml | 92 +---------------------------- 1 file changed, 3 insertions(+), 89 deletions(-) diff --git a/.github/workflows/build-riscv64.yml b/.github/workflows/build-riscv64.yml index ef66edb8..1ed25814 100644 --- a/.github/workflows/build-riscv64.yml +++ b/.github/workflows/build-riscv64.yml @@ -2,11 +2,6 @@ name: Build riscv64 wheel on: workflow_dispatch: - inputs: - release_tag: - description: 'Upstream release tag to build from' - required: false - type: string schedule: - cron: '0 2 * * 0' @@ -18,7 +13,6 @@ jobs: - name: Checkout uses: actions/checkout@v4 with: - ref: ${{ inputs.release_tag || github.ref }} fetch-depth: 0 - name: Install system dependencies @@ -26,20 +20,12 @@ jobs: sudo apt-get update sudo apt-get install -y libffi-dev - - name: Set up Python - run: | - # Remove broken /opt/python from PATH - export PATH=$(echo "$PATH" | tr ':' '\n' | grep -v /opt/python | tr '\n' ':' | sed 's/:$//') - sudo apt-get install -y python3-venv python3-pip python3-dev - /usr/bin/python3 -m venv --without-pip /tmp/build-venv - . /tmp/build-venv/bin/activate - curl -sS https://bootstrap.pypa.io/get-pip.py | /usr/bin/python3 - pip install --upgrade setuptools wheel + - name: Set up uv + uses: astral-sh/setup-uv@v7 - name: Build wheel run: | - . /tmp/build-venv/bin/activate - pip wheel --no-deps --wheel-dir /tmp/wheels/ . + uvx --python 3.14 pip wheel --no-deps --wheel-dir /tmp/wheels/ . - name: Verify platform tag run: | @@ -59,75 +45,3 @@ jobs: name: wheel-riscv64 path: /tmp/wheels/*.whl retention-days: 90 - - - name: Cleanup - if: always() - run: rm -rf /tmp/build-venv /tmp/wheels - - release: - needs: build - runs-on: ubuntu-24.04-riscv - if: success() - env: - GH_REPO: ${{ github.repository }} - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Download wheel artifact - uses: actions/download-artifact@v4 - with: - name: wheel-riscv64 - path: /tmp/wheels/ - - - name: Get wheel info - id: wheel_info - run: | - WHL=$(ls /tmp/wheels/*.whl | head -1) - BASENAME=$(basename "$WHL") - VERSION=$(echo "$BASENAME" | sed 's/^[^-]*-\([^-]*\)-.*/\1/') - echo "whl_path=$WHL" >> "$GITHUB_OUTPUT" - echo "whl_name=$BASENAME" >> "$GITHUB_OUTPUT" - echo "version=$VERSION" >> "$GITHUB_OUTPUT" - - - name: Generate checksums - run: | - cd /tmp/wheels - sha256sum *.whl > SHA256SUMS - - - name: Create or update release - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - TAG="riscv64-v${{ steps.wheel_info.outputs.version }}" - TITLE="riscv64 wheel v${{ steps.wheel_info.outputs.version }}" - gh release delete "$TAG" --yes 2>/dev/null || true - git tag -d "$TAG" 2>/dev/null || true - git push origin ":refs/tags/$TAG" 2>/dev/null || true - gh release create "$TAG" --title "$TITLE" --notes "Prebuilt riscv64 wheel for $(uname -m) Linux. - - Built on: BananaPi F3 (SpacemiT K1, rv64imafdcv) - Python: $(python3 --version 2>&1) - Wheel: ${{ steps.wheel_info.outputs.whl_name }} - - Install: - \`\`\` - pip install cffi --find-links https://github.com/gounthar/$(basename $PWD)/releases/download/$TAG/ - \`\`\`" /tmp/wheels/*.whl /tmp/wheels/SHA256SUMS - - - name: Cleanup - if: always() - run: rm -rf /tmp/wheels - notify-index: - needs: release - runs-on: ubuntu-latest - if: success() - steps: - - name: Trigger index update - env: - GH_TOKEN: ${{ secrets.DISPATCH_TOKEN }} - run: | - gh api repos/gounthar/riscv64-python-wheels/dispatches \ - -f event_type=fork-release-published \ - -f "client_payload[repo]=${{ github.repository }}" \ - -f "client_payload[tag]=${{ github.ref_name }}" From 84162b79e91d3178ba78a865f870738d48122dc8 Mon Sep 17 00:00:00 2001 From: Bruno Verachten Date: Mon, 30 Mar 2026 14:19:39 +0200 Subject: [PATCH 11/11] ci: add riscv64 manylinux wheels with native RISE runners Signed-off-by: Bruno Verachten --- .github/workflows/build-riscv64.yml | 47 ----------------------------- .github/workflows/ci.yaml | 28 ++++++++++++++--- 2 files changed, 23 insertions(+), 52 deletions(-) delete mode 100644 .github/workflows/build-riscv64.yml diff --git a/.github/workflows/build-riscv64.yml b/.github/workflows/build-riscv64.yml deleted file mode 100644 index 1ed25814..00000000 --- a/.github/workflows/build-riscv64.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: Build riscv64 wheel - -on: - workflow_dispatch: - schedule: - - cron: '0 2 * * 0' - -jobs: - build: - runs-on: ubuntu-24.04-riscv - timeout-minutes: 120 - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Install system dependencies - run: | - sudo apt-get update - sudo apt-get install -y libffi-dev - - - name: Set up uv - uses: astral-sh/setup-uv@v7 - - - name: Build wheel - run: | - uvx --python 3.14 pip wheel --no-deps --wheel-dir /tmp/wheels/ . - - - name: Verify platform tag - run: | - ls /tmp/wheels/*.whl - for whl in /tmp/wheels/*.whl; do - if echo "$whl" | grep -q "linux_riscv64\|manylinux.*riscv64"; then - echo "OK: $whl" - else - echo "FAIL: $whl does not have riscv64 platform tag" - exit 1 - fi - done - - - name: Upload wheel artifact - uses: actions/upload-artifact@v4 - with: - name: wheel-riscv64 - path: /tmp/wheels/*.whl - retention-days: 90 diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index c797fde4..dfd1cfa2 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -139,9 +139,18 @@ jobs: - { spec: cp314-manylinux_s390x, arch: s390x, omit: ${{ env.skip_slow_jobs }} } - { spec: cp314t-manylinux_s390x, arch: s390x, omit: ${{ env.skip_slow_jobs }} } + # riscv64 manylinux (native RISE runners) + - { spec: cp39-manylinux_riscv64, arch: riscv64 } + - { spec: cp310-manylinux_riscv64, arch: riscv64, omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp311-manylinux_riscv64, arch: riscv64, omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp312-manylinux_riscv64, arch: riscv64, omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp313-manylinux_riscv64, arch: riscv64, omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp314-manylinux_riscv64, arch: riscv64 } + - { spec: cp314t-manylinux_riscv64, arch: riscv64 } + linux: needs: [python_sdist, make_linux_matrix] - runs-on: ${{ (matrix.arch == 'aarch64') && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }} + runs-on: ${{ (matrix.arch == 'aarch64') && 'ubuntu-24.04-arm' || (matrix.arch == 'riscv64') && 'ubuntu-24.04-riscv' || 'ubuntu-24.04' }} strategy: fail-fast: false matrix: ${{ fromJSON(needs.make_linux_matrix.outputs.matrix_json) }} @@ -155,7 +164,11 @@ jobs: - name: configure docker foreign arch support uses: docker/setup-qemu-action@v3 - if: matrix.arch != 'x86_64' && matrix.arch != 'i686' && matrix.arch != 'aarch64' + if: matrix.arch != 'x86_64' && matrix.arch != 'i686' && matrix.arch != 'aarch64' && matrix.arch != 'riscv64' + + - name: Set up uv (riscv64) + if: matrix.arch == 'riscv64' + uses: astral-sh/setup-uv@v7 - name: build/test wheels id: build @@ -179,6 +192,7 @@ jobs: CIBW_MANYLINUX_AARCH64_IMAGE: ${{ matrix.manylinux_img || 'manylinux2014' }} CIBW_MANYLINUX_PPC64LE_IMAGE: ${{ matrix.manylinux_img || 'manylinux2014' }} CIBW_MANYLINUX_S390X_IMAGE: ${{ matrix.manylinux_img || 'manylinux2014' }} + CIBW_MANYLINUX_RISCV64_IMAGE: ${{ matrix.manylinux_img || 'manylinux_2_39' }} CIBW_MUSLLINUX_X86_64_IMAGE: ${{ matrix.musllinux_img || 'musllinux_1_2' }} CIBW_MUSLLINUX_I686_IMAGE: ${{ matrix.musllinux_img || 'musllinux_1_2' }} CIBW_MUSLLINUX_AARCH64_IMAGE: ${{ matrix.musllinux_img || 'musllinux_1_2' }} @@ -190,10 +204,14 @@ jobs: mkdir cffi tar zxf ${{ steps.fetch_sdist.outputs.download-path }}/cffi*.tar.gz --strip-components=1 -C cffi - python -m pip install --upgrade "${{ matrix.cibw_version || 'cibuildwheel' }}" - # actually build libffi + wheel (using env tweaks above) - python -m cibuildwheel --output-dir dist ./cffi + if [ "${{ matrix.arch }}" = "riscv64" ]; then + # Use uvx on riscv64 RISE runners (setup-python not available) + uvx --python 3.14 "${{ matrix.cibw_version || 'cibuildwheel' }}" --output-dir dist ./cffi + else + python -m pip install --upgrade "${{ matrix.cibw_version || 'cibuildwheel' }}" + python -m cibuildwheel --output-dir dist ./cffi + fi echo "artifact_name=$(ls ./dist/)" >> "$GITHUB_OUTPUT"