Skip to content
Draft
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
1 change: 1 addition & 0 deletions docs/packages/torch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,4 @@ versions:
- filename: torch-2.14.0+cpu-cp314-cp314t-manylinux_2_39_riscv64.whl
sha256: 13301800c70f5187f403256ed3680446dcece8534b5429380cfee44e6c8ce2bb
requires-python: '>=3.10'
- version: 2.14.1
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
From 0000000000000000000000000000000000000001 Mon Sep 17 00:00:00 2001
From: RISE Project CI <ci@riseproject.dev>
Date: Thu, 10 Jul 2026 00:00:00 +0000
Subject: [PATCH 1/2] [CI] Add manywheel Dockerfile for riscv64

Add Dockerfile_2_39_riscv64 for building riscv64 manywheel images using
quay.io/pypa/manylinux_2_39_riscv64 as base, and register the new
manylinux2_39_riscv64-builder:cpu-riscv64 image in build.sh.

Pin OPENBLAS_VERSION to v0.3.34: v0.3.33 (install_openblas.sh's default)
fails to build on riscv64 with "'coremsg' undeclared" in
dynamic_riscv64.c; v0.3.34 declares that buffer. Set as a plain shell
variable (not folded into DOCKER_GPU_BUILD_ARG) since build.sh
unconditionally appends its own `--build-arg "OPENBLAS_VERSION=..."`
after DOCKER_GPU_BUILD_ARG on the docker build command line, and a
later --build-arg for the same key silently wins.

Upstream-Status: To upstream

Signed-off-by: RISE Project CI <ci@riseproject.dev>
---
.ci/docker/manywheel/Dockerfile_2_39_riscv64 | 66 +++++++++++++++++++++++++++++++++
.ci/docker/manywheel/build.sh | 11 +++++++
2 files changed, 77 insertions(+)

diff --git a/.ci/docker/manywheel/Dockerfile_2_39_riscv64 b/.ci/docker/manywheel/Dockerfile_2_39_riscv64
new file mode 100644
--- /dev/null
+++ b/.ci/docker/manywheel/Dockerfile_2_39_riscv64
@@ -0,0 +1,66 @@
+FROM quay.io/pypa/manylinux_2_39_riscv64 as base
+
+ARG GCCTOOLSET_VERSION=14
+
+# Language variables
+ENV LC_ALL=en_US.UTF-8
+ENV LANG=en_US.UTF-8
+ENV LANGUAGE=en_US.UTF-8
+
+ARG PIP_EXTRA_INDEX_URL
+ENV PIP_EXTRA_INDEX_URL=${PIP_EXTRA_INDEX_URL}
+ARG PIP_PREFER_BINARY
+ENV PIP_PREFER_BINARY=${PIP_PREFER_BINARY}
+
+# Installed needed OS packages. This is to support all
+# the binary builds (torch, vision, audio, text, data)
+RUN yum -y update
+RUN yum install -y \
+ autoconf \
+ automake \
+ bison \
+ bzip2 \
+ curl \
+ diffutils \
+ file \
+ git \
+ less \
+ libffi-devel \
+ libgomp \
+ make \
+ openssl-devel \
+ patch \
+ perl \
+ unzip \
+ util-linux \
+ wget \
+ which \
+ xz \
+ zstd \
+ sudo \
+ gcc \
+ gcc-c++ \
+ gcc-gfortran \
+ gdb
+RUN yum install -y ninja-build
+
+# git236+ would refuse to run git commands in repos owned by other users
+# Which causes version check to fail, as pytorch repo is bind-mounted into the image
+# Override this behaviour by treating every folder as safe
+# For more details see https://github.com/pytorch/pytorch/issues/78659#issuecomment-1144107327
+RUN git config --global --add safe.directory "*"
+
+# Build CPython 3.15.0 / 3.15.0t from source; quay.io/pypa does not ship them yet
+COPY ./common/install_cpython.sh install_cpython.sh
+RUN CPYTHON_VERSIONS="3.15.0 3.15.0t" bash ./install_cpython.sh && rm install_cpython.sh
+
+FROM base as openblas
+# Install openblas
+ARG OPENBLAS_VERSION
+ADD ./common/install_openblas.sh install_openblas.sh
+RUN bash ./install_openblas.sh && rm install_openblas.sh
+
+FROM base as final
+
+# remove unnecessary python versions
+COPY --from=openblas /opt/OpenBLAS/ /opt/OpenBLAS/

diff --git a/.ci/docker/manywheel/build.sh b/.ci/docker/manywheel/build.sh
--- a/.ci/docker/manywheel/build.sh
+++ b/.ci/docker/manywheel/build.sh
@@ -43,6 +43,17 @@
DOCKER_GPU_BUILD_ARG=" --build-arg DEVTOOLSET_VERSION=13"
MANY_LINUX_VERSION="2_28_aarch64"
;;
+ manylinux2_39_riscv64-builder:cpu-riscv64)
+ TARGET=final
+ GPU_IMAGE=riscv64/almalinux:10-kitten
+ # Use a custom PyPI index to get pre-built wheels for RISC-V
+ # See https://riseproject-dev.github.io/python-wheels/
+ # v0.3.33 (install_openblas.sh's default) fails to build on riscv64
+ # with "'coremsg' undeclared" in dynamic_riscv64.c; v0.3.34 fixes it.
+ OPENBLAS_VERSION="v0.3.34"
+ DOCKER_GPU_BUILD_ARG=" --platform linux/riscv64 --build-arg DEVTOOLSET_VERSION=14 --build-arg PIP_EXTRA_INDEX_URL=https://pypi.riseproject.dev/simple --build-arg PIP_PREFER_BINARY=1"
+ MANY_LINUX_VERSION="2_39_riscv64"
+ ;;
manylinuxs390x-builder:cpu-s390x)
TARGET=final
GPU_IMAGE=s390x/almalinux:8
--
2.39.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
From 0000000000000000000000000000000000000002 Mon Sep 17 00:00:00 2001
From: RISE Project CI <ci@riseproject.dev>
Date: Thu, 10 Jul 2026 00:00:00 +0000
Subject: [PATCH 2/2] [CI] Add cpu-riscv64 support to manywheel scripts

