Skip to content

Commit 2ce6ac0

Browse files
authored
tilelang: add build-tilelang.yml for riscv64 wheels (#1730)
* **Package**: `tilelang` * **Version**: `0.1.13` * **Source**: https://github.com/tile-ai/tilelang * **Docs**: https://github.com/tile-ai/tilelang Compiles a vendored TVM fork plus a Cython wrapper into a CPU/LLVM-backed tile-programming DSL. Upstream publishes no riscv64 wheel. Mirrors upstream's own [`dist.yml`](https://github.com/tile-ai/tilelang/blob/v0.1.13/.github/workflows/dist.yml), adapted for the CPU/LLVM build mode it documents (`docs/get_started/Installation.md`) but never ships itself - upstream's own release wheels are always CUDA (Linux/Windows) or Metal (macOS). **Differs from upstream** - USE_CUDA=OFF, USE_ROCM=OFF, USE_LLVM=ON - upstream's own cibuildwheel config hardcodes USE_CUDA=ON/USE_ROCM=ON and installs a CUDA toolkit, unavailable on riscv64 - `dnf install llvm-devel` in before-all - USE_LLVM needs a host LLVM 15+, which upstream never needs since it always builds CUDA/Metal **Matrix**: single `cp312` build - `wheel.py-api` is `cp38` (one abi3 wheel covers every interpreter), and apache-tvm-ffi (a hard runtime dependency) ships no riscv64 wheel below cp312 **Testing** - same as upstream (`python -c "import tilelang; print(tilelang.__version__)"`) **License**: OK **Patches** - `0001-exclude-torch-c-dlpack-ext-from-the-riscv64-depende.patch` - Inappropriate. torch-c-dlpack-ext (optional, marker-gated) has no riscv64 wheel anywhere; upstream calls it a soft, JIT-fallback dependency. Reproduces on any arch lacking a wheel for it, not riscv64-only. Built on cp312; import succeeds, prints version.
1 parent aaa579b commit 2ce6ac0

3 files changed

Lines changed: 240 additions & 0 deletions

File tree

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
# SPDX-FileCopyrightText: 2026 The RISE Project
2+
# SPDX-License-Identifier: MIT
3+
---
4+
# This workflow is based on upstream's own wheel build/publish setup:
5+
# https://github.com/tile-ai/tilelang/blob/v0.1.13/.github/workflows/dist.yml
6+
name: Build tilelang wheels (riscv64)
7+
8+
on:
9+
workflow_dispatch:
10+
inputs:
11+
version:
12+
description: 'tilelang version to build (git tag without leading v, e.g. 0.1.13)'
13+
required: true
14+
default: '0.1.13'
15+
pull_request:
16+
paths:
17+
- '.github/workflows/build-tilelang.yml'
18+
19+
concurrency:
20+
group: ${{ github.workflow }}-${{ inputs.version || '0.1.13' }}-${{ github.head_ref || github.run_id }}
21+
cancel-in-progress: true
22+
23+
permissions:
24+
contents: read # to fetch code (actions/checkout)
25+
26+
env:
27+
TILELANG_VERSION: ${{ inputs.version || '0.1.13' }}
28+
MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64
29+
30+
jobs:
31+
setup:
32+
uses: $/.github/workflows/_setup.yml
33+
34+
build_sdist:
35+
needs: [setup]
36+
# The sdist just packages the source tree plus the vendored TVM/CUTLASS/
37+
# composable_kernel submodules (see pyproject's [tool.scikit-build.sdist]);
38+
# build it once on x86 instead of burning a scarce riscv runner (gotcha 4).
39+
name: Build tilelang ${{ inputs.version || '0.1.13' }} sdist
40+
runs-on: ubuntu-latest
41+
timeout-minutes: 30
42+
env:
43+
# Otherwise the sdist's version carries a dirty git-hash suffix that the
44+
# later wheel build (no .git in the extracted sdist) can never reproduce.
45+
NO_VERSION_LABEL: 'ON'
46+
outputs:
47+
sdist_name: ${{ steps.sdist.outputs.sdist_name }}
48+
steps:
49+
- name: Checkout tilelang v${{ env.TILELANG_VERSION }}
50+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
51+
with:
52+
repository: tile-ai/tilelang
53+
ref: v${{ env.TILELANG_VERSION }}
54+
submodules: recursive
55+
fetch-depth: 1
56+
persist-credentials: false
57+
58+
- name: Checkout python-wheels
59+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
60+
with:
61+
path: python-wheels
62+
persist-credentials: false
63+
64+
- name: Patch tilelang source
65+
run: |
66+
git apply python-wheels/patches/tilelang/${{ env.TILELANG_VERSION }}/00*.patch
67+
68+
- name: Setup Python and uv
69+
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
70+
with:
71+
python-version: '3.12'
72+
activate-environment: true
73+
enable-cache: false
74+
75+
- name: Build sdist
76+
id: sdist
77+
run: |
78+
uv run --no-project --with=build -m -- build --sdist --outdir=dist
79+
sdists=(dist/*.tar.gz)
80+
echo "sdist_name=$(basename "${sdists[0]}")" >> "$GITHUB_OUTPUT"
81+
82+
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
83+
with:
84+
name: tilelang-${{ env.TILELANG_VERSION }}-sdist
85+
path: dist/*.tar.gz
86+
if-no-files-found: error
87+
88+
build_wheels:
89+
needs: [setup, build_sdist]
90+
name: Build tilelang ${{ inputs.version || '0.1.13' }} ${{ matrix.python }}-manylinux_riscv64
91+
runs-on: ubuntu-24.04-riscv
92+
timeout-minutes: 600
93+
strategy:
94+
fail-fast: false
95+
matrix:
96+
# pyproject sets wheel.py-api = "cp38" (upstream ships a single
97+
# cp38-abi3 wheel, no free-threaded build - dist.yml: "let user to
98+
# build from source for now"), so one build covers every supported
99+
# interpreter. Build with cp312: tilelang hard-depends on
100+
# apache-tvm-ffi at runtime, whose own riscv64 wheel is cp312-abi3+,
101+
# so nothing below cp312 could import the result on riscv64 anyway.
102+
python: [cp312]
103+
steps:
104+
- name: Download sdist
105+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
106+
with:
107+
name: tilelang-${{ env.TILELANG_VERSION }}-sdist
108+
path: dist/
109+
110+
- name: Build wheels
111+
uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0
112+
with:
113+
package-dir: dist/${{ needs.build_sdist.outputs.sdist_name }}
114+
env:
115+
CIBW_BUILD: ${{ matrix.python }}-*
116+
CIBW_ARCHS: riscv64
117+
CIBW_SKIP: '*-musllinux_*'
118+
CIBW_MANYLINUX_RISCV64_IMAGE: ${{ env.MANYLINUX_RISCV64_IMAGE }}
119+
CIBW_BUILD_FRONTEND: build
120+
# Upstream's own [tool.cibuildwheel.linux] always sets USE_CUDA=ON
121+
# and USE_ROCM=ON and installs a CUDA toolkit via dnf; override for
122+
# the CPU-only build upstream documents but never ships itself
123+
# (docs/get_started/Installation.md: "USE_CUDA: ... set to OFF to
124+
# build a CPU version", "USE_LLVM: enable LLVM backend for CPU
125+
# codegen"). USE_LLVM=ON auto-detects llvm-config from PATH.
126+
CIBW_BEFORE_ALL_LINUX: dnf -y --enablerepo=crb install llvm-devel
127+
CIBW_ENVIRONMENT_LINUX: >-
128+
USE_CUDA=OFF USE_ROCM=OFF USE_LLVM=ON
129+
PIP_EXTRA_INDEX_URL=https://pypi.riseproject.dev/simple/
130+
UV_EXTRA_INDEX_URL=https://pypi.riseproject.dev/simple/
131+
UV_INDEX_STRATEGY=unsafe-best-match
132+
CIBW_TEST_ENVIRONMENT_LINUX: >-
133+
PIP_ONLY_BINARY=:all:
134+
UV_ONLY_BINARY=:all:
135+
# Mirror upstream's own repair-wheel-command, dropping the
136+
# CUDA-only excludes (no libcuda/CUDA toolkit in a CPU-only build).
137+
# libtvm_ffi.so/libz3.so* come from the apache-tvm-ffi/z3-solver
138+
# dependency wheels, not bundled here.
139+
CIBW_REPAIR_WHEEL_COMMAND_LINUX: >-
140+
auditwheel -v repair --exclude libtvm_ffi.so --exclude 'libz3.so*' -w {dest_dir} {wheel}
141+
CIBW_TEST_COMMAND: 'python -c "import tilelang; print(tilelang.__version__)"'
142+
143+
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
144+
with:
145+
name: tilelang-${{ env.TILELANG_VERSION }}-${{ matrix.python }}-manylinux_riscv64
146+
path: ./wheelhouse/*.whl
147+
if-no-files-found: error
148+
149+
publish:
150+
name: Publish tilelang ${{ inputs.version || '0.1.13' }}
151+
needs: [setup, build_wheels]
152+
permissions:
153+
contents: write
154+
pull-requests: write
155+
uses: $/.github/workflows/_publish-wheel.yml
156+
with:
157+
artifact-pattern: tilelang-${{ inputs.version || '0.1.13' }}-*-manylinux_riscv64
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
From 0e6a6a1f4c1a5cd3c8c3e0b1a0f6b6a6d1e0c0a1 Mon Sep 17 00:00:00 2001
2+
From: Ludovic Henry <git@ludovic.dev>
3+
Date: Thu, 10 Sep 2026 14:43:22 +0000
4+
Subject: [PATCH] exclude torch-c-dlpack-ext from the riscv64 dependency set
5+
6+
Upstream-Status: Inappropriate [riscv64 CI-specific: drops a torch C-extension accelerator with no riscv64 wheel anywhere; not something upstream would want for its general audience]
7+
8+
torch-c-dlpack-ext is an unconditional dependency for python_version <
9+
'3.14', but it ships no riscv64 wheel on PyPI or pypi.riseproject.dev, so
10+
`pip install` of the riscv64 wheel fails to resolve on any interpreter
11+
below 3.14. Upstream's own comment above the dependency says it is a soft
12+
accelerator, not a hard requirement: "Without it, TVM FFI may require JIT
13+
compilation on first import." Gate it off on riscv64 with an extra
14+
platform_machine marker so the rest of the dependency set (all of which do
15+
have riscv64 wheels) resolves normally; every other architecture keeps the
16+
exact same dependency.
17+
18+
Signed-off-by: Ludovic Henry <git@ludovic.dev>
19+
---
20+
pyproject.toml | 2 +-
21+
1 file changed, 1 insertion(+), 1 deletion(-)
22+
23+
diff --git a/pyproject.toml b/pyproject.toml
24+
index 1111111..2222222 100644
25+
--- a/pyproject.toml
26+
+++ b/pyproject.toml
27+
@@ -30,7 +30,7 @@ dependencies = [
28+
"apache-tvm-ffi>=0.1.11,<0.1.13",
29+
# torch-c-dlpack-ext provides prebuilt torch extensions.
30+
# Without it, TVM FFI may require JIT compilation on first import.
31+
- "torch-c-dlpack-ext; python_version < '3.14'",
32+
+ "torch-c-dlpack-ext; python_version < '3.14' and platform_machine != 'riscv64'",
33+
"cloudpickle",
34+
"ml-dtypes",
35+
"numpy>=1.23.5",
36+
--
37+
2.50.1
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
From b37abc7edf7b3349a341180d2ebaaba0ac45e9b9 Mon Sep 17 00:00:00 2001
2+
From: Ludovic Henry <git@ludovic.dev>
3+
Date: Thu, 10 Sep 2026 20:00:00 +0200
4+
Subject: [PATCH] cap the cython build requirement below 3.3
5+
6+
Upstream-Status: To upstream [not submitted: cannot open issues/PRs against tile-ai/tilelang from this environment; cross-platform bug, not riscv64-specific]
7+
8+
build-system.requires pins "cython>=3.1.0" with no upper bound. Cython
9+
3.3.0 (Cython/Utility/ModuleSetupCode.c) added a hard #error when a
10+
Limited API build targets below Python 3.9:
11+
12+
#if Py_LIMITED_API < 0x03090000
13+
#error "Cython 3.3 requires the Python Limited API version to be
14+
3.9 or greater."
15+
16+
tilelang's own scikit-build config sets `wheel.py-api = "cp38"`, so
17+
SKBUILD_SABI_VERSION is 3.8 and tilelang_cython_wrapper's generated
18+
.cpp fails to compile once an unbounded resolve picks up Cython
19+
3.3.0 (the current latest release on PyPI). This is not
20+
architecture-specific: any build resolving cython>=3.3 against the
21+
existing cp38 Limited API target breaks the same way. Cap it below
22+
3.3 so the resolver keeps picking a Cython release that predates this
23+
check, matching the Cython version tilelang's own CI has actually
24+
been built and tested against.
25+
26+
Signed-off-by: Ludovic Henry <git@ludovic.dev>
27+
---
28+
pyproject.toml | 2 +-
29+
1 file changed, 1 insertion(+), 1 deletion(-)
30+
31+
diff --git a/pyproject.toml b/pyproject.toml
32+
index dbb451e..1edf272 100644
33+
--- a/pyproject.toml
34+
+++ b/pyproject.toml
35+
@@ -74,7 +74,7 @@ torch = [
36+
37+
[build-system]
38+
requires = [
39+
- "cython>=3.1.0",
40+
+ "cython>=3.1.0,<3.3",
41+
"scikit-build-core",
42+
"z3-solver>=4.13.0,<4.15.5",
43+
# Not for auditwheel, explicitly add patchelf for repairing libz3.so.
44+
--
45+
2.50.1 (Apple Git-155)
46+

0 commit comments

Comments
 (0)