Skip to content
Open
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
210 changes: 210 additions & 0 deletions .github/workflows/build-stpyv8.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
# SPDX-FileCopyrightText: 2026 The RISE Project
# SPDX-License-Identifier: MIT
---
# This workflow is based on: https://github.com/cloudflare/stpyv8/blob/v13.1.201.22/.github/workflows/linux.yml
name: Build stpyv8 wheels (riscv64)

on:
workflow_dispatch:
inputs:
version:
description: 'Version glob to (re)build; empty builds every version of docs/packages/stpyv8.yaml not released yet'
required: false
default: ''
pull_request:
branches: [main]
paths:
- '.github/workflows/build-stpyv8.yml'
- 'docs/packages/stpyv8.yaml'
- 'patches/stpyv8/**'
push:
branches: [main]
paths:
- '.github/workflows/build-stpyv8.yml'
- 'docs/packages/stpyv8.yaml'
- 'patches/stpyv8/**'

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

permissions:
contents: read

jobs:
setup:
uses: $/.github/workflows/_setup.yml
with:
package: stpyv8
version: ${{ inputs.version }}

build_v8:
name: Build v8 for stpyv8 ${{ matrix.version }} riscv64
needs: [setup]
if: needs.setup.outputs.versions != '[]'
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
env:
STPYV8_VERSION: ${{ matrix.version }}
V8_DEPS_LINUX: '0'
# depot_tools downloads every gclient gcs dep through gsutil under vpython, whose venv pins a crcmod wheel chromium does not build for riscv64; the bypass runs those scripts on the container python instead.
VPYTHON_BYPASS: manually managed python not supported by chrome operations
runs-on: ubuntu-24.04-riscv
timeout-minutes: 2880 # 48h: a monolithic v8 build from scratch, the scale build-nodejs-wheel-binaries.yml measured at ~23h
container:
image: quay.io/pypa/manylinux_2_39_riscv64

steps:
- name: Checkout stpyv8 v${{ env.STPYV8_VERSION }}
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: cloudflare/stpyv8
ref: v${{ env.STPYV8_VERSION }}
persist-credentials: false

- name: Checkout python-wheels
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: python-wheels
persist-credentials: false

- name: Patch stpyv8 source
run: git apply python-wheels/patches/stpyv8/${{ env.STPYV8_VERSION }}/*.patch

- name: Restore v8
id: v8-cache
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: |
v8/include
v8/out.gn/x64.release.sample/obj/libv8_monolith.a
v8/out.gn/x64.release.sample/icudtl.dat
# Upstream keys this on hashFiles('v8/src/**'); that tree only exists once the build has run, so key on what pins it instead -- the version and the patches.
key: stpyv8-v8-${{ env.STPYV8_VERSION }}-riscv64-${{ hashFiles('python-wheels/patches/stpyv8/**') }}

- name: Provide a riscv64-linux-gnu- prefixed toolchain
if: steps.v8-cache.outputs.cache-hit != 'true'
run: |
mkdir -p "${RUNNER_TEMP}/riscv64-toolchain/bin"
for tool in gcc g++ ar as ld nm objcopy objdump ranlib readelf strip; do
real=$(command -v "${tool}" || true)
[ -n "${real}" ] && ln -sf "${real}" "${RUNNER_TEMP}/riscv64-toolchain/bin/riscv64-linux-gnu-${tool}"
done
echo "${RUNNER_TEMP}/riscv64-toolchain/bin" >> "${GITHUB_PATH}"

- name: Clone depot_tools
if: steps.v8-cache.outputs.cache-hit != 'true'
# setup.py bootstraps depot_tools' hermetic python only for a checkout that already exists, and `fetch` refuses to run without it.
run: |
git clone --depth 1 https://chromium.googlesource.com/chromium/tools/depot_tools.git depot_tools
# An absolute path: depot_tools' cipd bootstrap resolves its own directory from $0 and cannot find its digests file when invoked through a relative one.
"${PWD}/depot_tools/gclient" --version

- name: Build v8
if: steps.v8-cache.outputs.cache-hit != 'true'
run: |
/opt/python/cp312-cp312/bin/pip install setuptools wheel
/opt/python/cp312-cp312/bin/python setup.py v8

- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: stpyv8-${{ env.STPYV8_VERSION }}-v8-riscv64
path: |
v8/include
v8/out.gn/x64.release.sample/obj/libv8_monolith.a
v8/out.gn/x64.release.sample/icudtl.dat
if-no-files-found: error

build_wheel:
name: Build stpyv8 ${{ matrix.version }} ${{ matrix.python }}-manylinux_riscv64
needs: [setup, build_v8]
if: needs.setup.outputs.versions != '[]'
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
# Boost.Python links the version-specific CPython ABI and has no free-threaded build.
python: ["cp312", "cp313", "cp314"]
env:
STPYV8_VERSION: ${{ matrix.version }}
# Newer than upstream's 1.87.0, which predates CPython 3.14.
BOOST_VERSION: 1.90.0
PYBIN: /opt/python/${{ matrix.python }}-${{ matrix.python }}/bin
runs-on: ubuntu-24.04-riscv
timeout-minutes: 720
container:
image: quay.io/pypa/manylinux_2_39_riscv64

steps:
- name: Checkout stpyv8 v${{ env.STPYV8_VERSION }}
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: cloudflare/stpyv8
ref: v${{ env.STPYV8_VERSION }}
persist-credentials: false

- name: Checkout python-wheels
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: python-wheels
persist-credentials: false

- name: Patch stpyv8 source
run: git apply python-wheels/patches/stpyv8/${{ env.STPYV8_VERSION }}/*.patch

- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: stpyv8-${{ env.STPYV8_VERSION }}-v8-riscv64
path: v8

- name: Install Boost
run: |
archive="boost_$(echo "${BOOST_VERSION}" | tr . _)"
curl -fsSL -o boost.tar.gz "https://archives.boost.io/release/${BOOST_VERSION}/source/${archive}.tar.gz"
tar xf boost.tar.gz
cd "${archive}"
./bootstrap.sh --with-python="${PYBIN}/python"
./b2 install -j"$(nproc)" --with-system --with-python --with-filesystem --with-iostreams --with-date_time --with-thread
ldconfig /usr/local/lib

- name: Build wheel
run: |
"${PYBIN}/pip" install setuptools wheel
"${PYBIN}/python" setup.py bdist_wheel --skip-build-v8 -d wheelhouse

- name: Repair wheel
run: LD_LIBRARY_PATH=/usr/local/lib auditwheel repair --plat manylinux_2_39_riscv64 -w dist wheelhouse/*.whl

- name: Test wheel
# Staged elsewhere: at the repository root the checkout's own STPyV8.py shadows the installed one.
run: |
"${PYBIN}/pip" install dist/*.whl pytest pytest-order
mkdir -p "${RUNNER_TEMP}/tests"
cp -r tests pytest.ini "${RUNNER_TEMP}/tests"
cd "${RUNNER_TEMP}/tests"
"${PYBIN}/python" -m pytest -v

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

publish:
name: Publish stpyv8 ${{ matrix.version }}
needs: [setup, build_wheel]
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: stpyv8-${{ matrix.version }}-*-manylinux_riscv64
5 changes: 5 additions & 0 deletions docs/packages/stpyv8.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package-name: stpyv8
source-code: https://github.com/cloudflare/stpyv8
license: Apache-2.0
versions:
- version: 13.1.201.22
Loading
Loading