Add riscv64 support to the manywheel scripts:
- build.sh: add cpu-riscv64 to GPU_ARCH_TYPE case
- build_env_setup.py: add manylinux_2_39_riscv64 PLATFORM_TAG and cpu-riscv64 env setup
- build_wheel.py: add riscv64 BLAS configuration (OpenBLAS, no MKLDNN)
- repair_wheel.py: generalise aarch64_extra_deps -> arch_extra_deps for multi-arch

Upstream-Status: Submitted [https://github.com/pytorch/pytorch/pull/191657]

Signed-off-by: RISE Project CI <ci@riseproject.dev>
---
diff --git a/.ci/manywheel/build.sh b/.ci/manywheel/build.sh
index 2f4abd2..8a0b0db 100755
--- a/.ci/manywheel/build.sh
+++ b/.ci/manywheel/build.sh
@@ -6,7 +6,7 @@ SCRIPTPATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
PYTORCH_ROOT="${PYTORCH_ROOT:-$(cd "${SCRIPTPATH}/../.." && pwd)}"

case "${GPU_ARCH_TYPE:-BLANK}" in
- cuda|cuda-aarch64|cpu|cpu-aarch64|cpu-cxx11-abi|xpu|rocm)
+ cuda|cuda-aarch64|cpu|cpu-aarch64|cpu-riscv64|cpu-cxx11-abi|xpu|rocm)
# New pipeline: pyproject-driven build via `python -m build`
# then patchelf-based wheel repair.
source "${SCRIPTPATH}/set_desired_python.sh"
diff --git a/.ci/manywheel/build_env_setup.py b/.ci/manywheel/build_env_setup.py
index 776fde3..f8edfd2 100755
--- a/.ci/manywheel/build_env_setup.py
+++ b/.ci/manywheel/build_env_setup.py
@@ -227,6 +227,7 @@ def discover_rocm_home() -> str:
PLATFORM_TAGS: dict[str, str] = {
"x86_64": "manylinux_2_28_x86_64",
"aarch64": "manylinux_2_28_aarch64",
+ "riscv64": "manylinux_2_39_riscv64",
}


