From deb351377aa26cf49277c64c0defccd503f920bd Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Tue, 25 Aug 2026 16:13:46 +0200 Subject: [PATCH 1/4] sglang: add build-sglang.yml for riscv64 wheels sglang bundles three PyO3 extension modules (_server, _grpc, _multimodal) built from its rust/ cargo workspace, so its PyPI wheels are per-interpreter platform wheels with no riscv64 build. Mirrors upstream's .github/workflows/release-pypi.yml: build on the runner with `python -m build --wheel` from python/, then auditwheel repair. riscv64 deltas are setup-uv instead of setup-python, protoc from apt (upstream's install_protoc.sh only knows x86_64/aarch64 release zips), and an explicit rustup toolchain matching rust/rust-toolchain.toml. The ~300 runtime dependencies (torch, transformers, the CUDA stack) are not installable on riscv64, so the wheel is smoke-tested by loading each compiled extension module directly instead of importing the package. --- .github/workflows/build-sglang.yml | 133 +++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 .github/workflows/build-sglang.yml diff --git a/.github/workflows/build-sglang.yml b/.github/workflows/build-sglang.yml new file mode 100644 index 000000000..6e43695e9 --- /dev/null +++ b/.github/workflows/build-sglang.yml @@ -0,0 +1,133 @@ +# SPDX-FileCopyrightText: 2026 The RISE Project +# SPDX-License-Identifier: MIT + +name: Build sglang wheels (riscv64) + +on: + workflow_dispatch: + inputs: + version: + description: 'sglang version to build (git tag without leading v, e.g. 0.5.18)' + required: true + default: '0.5.18' + pull_request: + paths: + - '.github/workflows/build-sglang.yml' + +concurrency: + group: ${{ github.workflow }}-${{ inputs.version || '0.5.18' }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read + +env: + SGLANG_VERSION: ${{ inputs.version || '0.5.18' }} + +jobs: + build_wheels: + name: Build sglang ${{ inputs.version || '0.5.18' }} ${{ matrix.python-version }}-riscv64 + runs-on: ubuntu-24.04-riscv + timeout-minutes: 720 + strategy: + fail-fast: false + matrix: + python-version: ['3.12', '3.13', '3.14', '3.14t'] + + steps: + - name: Checkout sglang v${{ env.SGLANG_VERSION }} + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + repository: sgl-project/sglang + ref: v${{ env.SGLANG_VERSION }} + persist-credentials: false + + - name: Install Python + uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 + with: + python-version: ${{ matrix.python-version }} + activate-environment: true + enable-cache: false + + # Upstream's scripts/ci/utils/install_protoc.sh only knows x86_64/aarch64 + # release zips; patchelf is what auditwheel shells out to. + - name: Install protoc and patchelf + run: | + sudo apt-get update -qq + sudo apt-get install -qq -y --no-install-recommends protobuf-compiler patchelf + + # rust/rust-toolchain.toml pins 1.92, but cargo is invoked from python/ so + # rustup never reads it. + - uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # master + with: + toolchain: '1.92' + + - name: Install build tooling + run: uv pip install --upgrade pip build auditwheel + + - name: Build wheel + env: + SETUPTOOLS_SCM_PRETEND_VERSION: ${{ env.SGLANG_VERSION }} + run: | + cd python + cp ../README.md ../LICENSE . + python -m build --wheel + + - name: Repair wheel for manylinux + run: | + cd python + mkdir -p dist-repaired + python -m auditwheel repair dist/*.whl -w dist-repaired/ + rm dist/*.whl + mv dist-repaired/*.whl dist/ + + # sglang's ~300 runtime dependencies (torch, transformers, the CUDA stack) + # are not installable on riscv64, so `import sglang` is out of reach: load + # each compiled PyO3 module straight off disk instead. + - name: Smoke-test the extension modules + env: + PIP_EXTRA_INDEX_URL: https://pypi.riseproject.dev/simple/ + run: | + cd python + uv pip install numpy + unzip -q -o dist/*.whl -d unpacked + python - <<'EOF' + import importlib.machinery + import importlib.util + import pathlib + + modules = sorted(pathlib.Path("unpacked/sglang/srt/rust_extensions").glob("_*.so")) + names = {path.name.split(".")[0] for path in modules} + assert names == {"_grpc", "_multimodal", "_server"}, names + for path in modules: + name = path.name.split(".")[0] + loader = importlib.machinery.ExtensionFileLoader(name, str(path)) + spec = importlib.util.spec_from_loader(name, loader) + module = importlib.util.module_from_spec(spec) + loader.exec_module(module) + print(name, sorted(a for a in dir(module) if not a.startswith("_"))) + EOF + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: sglang-${{ env.SGLANG_VERSION }}-${{ matrix.python-version }}-riscv64 + path: python/dist/*.whl + if-no-files-found: error + + publish: + name: Publish sglang ${{ inputs.version || '0.5.18' }} to GitLab + needs: [build_wheels] + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + + steps: + - name: Publish wheels and open docs PR + uses: riseproject-dev/python-wheels/actions/publish-wheels@main + with: + artifact-pattern: sglang-${{ env.SGLANG_VERSION }}-*-riscv64 + gitlab-username: ${{ vars.GITLAB_DEPLOY_USER }} + gitlab-token: ${{ secrets.GITLAB_DEPLOY_TOKEN }} + gitlab-project-id: ${{ vars.GITLAB_PROJECT_ID }} + gh-token: ${{ secrets.GITHUB_TOKEN }} From e3a0e1a7f9832b13757146fda7ab33fa1581ac5c Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Tue, 25 Aug 2026 16:15:51 +0200 Subject: [PATCH 2/4] sglang: resolve the smoke-test numpy from our registry uv ignores PIP_EXTRA_INDEX_URL, so numpy would have resolved off public PyPI where no riscv64 wheel exists. Also unpack with stdlib zipfile rather than assuming unzip on the runner, and upload the wheel before the smoke test so a failing import still leaves an artifact to triage. --- .github/workflows/build-sglang.yml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build-sglang.yml b/.github/workflows/build-sglang.yml index 6e43695e9..39de2a957 100644 --- a/.github/workflows/build-sglang.yml +++ b/.github/workflows/build-sglang.yml @@ -81,16 +81,24 @@ jobs: rm dist/*.whl mv dist-repaired/*.whl dist/ + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: sglang-${{ env.SGLANG_VERSION }}-${{ matrix.python-version }}-riscv64 + path: python/dist/*.whl + if-no-files-found: error + # sglang's ~300 runtime dependencies (torch, transformers, the CUDA stack) # are not installable on riscv64, so `import sglang` is out of reach: load # each compiled PyO3 module straight off disk instead. - name: Smoke-test the extension modules env: - PIP_EXTRA_INDEX_URL: https://pypi.riseproject.dev/simple/ + UV_EXTRA_INDEX_URL: https://pypi.riseproject.dev/simple/ + UV_INDEX_STRATEGY: unsafe-best-match + UV_ONLY_BINARY: ':all:' run: | cd python uv pip install numpy - unzip -q -o dist/*.whl -d unpacked + python -m zipfile -e dist/*.whl unpacked/ python - <<'EOF' import importlib.machinery import importlib.util @@ -108,12 +116,6 @@ jobs: print(name, sorted(a for a in dir(module) if not a.startswith("_"))) EOF - - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - name: sglang-${{ env.SGLANG_VERSION }}-${{ matrix.python-version }}-riscv64 - path: python/dist/*.whl - if-no-files-found: error - publish: name: Publish sglang ${{ inputs.version || '0.5.18' }} to GitLab needs: [build_wheels] From ebb14f1a67954b83998ab0f87b5c3be88c8ea00d Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Tue, 25 Aug 2026 21:04:03 +0200 Subject: [PATCH 3/4] sglang: drop pull_request trigger, build via Trigger: directive --- .github/workflows/build-sglang.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/build-sglang.yml b/.github/workflows/build-sglang.yml index 39de2a957..5922d24bb 100644 --- a/.github/workflows/build-sglang.yml +++ b/.github/workflows/build-sglang.yml @@ -10,9 +10,6 @@ on: description: 'sglang version to build (git tag without leading v, e.g. 0.5.18)' required: true default: '0.5.18' - pull_request: - paths: - - '.github/workflows/build-sglang.yml' concurrency: group: ${{ github.workflow }}-${{ inputs.version || '0.5.18' }}-${{ github.head_ref || github.run_id }} From 41c6596568ecb0c9df4cdf51d2e218b2ad7e7c0f Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Wed, 26 Aug 2026 02:09:31 +0200 Subject: [PATCH 4/4] sglang: restore the pull_request trigger MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous commit dropped it to follow "workflows: rework triggering behaviour" (#364), which has since been reverted by #391 — every workflow on main declares both triggers again, and a workflow that has never run cannot be reached by workflow_dispatch or by a Trigger: line at all. Also aligns the header with the sibling workflows: the YAML document marker and the upstream-workflow reference this one is derived from. --- .github/workflows/build-sglang.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-sglang.yml b/.github/workflows/build-sglang.yml index 5922d24bb..919e09347 100644 --- a/.github/workflows/build-sglang.yml +++ b/.github/workflows/build-sglang.yml @@ -1,6 +1,7 @@ # SPDX-FileCopyrightText: 2026 The RISE Project # SPDX-License-Identifier: MIT - +--- +# This workflow is based on: https://github.com/sgl-project/sglang/blob/v0.5.18/.github/workflows/release-pypi.yml name: Build sglang wheels (riscv64) on: @@ -10,13 +11,16 @@ on: description: 'sglang version to build (git tag without leading v, e.g. 0.5.18)' required: true default: '0.5.18' + pull_request: + paths: + - '.github/workflows/build-sglang.yml' concurrency: group: ${{ github.workflow }}-${{ inputs.version || '0.5.18' }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true permissions: - contents: read + contents: read # to fetch code (actions/checkout) env: SGLANG_VERSION: ${{ inputs.version || '0.5.18' }}