Skip to content
Merged
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
194 changes: 194 additions & 0 deletions .github/workflows/build-usd-core.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
# SPDX-FileCopyrightText: 2026 The RISE Project
# SPDX-License-Identifier: MIT
---
# Mirrors the Linux job of upstream's .github/workflows/pypi.yml: build_usd.py with
# imaging/MaterialX/examples/tutorials off, then build_scripts/pypi/{setup.py,
# updatePluginfos.py}, narrowed to riscv64.
name: Build usd-core wheels (riscv64)

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

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

permissions:
contents: read

env:
MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64

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

build_wheels:
needs: [setup]
if: needs.setup.outputs.versions != '[]'
name: Build usd-core ${{ matrix.version }} ${{ matrix.python }}-manylinux_riscv64
runs-on: ubuntu-24.04-riscv
timeout-minutes: 1440
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
# Upstream publishes cp39-cp314 and no free-threaded wheel; the
# pxr_boost::python bindings never declare Py_mod_gil, so a cp314t wheel
# would only re-enable the GIL.
python: ["cp312", "cp313", "cp314"]

env:
USD_CORE_VERSION: ${{ matrix.version }}

steps:
- name: Resolve the OpenUSD release tag
id: tag
run: |
set -euo pipefail
printf 'tag=v%s\n' \
"$(awk -F. '{printf "%s.%02d", $1, $2}' <<<"${USD_CORE_VERSION}")" >> "$GITHUB_OUTPUT"

- name: Checkout OpenUSD ${{ steps.tag.outputs.tag }}
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: PixarAnimationStudios/OpenUSD
ref: ${{ steps.tag.outputs.tag }}
persist-credentials: false

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

- name: Patch OpenUSD
run: git apply python-wheels/patches/usd-core/${{ env.USD_CORE_VERSION }}/00*.patch

- name: Pull manylinux_riscv64 image
run: docker pull "${MANYLINUX_RISCV64_IMAGE}"

- name: Build USD and the wheel
run: |
mkdir -p dist
docker run -i --rm \
-v "${GITHUB_WORKSPACE}:/work" \
-w /work \
-e PYTHON_TAG="${{ matrix.python }}" \
"${MANYLINUX_RISCV64_IMAGE}" bash -s <<'USD_BUILD_EOF'
#!/usr/bin/env bash
set -euxo pipefail

PY="/opt/python/${PYTHON_TAG}-${PYTHON_TAG}/bin/python"
"$PY" -m pip install setuptools wheel

# Upstream's own pypi.yml hack: the manylinux image ships no libpython
# (PEP 513), and FindPython's Development component refuses to configure
# without the file even though PXR_PY_UNDEFINED_DYNAMIC_LOOKUP means USD
# never links against it.
"$PY" -c "import pathlib,sysconfig; pathlib.Path(sysconfig.get_config_var('LIBDIR'), sysconfig.get_config_var('LDLIBRARY')).touch()"

"$PY" build_scripts/build_usd.py --build-monolithic \
--build-args USD,"-DPXR_PY_UNDEFINED_DYNAMIC_LOOKUP=ON -DPXR_BUILD_USD_TOOLS=OFF -DPXR_BUILD_EXEC=OFF -DPXR_INSTALL_LOCATION=../pxr/pluginfo -DPXR_PYTHON_INSTALL_DIR=lib/python" \
--no-materialx --no-imaging --no-examples --no-tutorials \
--build /work/gen/build --src /work/gen/src /work/inst -v

mkdir packaging
cp -R /work/inst ./packaging
cp build_scripts/pypi/package_files/* ./packaging
cp LICENSE.txt ./packaging
# auditwheel vendors the TBB shared library into the wheel, so its
# Apache-2.0 text has to travel with it; setuptools' default
# license_files glob picks LICENSE* up without a setup.py edit.
cp gen/src/oneTBB-*/LICENSE ./packaging/LICENSE.oneTBB.txt

cd packaging
"$PY" setup.py bdist_wheel --python-tag "${PYTHON_TAG}"
cd /work