@@ -494,7 +495,13 @@ def main() -> None:
setup_cuda(cuda_version)
env_out.update(cuda_build_env(cuda_version, arch))
print(f"CUDA {cuda_version} environment configured")
- elif gpu_arch_type in ("cpu", "cpu-aarch64", "cpu-s390x", "cpu-cxx11-abi"):
+ elif gpu_arch_type in (
+ "cpu",
+ "cpu-aarch64",
+ "cpu-riscv64",
+ "cpu-s390x",
+ "cpu-cxx11-abi",
+ ):
cleanup_cuda_for_cpu_build()
env_out.update(CPU_BUILD_ENV)
print("CPU environment configured")
diff --git a/.ci/manywheel/build_wheel.py b/.ci/manywheel/build_wheel.py
index 4b33397..b39298e 100755
--- a/.ci/manywheel/build_wheel.py
+++ b/.ci/manywheel/build_wheel.py
@@ -36,26 +36,34 @@ def configure_blas_env() -> None:
os.environ["CMAKE_LIBRARY_PATH"] = "/opt/intel/lib:/lib"
return

- if arch != "aarch64":
- return
+ elif arch == "aarch64":
+ if not Path("/acl").is_dir():
+ sys.exit("ERROR: ARM Compute Library not found at /acl")
+ os.environ["USE_MKLDNN"] = "1"
+ os.environ["USE_MKLDNN_ACL"] = "1"
+ os.environ["ACL_ROOT_DIR"] = "/acl"
+
+ if gpu_arch_type == "cuda-aarch64":
+ nvpl = Path("/usr/local/lib/libnvpl_blas_lp64_gomp.so.0")
+ if not nvpl.is_file():
+ sys.exit(f"ERROR: NVPL BLAS not found at {nvpl}")
+ print("Using NVPL BLAS/LAPACK and ACL for MKLDNN on CUDA aarch64")
+ os.environ["BLAS"] = "NVPL"
+ elif gpu_arch_type in ("cpu-aarch64", "cpu"):
+ openblas = Path("/opt/OpenBLAS/lib/libopenblas.so.0")
+ if not openblas.is_file():
+ sys.exit(f"ERROR: OpenBLAS not found at {openblas}")
+ print("Using OpenBLAS and ACL for MKLDNN on CPU aarch64")
+ os.environ["BLAS"] = "OpenBLAS"
+ os.environ["OpenBLAS_HOME"] = "/opt/OpenBLAS"
+
+ elif arch == "riscv64":
+ os.environ["USE_MKLDNN"] = "0"

- if not Path("/acl").is_dir():
- sys.exit("ERROR: ARM Compute Library not found at /acl")
- os.environ["USE_MKLDNN"] = "1"
- os.environ["USE_MKLDNN_ACL"] = "1"
- os.environ["ACL_ROOT_DIR"] = "/acl"
-
- if gpu_arch_type == "cuda-aarch64":
- nvpl = Path("/usr/local/lib/libnvpl_blas_lp64_gomp.so.0")
- if not nvpl.is_file():
- sys.exit(f"ERROR: NVPL BLAS not found at {nvpl}")
- print("Using NVPL BLAS/LAPACK and ACL for MKLDNN on CUDA aarch64")
- os.environ["BLAS"] = "NVPL"
- elif gpu_arch_type in ("cpu-aarch64", "cpu"):
openblas = Path("/opt/OpenBLAS/lib/libopenblas.so.0")
if not openblas.is_file():
sys.exit(f"ERROR: OpenBLAS not found at {openblas}")
- print("Using OpenBLAS and ACL for MKLDNN on CPU aarch64")
+ print("Using OpenBLAS for MKLDNN on CPU riscv64")
os.environ["BLAS"] = "OpenBLAS"
os.environ["OpenBLAS_HOME"] = "/opt/OpenBLAS"

diff --git a/.ci/manywheel/repair_wheel.py b/.ci/manywheel/repair_wheel.py
index 5cc1122..a66444e 100755
--- a/.ci/manywheel/repair_wheel.py
+++ b/.ci/manywheel/repair_wheel.py
@@ -29,6 +29,8 @@ from pathlib import Path

from auditwheel.wheeltools import add_platforms, InWheelCtx

+from build_env_setup import PLATFORM_TAGS
+

PATCHELF = "/usr/local/bin/patchelf"

@@ -116,19 +118,22 @@ def rocm_rpaths() -> str:
)


-def aarch64_extra_deps(use_cuda: bool) -> list[Path]:
+def arch_extra_deps(arch: str, use_cuda: bool) -> list[Path]:
"""Libraries to bundle into torch/lib/ on aarch64.

- CPU builds link against OpenBLAS + libgfortran; CUDA builds link against
- NVPL. Both pick up ARM Compute Library (ACL) for oneDNN acceleration.
+ CPU builds link against OpenBLAS + libgfortran
+ CUDA builds link against NVPL.
"""
- deps: list[Path] = []
candidates: list[Path] = [Path("/usr/lib64/libgfortran.so.5")]
- if Path("/acl/build").is_dir():
- candidates += [
- Path("/acl/build/libarm_compute.so"),
- Path("/acl/build/libarm_compute_graph.so"),
- ]
+ if arch == "aarch64":
+ # Both CPU and CUDA builds pick up ARM Compute Library (ACL) for
+ # oneDNN acceleration on AArch64.
+ if Path("/acl/build").is_dir():
+ candidates += [
+ Path("/acl/build/libarm_compute.so"),
+ Path("/acl/build/libarm_compute_graph.so"),
+ ]
+
if use_cuda:
candidates += [
Path(f"/usr/local/lib/{name}")
@@ -141,7 +146,8 @@ def aarch64_extra_deps(use_cuda: bool) -> list[Path]:
]
else:
candidates.append(Path("/opt/OpenBLAS/lib/libopenblas.so.0"))
- deps = [p for p in candidates if p.is_file()]
+
+ deps: list[Path] = [p for p in candidates if p.is_file()]
return deps


@@ -352,7 +358,7 @@ def repair_wheel(
output_dir: Path,
platform_tag: str,
libgomp_path: Path,
- aarch64_deps: list[Path],
+ arch_deps: list[Path],
bundled_libs: list[BundledLib],
aux_files: list[AuxFile],
c_so_rpath: str,
@@ -379,7 +385,7 @@ def repair_wheel(
)

# Bundle aarch64 BLAS/LAPACK/ACL dependencies (no-op on x86)
- for dep in aarch64_deps:
+ for dep in arch_deps:
shutil.copy(dep, torch_lib / dep.name)

# TODO: Remove when switching to ROCm wheels
@@ -487,21 +493,23 @@ def main() -> None:
lib_so_rpath = "$ORIGIN"
force_rpath = False

- aarch64_deps = aarch64_extra_deps(use_cuda) if arch == "aarch64" else []
+ arch_deps = arch_extra_deps(arch, use_cuda)

args.output_dir.mkdir(parents=True, exist_ok=True)
wheels = sorted(args.input_dir.glob("*.whl"))
if not wheels:
sys.exit(f"No wheels found in {args.input_dir}")

- platform_tag = f"manylinux_2_28_{arch}"
+ if arch not in PLATFORM_TAGS:
+ sys.exit(f"Unknown arch {arch}")
+ platform_tag = PLATFORM_TAGS[arch]
for whl in wheels:
repair_wheel(
whl,
args.output_dir,
platform_tag,
libgomp_path,
- aarch64_deps,
+ arch_deps,
bundled_libs,
aux_files,
c_so_rpath,

--
2.39.0
Loading