PYTHONPATH=/work/packaging/pypi/lib/python \
LD_LIBRARY_PATH="/work/packaging/pypi/lib:${LD_LIBRARY_PATH:-}" \
auditwheel repair packaging/dist/*.whl

repaired="$(echo wheelhouse/*.whl)"
"$PY" build_scripts/pypi/updatePluginfos.py \
"${repaired}" "/work/dist/$(basename "${repaired}")"
ls -la /work/dist
USD_BUILD_EOF

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

- name: Test usd-core wheel
run: |
docker run -i --rm \
-v "${GITHUB_WORKSPACE}:/work" \
-w /work \
-e PYTHON_TAG="${{ matrix.python }}" \
"${MANYLINUX_RISCV64_IMAGE}" bash -s <<'USD_TEST_EOF'
#!/usr/bin/env bash
set -euxo pipefail

PY="/opt/python/${PYTHON_TAG}-${PYTHON_TAG}/bin/python"
"$PY" -m pip install pytest
"$PY" -m pip install --no-index --find-links=/work/dist usd-core

# /work/pxr is the checkout's C++ source tree and would shadow the
# installed package as a namespace package, so run from elsewhere and
# prove which pxr was imported.
cd /tmp
"$PY" -c "
import pathlib, pxr
p = pathlib.Path(pxr.__file__)
print(p)
assert 'site-packages' in p.parts
import importlib, pkgutil
mods = sorted(m.name for m in pkgutil.iter_modules(pxr.__path__))
for m in mods:
importlib.import_module('pxr.' + m)
print(len(mods), 'modules imported:', ' '.join(mods))
assert 'Usd' in mods and 'Sdf' in mods and 'UsdGeom' in mods
"
"$PY" -m pytest -v /work/build_scripts/pypi/test.py
USD_TEST_EOF

publish:
name: Publish usd-core ${{ matrix.version }}
needs: [setup, build_wheels]
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: usd-core-${{ matrix.version }}-*-manylinux_riscv64
6 changes: 6 additions & 0 deletions docs/packages/usd-core.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package-name: usd-core
source-code: https://github.com/PixarAnimationStudios/OpenUSD
license: LicenseRef-TOST-1.0
versions:
- version: 26.8
patched: true
121 changes: 121 additions & 0 deletions patches/usd-core/26.8/0001-Support-riscv64-in-pxr-base-arch.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
From e346d5ee838ae79333ed9e0f6242891c841ed1b8 Mon Sep 17 00:00:00 2001
From: Ludovic Henry <git@ludovic.dev>
Date: Mon, 21 Sep 2026 01:53:09 +0000
Subject: [PATCH] Support riscv64 in pxr/base/arch

pxr/base/arch/defines.h recognises only x86 and ARM, and its "Bits" block
ends in #error "Unsupported architecture. x86_64 or ARM64 required." - so
every translation unit of USD fails on riscv64 before anything else is
compiled. Two further sites are reached once that is fixed: arch/math.h
guards ArchSign/ArchFloatToBitPattern/... on
ARCH_CPU_INTEL || ARCH_CPU_ARM || ARCH_OS_WASM_VM and ends in #error Unknown
system architecture (the code it guards is portable IEEE-754 bit twiddling,
not x86 or ARM specific), and nonLockingLinux__execve() in
arch/stackTrace.cpp has hand-written syscall asm for aarch64 and x86_64 with
#error Unknown architecture in the #else.

Add an ARCH_CPU_RISCV define for __riscv, admit __riscv_xlen == 64 to
ARCH_BITS_64, let math.h's gate accept it, and give
nonLockingLinux__execve() a riscv64 branch. The syscall branch mirrors the
aarch64 one exactly: the Linux riscv64 ABI passes arguments in a0-a2, takes
the syscall number in a7, uses the same generic __NR_execve == 221 as
aarch64, and traps with ecall instead of svc. Everything else in arch is
already portable: ARCH_SPIN_PAUSE() has a no-op #else, timing.h only reaches
rdtsc behind PXR_ARCH_PREFER_TSC_TIMING and otherwise uses
std::chrono::steady_clock, and the remaining #error branches in
systemInfo.cpp/fileSystem.cpp/assumptions.cpp select on the OS, not the CPU.

With this, the core (non-imaging) USD libraries and their Python bindings
build and run on riscv64; pxr/base/gf's SIMD paths are already gated on
__SSE2__/__ARM_NEON with scalar fallbacks, and the vendored
double-conversion already lists __riscv.

Upstream-Status: To upstream [not submitted from this automated port run; needs a pull request against PixarAnimationStudios/OpenUSD]
---
pxr/base/arch/defines.h | 7 +++++--
pxr/base/arch/math.h | 1 +
pxr/base/arch/overview.dox | 1 +
pxr/base/arch/stackTrace.cpp | 14 ++++++++++++++
4 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/pxr/base/arch/defines.h b/pxr/base/arch/defines.h
index b7ed634..58e860c 100644
--- a/pxr/base/arch/defines.h
+++ b/pxr/base/arch/defines.h
@@ -39,6 +39,8 @@
#elif defined(__arm__) || defined(__aarch64__) || defined(_M_ARM) || \
defined(_M_ARM64)
#define ARCH_CPU_ARM
+#elif defined(__riscv)
+#define ARCH_CPU_RISCV
#endif

//
@@ -46,12 +48,13 @@
//

#if defined(__x86_64__) || defined(__aarch64__) || defined(_M_X64) || \
- defined(_M_ARM64) || defined(__wasm64__)
+ defined(_M_ARM64) || defined(__wasm64__) || \
+ (defined(__riscv) && __riscv_xlen == 64)
#define ARCH_BITS_64
#elif defined(__wasm32__)
#define ARCH_BITS_32
#else
-#error "Unsupported architecture. x86_64 or ARM64 required."
+#error "Unsupported architecture. x86_64, ARM64 or RISC-V 64 required."
#endif

//
diff --git a/pxr/base/arch/math.h b/pxr/base/arch/math.h
index ccd53a6..8191023 100644
--- a/pxr/base/arch/math.h
+++ b/pxr/base/arch/math.h
@@ -30,6 +30,7 @@ PXR_NAMESPACE_OPEN_SCOPE
///@{

#if defined (ARCH_CPU_INTEL) || defined (ARCH_CPU_ARM) || \
+ defined (ARCH_CPU_RISCV) || \
defined(ARCH_OS_WASM_VM) || defined (doxygen)

/// This is the smallest value e such that 1+e^2 == 1, using floats.
diff --git a/pxr/base/arch/overview.dox b/pxr/base/arch/overview.dox
index b8eaf9b..045375b 100644
--- a/pxr/base/arch/overview.dox
+++ b/pxr/base/arch/overview.dox
@@ -64,6 +64,7 @@ For processor:
<ul>
<li> ARCH_CPU_INTEL
<li> ARCH_CPU_ARM
+ <li> ARCH_CPU_RISCV
</ul>

For bits:
diff --git a/pxr/base/arch/stackTrace.cpp b/pxr/base/arch/stackTrace.cpp
index 384959e..6a90d38 100644
--- a/pxr/base/arch/stackTrace.cpp
+++ b/pxr/base/arch/stackTrace.cpp
@@ -878,6 +878,20 @@ nonLockingLinux__execve (const char *file,
);
result = __file_result;
}
+#elif defined (ARCH_CPU_RISCV) && defined(ARCH_BITS_64)
+ {
+ long __file_result asm ("a0") = (long)file;
+ char* const* __argv asm ("a1") = argv;
+ char* const* __envp asm ("a2") = envp;
+ long __num_execve asm ("a7") = 221;
+ __asm__ __volatile__ (
+ "ecall"
+ : "=r" (__file_result)
+ : "r"(__num_execve), "r" (__file_result), "r" (__argv), "r" (__envp)
+ : "memory"
+ );
+ result = __file_result;
+ }
#elif defined(ARCH_CPU_INTEL) && defined(ARCH_BITS_64)

/*
--
2.43.0

Loading