From 0d3e55a5304b312597fcff1a11a88d13f1d3aabc Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Thu, 15 Oct 2026 06:52:10 +0000 Subject: [PATCH 1/2] sapien: add riscv64 port (PhysX built from source) Adds build-sapien.yml, docs/packages/sapien.yaml and the patches/sapien/3.0.3 patch set porting SAPIEN 3.0.3 to riscv64. PhysX is built from source from sapien-sim/PhysX (the exact fork + tag 105.1-physx-5.3.1.patch0 SAPIEN pins, not raw NVIDIA-Omniverse/PhysX; no riscv64 precompiled archive exists) and fed back in via the new SAPIEN_PHYSX5_DIR plumbing in setup.py. Six concrete PhysX/SAPIEN sites needed patching: - PxPreprocessor.h: new PX_RISCV64 define, folded into PX_P64_FAMILY only (not PX_ARM_FAMILY/PX_INTEL_FAMILY). COMPILE_VECTOR_INTRINSICS is gated on PX_INTEL_FAMILY||PX_SWITCH only, so riscv64 automatically lands on PxVecMathAoSScalar.h -- the same scalar fallback aarch64's own precompiled Linux build already ships in production. - SnSerialUtils.cpp: a tenth binary-platform-tag table entry (SN_NUM_BINARY_PLATFORMS 9->10). - source/compiler/cmake/linux/CMakeLists.txt: extend the aarch64-only -Werror relaxation to riscv64 too, rather than exposing a brand new GCC target to an x86_64-tuned -Werror exclude list untested. - Root CMakeLists.txt: skip CMake's CUDA language on riscv64 like macOS (project() enables it unconditionally on every non-Apple platform, independent of the runtime SAPIEN_CUDA option). - cmake/physx5.cmake: a dedicated bin/linux.riscv64/release path instead of silently reusing the x86_64-labeled bin/linux.clang bucket. - setup.py: thread --physx5-dir/SAPIEN_PHYSX5_DIR into both cmake invocations (there was no CLI/env plumbing for it at all). Verified directly against sapien-sim/PhysX@105.1-physx-5.3.1.patch0 and haosulab/SAPIEN@3.0.3 source (sparse sibling clones, not committed here): PxUnixFPU.h's SIMDGuard #error, flagged by the prior triage as a 6th compile blocker, turns out to be unreachable on riscv64 -- PxFPU.h only ever includes it when PX_LINUX&&PX_SSE2, so riscv64 (PX_SSE2=0) already takes PxFPU.h's own generic no-op ctor/dtor fallback without it. No patch needed there. A 7th patch adds an explicit riscv64 branch to the sapien-vulkan-2 submodule's cmake/openvr.cmake (via a FetchContent PATCH_COMMAND against the comoco-xiao/openvr fork's own CMakeLists.txt, since that source isn't vendored here): it currently silently takes the x86_64-labeled -DLINUX64 branch instead of -DLINUXARM64's riscv64 equivalent. Low-risk either way (openvr_api is linked but never exercised without VR hardware) but fixed for correctness. build-sapien.yml builds PhysX and SAPIEN's --sapien-only core once (not per interpreter) inside manylinux_2_39_riscv64, then loops --pybind-only + auditwheel repair over cp312/cp313/cp314/cp314t, matching upstream's own scripts/build.sh/build_aarch64.sh shape. sapien-vulkan-2's 11 FetchContent deps (glm/assimp-fork/spdlog/glfw/ktx/Vulkan-Headers/glslang/SPIRV-Cross/ imgui/openexr/openvr-fork) are left to CMake's own FetchContent machinery inside the build step -- this repo's build-openexr.yml/build-glfw.yml/ build-cmeel-zlib.yml/build-cmeel-assimp.yml already prove OpenEXR/glfw/ zlib/assimp source-compile cleanly on manylinux_2_39_riscv64, but that's signal, not proof, for this different FetchContent-vs-pip-wheel consumption path; KTX-Software's Basis Universal transcoder was the remaining worry, but BASISU_SUPPORT_SSE turns out to be a CMAKE_DEPENDENT_OPTION keyed on CPU_ARCHITECTURE STREQUAL x86_64/x86, so it already resolves OFF on riscv64 without a patch. The docker/arm.Dockerfile "forked auditwheel" (fbxiang/auditwheel@fe61bcd) mystery is resolved: diffed against stock pypa/auditwheel 6.2.0 (its CHANGELOG base), the fork is a single ~20-line, architecture-independent `--internal ` flag that skips auditwheel's usual hash-renaming for named libraries. SAPIEN needs it so the grafted libsapien.so/libsvulkan2.so keep their exact names (pysapien loads them by fixed filename); x86_64 and aarch64 Dockerfiles both already carry it. This repo's stock auditwheel does not support --internal, so the riscv64 build installs the same fork, not a workaround. No GPU/Vulkan driver exists on the riscv64 runners, so the wheel test is physics-only (sapien.Scene + physx_system, no renderer). The SwiftShader/lavapipe software-Vulkan fallback was not investigated this pass. Nothing here has been compiled on riscv64 yet -- there is no riscv64 toolchain available to validate the C++ patches locally, so correctness of the PhysX cmake invocation (output library layout especially) and the sapien-vulkan-2 FetchContent compile are unproven until CI actually runs this workflow. --- .github/workflows/build-sapien.yml | 240 ++++++++++++++++++ docs/packages/sapien.yaml | 5 + ...ndation-add-riscv64-to-PX_P64_FAMILY.patch | 62 +++++ ...tion-add-riscv64-binary-platform-tag.patch | 65 +++++ ...arch64-warning-relaxation-to-riscv64.patch | 39 +++ ...-cmake-skip-cuda-language-on-riscv64.patch | 36 +++ ...make-physx5-add-riscv64-library-path.patch | 40 +++ ...006-setup.py-plumb-sapien_physx5_dir.patch | 60 +++++ ...7-svulkan2-openvr-add-riscv64-branch.patch | 48 ++++ 9 files changed, 595 insertions(+) create mode 100644 .github/workflows/build-sapien.yml create mode 100644 docs/packages/sapien.yaml create mode 100644 patches/sapien/3.0.3/0001-physx-foundation-add-riscv64-to-PX_P64_FAMILY.patch create mode 100644 patches/sapien/3.0.3/0002-physx-serialization-add-riscv64-binary-platform-tag.patch create mode 100644 patches/sapien/3.0.3/0003-physx-cmake-extend-aarch64-warning-relaxation-to-riscv64.patch create mode 100644 patches/sapien/3.0.3/0004-cmake-skip-cuda-language-on-riscv64.patch create mode 100644 patches/sapien/3.0.3/0005-cmake-physx5-add-riscv64-library-path.patch create mode 100644 patches/sapien/3.0.3/0006-setup.py-plumb-sapien_physx5_dir.patch create mode 100644 patches/sapien/3.0.3/0007-svulkan2-openvr-add-riscv64-branch.patch diff --git a/.github/workflows/build-sapien.yml b/.github/workflows/build-sapien.yml new file mode 100644 index 000000000000..ed0934a7e0b3 --- /dev/null +++ b/.github/workflows/build-sapien.yml @@ -0,0 +1,240 @@ +# SPDX-FileCopyrightText: 2026 The RISE Project +# SPDX-License-Identifier: MIT +# +# Upstream builds libsapien and the Python bindings as two separate CMake +# stages (setup.py --sapien-only then --pybind-only per interpreter, scripts/ +# build.sh / build_aarch64.sh) rather than via cibuildwheel; this workflow +# follows the same shape, driving the manylinux image directly instead of a +# matrix per interpreter so the expensive C++ world (PhysX, svulkan2 and its +# FetchContent deps) is only built once. PhysX has no riscv64 precompiled +# archive, so it's built from source from sapien-sim/PhysX (the exact fork +# SAPIEN pins, not raw NVIDIA-Omniverse/PhysX) and fed back in via +# SAPIEN_PHYSX5_DIR. GPU PhysX, CUDA and OpenImageDenoise are all off +# (SAPIEN_CUDA defaults OFF without a CUDA_PATH). +name: Build sapien wheels (riscv64) + +on: + workflow_dispatch: + inputs: + version: + description: 'Version glob to (re)build; empty builds every version of docs/packages/sapien.yaml not released yet' + required: false + default: '' + pull_request: + branches: [main] + paths: + - '.github/workflows/build-sapien.yml' + - 'docs/packages/sapien.yaml' + - 'patches/sapien/**' + push: + branches: [main] + paths: + - '.github/workflows/build-sapien.yml' + - 'docs/packages/sapien.yaml' + - 'patches/sapien/**' + +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 + PIP_EXTRA_INDEX_URL: https://pypi.riseproject.dev/simple/ + PHYSX_TAG: 105.1-physx-5.3.1.patch0 + AUDITWHEEL_FORK_REF: fe61bcdfb78f3955d9a3b6fbb05e3852c32239b0 + +jobs: + setup: + uses: $/.github/workflows/_setup.yml + with: + package: sapien + version: ${{ inputs.version }} + + build_wheels: + needs: [setup] + if: needs.setup.outputs.versions != '[]' + name: Build sapien ${{ matrix.version }}-manylinux_riscv64 + runs-on: ubuntu-24.04-riscv + timeout-minutes: 1440 + strategy: + fail-fast: false + matrix: + version: ${{ fromJSON(needs.setup.outputs.versions) }} + + env: + SAPIEN_VERSION: ${{ matrix.version }} + + steps: + - name: Checkout haosulab/SAPIEN ${{ env.SAPIEN_VERSION }} + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + repository: haosulab/SAPIEN + ref: ${{ env.SAPIEN_VERSION }} + submodules: recursive + path: sapien + persist-credentials: false + + - name: Checkout sapien-sim/PhysX ${{ env.PHYSX_TAG }} + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + repository: sapien-sim/PhysX + ref: ${{ env.PHYSX_TAG }} + path: physx-src + persist-credentials: false + + - name: Checkout python-wheels + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + path: python-wheels + persist-credentials: false + + - name: Apply riscv64 patches + run: | + set -eux + PATCH_DIR="$PWD/python-wheels/patches/sapien/${SAPIEN_VERSION}" + cd physx-src + git apply -v "$PATCH_DIR"/0001-physx-foundation-add-riscv64-to-PX_P64_FAMILY.patch + git apply -v "$PATCH_DIR"/0002-physx-serialization-add-riscv64-binary-platform-tag.patch + git apply -v "$PATCH_DIR"/0003-physx-cmake-extend-aarch64-warning-relaxation-to-riscv64.patch + cd ../sapien + git apply -v "$PATCH_DIR"/0004-cmake-skip-cuda-language-on-riscv64.patch + git apply -v "$PATCH_DIR"/0005-cmake-physx5-add-riscv64-library-path.patch + git apply -v "$PATCH_DIR"/0006-setup.py-plumb-sapien_physx5_dir.patch + git apply -v "$PATCH_DIR"/0007-svulkan2-openvr-add-riscv64-branch.patch + + - name: Build PhysX, SAPIEN core and the Python wheels + run: | + mkdir -p output "$HOME/.cache/sapien-ccache" + docker run -i --rm \ + -v "$PWD/sapien:/sapien" \ + -v "$PWD/physx-src:/physx-src" \ + -v "$PWD/output:/output" \ + -v "$HOME/.cache/sapien-ccache:/ccache" \ + -e CCACHE_DIR=/ccache \ + -e PIP_EXTRA_INDEX_URL \ + -e AUDITWHEEL_FORK_REF \ + -e CMAKE_BUILD_PARALLEL_LEVEL=4 \ + "$MANYLINUX_RISCV64_IMAGE" bash -s <<'SAPIEN_BUILD_EOF' + #!/usr/bin/env bash + set -euxo pipefail + + dnf install -y --setopt=install_weak_deps=False \ + ninja-build \ + libXinerama-devel libXrandr-devel libXcursor-devel libXi-devel \ + wayland-devel libxkbcommon-devel wayland-protocols-devel + + PYBIN0=/opt/python/cp312-cp312/bin + export PATH="$PYBIN0:$PATH" + "$PYBIN0/pip" install -U "git+https://github.com/fbxiang/auditwheel.git@${AUDITWHEEL_FORK_REF}" + cat > /usr/local/bin/auditwheel </dev/null 2>&1 && \ + PHYSX_CCACHE_ARGS="-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache" || \ + PHYSX_CCACHE_ARGS="" + cmake -S /physx-src/physx/compiler/public -B /tmp/physx_build -G Ninja \ + -DTARGET_BUILD_PLATFORM=linux \ + -DPHYSX_ROOT_DIR=/physx-src/physx \ + -DPX_GENERATE_STATIC_LIBRARIES=1 \ + -DPX_BUILDSNIPPETS=0 \ + -DPX_BUILDPVDRUNTIME=0 \ + -DCMAKE_BUILD_TYPE=release \ + ${PHYSX_CCACHE_ARGS} + cmake --build /tmp/physx_build + find /physx-src/physx/bin -name 'libPhysX*_static_64.a' \ + -exec cp {} "$PHYSX_INSTALL/bin/linux.riscv64/release/" \; + ls "$PHYSX_INSTALL/bin/linux.riscv64/release" + cp -r /physx-src/physx/include "$PHYSX_INSTALL/include" + + cd /sapien + "$PYBIN0/python3" -m pip install -U setuptools wheel + command -v ccache >/dev/null 2>&1 && \ + export CMAKE_C_COMPILER_LAUNCHER=ccache CMAKE_CXX_COMPILER_LAUNCHER=ccache + "$PYBIN0/python3" setup.py bdist_wheel --sapien-only \ + --build-dir=sapien_build --physx5-dir="$PHYSX_INSTALL" + + for PYTAG in cp312-cp312 cp313-cp313 cp314-cp314 cp314-cp314t; do + PYBIN=/opt/python/${PYTAG}/bin + "$PYBIN/python3" -m pip install -U setuptools wheel + "$PYBIN/python3" setup.py bdist_wheel --pybind-only \ + --build-dir=sapien_build --physx5-dir="$PHYSX_INSTALL" + done + + PACKAGE_VERSION=$("$PYBIN0/python3" setup.py --get-version) + mkdir -p /output + for whl in dist/sapien-"${PACKAGE_VERSION}"-*.whl; do + /usr/local/bin/auditwheel repair "$whl" \ + --exclude 'libvulkan*' --exclude 'libOpenImageDenoise*' \ + --exclude 'libm.so*' --exclude 'libc.so*' --exclude 'libdl.so*' --exclude 'libpthread.so*' \ + --internal libsapien --internal libsvulkan2 \ + -w /output + done + ls -la /output + SAPIEN_BUILD_EOF + + - name: Test sapien wheel (physics only, no GPU/Vulkan on this runner) + run: | + docker run -i --rm \ + -v "$PWD/output:/output" \ + -e PIP_EXTRA_INDEX_URL \ + "$MANYLINUX_RISCV64_IMAGE" bash -s <<'SAPIEN_TEST_EOF' + #!/usr/bin/env bash + set -euxo pipefail + + for PYTAG in cp312-cp312 cp313-cp313 cp314-cp314 cp314-cp314t; do + PYBIN=/opt/python/${PYTAG}/bin + WHEEL=$(ls /output/sapien-*-"${PYTAG}"-manylinux_*riscv64.whl) + "$PYBIN/pip" install "$WHEEL" + "$PYBIN/python3" -c " + import sapien + + scene = sapien.Scene() + scene.physx_system.timestep = 1 / 100 + scene.create_actor_builder().add_box_collision(half_size=[1, 1, 1]).build_static() + for _ in range(10): + scene.step() + print('sapien physx smoke test OK:', sapien.__version__) + " + done + SAPIEN_TEST_EOF + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: sapien-${{ env.SAPIEN_VERSION }}-manylinux_riscv64 + path: output/*.whl + if-no-files-found: error + + publish: + name: Publish sapien ${{ 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: sapien-${{ matrix.version }}-manylinux_riscv64 diff --git a/docs/packages/sapien.yaml b/docs/packages/sapien.yaml new file mode 100644 index 000000000000..4216709c1ba0 --- /dev/null +++ b/docs/packages/sapien.yaml @@ -0,0 +1,5 @@ +package-name: sapien +source-code: https://github.com/haosulab/SAPIEN +license: Apache-2.0 +versions: +- version: 3.0.3 diff --git a/patches/sapien/3.0.3/0001-physx-foundation-add-riscv64-to-PX_P64_FAMILY.patch b/patches/sapien/3.0.3/0001-physx-foundation-add-riscv64-to-PX_P64_FAMILY.patch new file mode 100644 index 000000000000..de618e0e296c --- /dev/null +++ b/patches/sapien/3.0.3/0001-physx-foundation-add-riscv64-to-PX_P64_FAMILY.patch @@ -0,0 +1,62 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ludovic Henry +Date: Thu, 15 Oct 2026 00:00:00 +0000 +Subject: [PATCH] physx/foundation: add riscv64 to PX_P64_FAMILY + +Upstream-Status: To upstream [no riscv64 CI to validate against yet] + +PxPreprocessor.h's architecture block recognizes x86_64, i386, arm64, +arm32 and ppc only; any other __riscv/__riscv_xlen==64 target falls +through to `#error "Unknown architecture"`, which is a real compile +blocker for riscv64 (not an untested-upstream SIMD path: this file +never reaches a SIMD choice at all without first defining an arch). + +Add PX_RISCV64 as its own define, give it the usual `#ifndef ... 0 +#endif` default like every other arch macro, and fold it into +PX_P64_FAMILY only (the 64-bit-pointer shortcut used by serialization +and struct layout code) -- not PX_ARM_FAMILY or PX_INTEL_FAMILY, which +riscv64 is neither. Downstream, COMPILE_VECTOR_INTRINSICS +(PxVecMath.h) is gated on PX_INTEL_FAMILY || PX_SWITCH only, so once +PX_RISCV64 exists, riscv64 automatically lands on PxVecMathAoSScalar.h +-- the same scalar fallback aarch64's own precompiled Linux build +already ships in production, not a new/untested code path. + +Signed-off-by: Ludovic Henry +--- + physx/include/foundation/PxPreprocessor.h | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/physx/include/foundation/PxPreprocessor.h b/physx/include/foundation/PxPreprocessor.h +index 0000000..0000000 100644 +--- a/physx/include/foundation/PxPreprocessor.h ++++ b/physx/include/foundation/PxPreprocessor.h +@@ -116,6 +116,8 @@ + #define PX_ARM 1 + #elif defined(__ppc__) || defined(_M_PPC) || defined(__CELLOS_LV2__) + #define PX_PPC 1 ++#elif defined(__riscv) && (__riscv_xlen == 64) ++ #define PX_RISCV64 1 + #else + #error "Unknown architecture" + #endif +@@ -177,6 +179,9 @@ + #ifndef PX_PPC + #define PX_PPC 0 + #endif ++#ifndef PX_RISCV64 ++ #define PX_RISCV64 0 ++#endif + #ifndef PX_SSE2 + #define PX_SSE2 0 + #endif +@@ -227,7 +232,7 @@ + // architecture + #define PX_INTEL_FAMILY (PX_X64 || PX_X86) + #define PX_ARM_FAMILY (PX_ARM || PX_A64) +-#define PX_P64_FAMILY (PX_X64 || PX_A64) // shortcut for 64-bit architectures ++#define PX_P64_FAMILY (PX_X64 || PX_A64 || PX_RISCV64) // shortcut for 64-bit architectures + + /** + C++ standard library defines +-- +2.50.1 diff --git a/patches/sapien/3.0.3/0002-physx-serialization-add-riscv64-binary-platform-tag.patch b/patches/sapien/3.0.3/0002-physx-serialization-add-riscv64-binary-platform-tag.patch new file mode 100644 index 000000000000..ee0e1fddaad0 --- /dev/null +++ b/patches/sapien/3.0.3/0002-physx-serialization-add-riscv64-binary-platform-tag.patch @@ -0,0 +1,65 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ludovic Henry +Date: Thu, 15 Oct 2026 00:00:00 +0000 +Subject: [PATCH] physx/serialization: add riscv64 binary platform tag + +Upstream-Status: To upstream [no riscv64 CI to validate against yet] + +getBinaryPlatformTag() in SnSerialUtils.cpp is a real compile blocker +on riscv64 independent of the PxPreprocessor.h arch define: with +PX_RISCV64 now defined (previous patch), none of the existing +PX_WINDOWS/PX_LINUX/PX_OSX/PX_SWITCH x PX_X86/PX_X64/PX_A64 branches +match it, so it falls straight through to `#error Unknown binary +platform`. Add a tenth table entry (FOURCC 'L','R','6','4', name +"linuxriscv64") and the matching `#elif PX_LINUX && PX_RISCV64` branch, +bumping SN_NUM_BINARY_PLATFORMS from 9 to 10 to match. + +Signed-off-by: Ludovic Henry +--- + .../src/serialization/SnSerialUtils.cpp | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/physx/source/physxextensions/src/serialization/SnSerialUtils.cpp b/physx/source/physxextensions/src/serialization/SnSerialUtils.cpp +index 0000000..0000000 100644 +--- a/physx/source/physxextensions/src/serialization/SnSerialUtils.cpp ++++ b/physx/source/physxextensions/src/serialization/SnSerialUtils.cpp +@@ -39,6 +39,6 @@ + { + +-#define SN_NUM_BINARY_PLATFORMS 9 ++#define SN_NUM_BINARY_PLATFORMS 10 + const PxU32 sBinaryPlatformTags[SN_NUM_BINARY_PLATFORMS] = + { + PX_MAKE_FOURCC('W','_','3','2'), +@@ -49,7 +49,8 @@ + PX_MAKE_FOURCC('M','_','6','4'), + PX_MAKE_FOURCC('N','X','3','2'), + PX_MAKE_FOURCC('N','X','6','4'), +- PX_MAKE_FOURCC('L','A','6','4') ++ PX_MAKE_FOURCC('L','A','6','4'), ++ PX_MAKE_FOURCC('L','R','6','4') + }; + + const char* sBinaryPlatformNames[SN_NUM_BINARY_PLATFORMS] = +@@ -62,7 +63,8 @@ + "mac64", + "switch32", + "switch64", +- "linuxaarch64" ++ "linuxaarch64", ++ "linuxriscv64" + }; + + } +@@ -88,7 +90,9 @@ + #elif PX_SWITCH && PX_A64 + return sBinaryPlatformTags[7]; + #elif PX_LINUX && PX_A64 + return sBinaryPlatformTags[8]; ++#elif PX_LINUX && PX_RISCV64 ++ return sBinaryPlatformTags[9]; + #else + #error Unknown binary platform + #endif +-- +2.50.1 diff --git a/patches/sapien/3.0.3/0003-physx-cmake-extend-aarch64-warning-relaxation-to-riscv64.patch b/patches/sapien/3.0.3/0003-physx-cmake-extend-aarch64-warning-relaxation-to-riscv64.patch new file mode 100644 index 000000000000..dd5a6b027174 --- /dev/null +++ b/patches/sapien/3.0.3/0003-physx-cmake-extend-aarch64-warning-relaxation-to-riscv64.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ludovic Henry +Date: Thu, 15 Oct 2026 00:00:00 +0000 +Subject: [PATCH] physx/cmake: extend aarch64 warning relaxation to riscv64 + +Upstream-Status: To upstream [no riscv64 CI to validate against yet] + +source/compiler/cmake/linux/CMakeLists.txt treats aarch64 as the only +non-x86_64 Linux target: every other CMAKE_SYSTEM_PROCESSOR (including +riscv64, once it reaches this file at all via TARGET_BUILD_PLATFORM= +linux) falls into the plain ELSE() branch, which turns on `-Werror` +with an exclude list tuned for x86_64 GCC/Clang. aarch64 instead gets +`-Wno-error` plus `-ffp-contract=off` (floating-point-contraction +differences were already flagged as a real behavioural risk on that +arch). A brand new GCC target is virtually guaranteed to trip at least +one warning this x86_64 exclude list doesn't cover, so extend the +aarch64 branch's condition to riscv64 too rather than exposing a new +arch to -Werror untested. + +Signed-off-by: Ludovic Henry +--- + physx/source/compiler/cmake/linux/CMakeLists.txt | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/physx/source/compiler/cmake/linux/CMakeLists.txt b/physx/source/compiler/cmake/linux/CMakeLists.txt +index 0000000..0000000 100644 +--- a/physx/source/compiler/cmake/linux/CMakeLists.txt ++++ b/physx/source/compiler/cmake/linux/CMakeLists.txt +@@ -76,7 +76,7 @@ SET(CLANG_WARNINGS "-ferror-limit=0 -Wall -Wextra -Werror -Wstrict-aliasing=2 + ") + + +-IF(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64") ++IF(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64") + # gwoolery: disable warnings as errors for now on aarch64 linux. Most, but not all warnings, would be caught by: + # -Wno-invalid-offsetof -Wno-unused-result -Wno-unused-variable -Wno-uninitialized -Wno-unused-but-set-variable + # -Wno-unused-function -Wno-conversion-null -Wno-deprecated-declarations +-- +2.50.1 diff --git a/patches/sapien/3.0.3/0004-cmake-skip-cuda-language-on-riscv64.patch b/patches/sapien/3.0.3/0004-cmake-skip-cuda-language-on-riscv64.patch new file mode 100644 index 000000000000..2895a4dba7f9 --- /dev/null +++ b/patches/sapien/3.0.3/0004-cmake-skip-cuda-language-on-riscv64.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ludovic Henry +Date: Thu, 15 Oct 2026 00:00:00 +0000 +Subject: [PATCH] cmake: skip CUDA language on riscv64 + +Upstream-Status: To upstream [no riscv64 CI to validate against yet] + +The top-level project() call enables CMake's CUDA language on every +platform except APPLE, independent of the runtime SAPIEN_CUDA option +(setup.py sets -DSAPIEN_CUDA=OFF when CUDA_PATH is unset, but that +cache variable isn't read until after project() already ran). +Enabling the CUDA language makes CMake require a CUDA compiler at +configure time even when SAPIEN_CUDA will end up OFF, which fails +outright on riscv64 runners with no CUDA toolkit. aarch64 wheels are +built with CUDA on via the sbsa toolkit (Jetson/Grace), so this isn't +an aarch64-style fix -- it needs the same treatment as macOS, which +never had a CUDA story either. + +Signed-off-by: Ludovic Henry +--- + CMakeLists.txt | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 0000000..0000000 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -1,5 +1,5 @@ + cmake_minimum_required(VERSION 3.18 FATAL_ERROR) +-if (APPLE) ++if (APPLE OR CMAKE_SYSTEM_PROCESSOR MATCHES "riscv64") + project(sapien LANGUAGES C CXX) + else() + project(sapien LANGUAGES C CXX CUDA) +-- +2.50.1 diff --git a/patches/sapien/3.0.3/0005-cmake-physx5-add-riscv64-library-path.patch b/patches/sapien/3.0.3/0005-cmake-physx5-add-riscv64-library-path.patch new file mode 100644 index 000000000000..64fe118d83d7 --- /dev/null +++ b/patches/sapien/3.0.3/0005-cmake-physx5-add-riscv64-library-path.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ludovic Henry +Date: Thu, 15 Oct 2026 00:00:00 +0000 +Subject: [PATCH] cmake/physx5: add riscv64 library path + +Upstream-Status: Inappropriate [riseproject.dev builds PhysX from source for riscv64 rather than fetching a precompiled archive] + +cmake/physx5.cmake only fetches a precompiled PhysX archive; there is +no riscv64 archive (sapien-sim/physx-precompiled publishes macOS, +linux-aarch64, linux x86_64 and windows only). We build PhysX from +source instead and point SAPIEN_PHYSX5_DIR at the install tree, which +this file already supports via `IS_DIRECTORY ${SAPIEN_PHYSX5_DIR}` -- +skipping the FetchContent branch entirely. What's missing is the +arch-selection block below it that picks which `bin/linux./...` +subdirectory to link against: riscv64 would silently fall into the +x86_64-labeled `bin/linux.clang/release` bucket (the plain ELSE()). +Give it its own `bin/linux.riscv64/release` bucket instead, and make +our from-source PhysX build (build-sapien.yml) install into that +exact path. + +Signed-off-by: Ludovic Henry +--- + cmake/physx5.cmake | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/cmake/physx5.cmake b/cmake/physx5.cmake +index 0000000..0000000 100644 +--- a/cmake/physx5.cmake ++++ b/cmake/physx5.cmake +@@ -68,6 +68,8 @@ elseif(UNIX) + + if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|arm64") + target_link_directories(physx5 INTERFACE $) ++ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "riscv64") ++ target_link_directories(physx5 INTERFACE $) + else() + if (CMAKE_BUILD_TYPE STREQUAL "Debug") + target_link_directories(physx5 INTERFACE $) +-- +2.50.1 diff --git a/patches/sapien/3.0.3/0006-setup.py-plumb-sapien_physx5_dir.patch b/patches/sapien/3.0.3/0006-setup.py-plumb-sapien_physx5_dir.patch new file mode 100644 index 000000000000..0b42449acb59 --- /dev/null +++ b/patches/sapien/3.0.3/0006-setup.py-plumb-sapien_physx5_dir.patch @@ -0,0 +1,60 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ludovic Henry +Date: Thu, 15 Oct 2026 00:00:00 +0000 +Subject: [PATCH] setup.py: plumb SAPIEN_PHYSX5_DIR + +Upstream-Status: Inappropriate [riseproject.dev-specific: lets the from-source riscv64 PhysX build feed cmake/physx5.cmake's SAPIEN_PHYSX5_DIR cache variable] + +cmake/physx5.cmake already reads SAPIEN_PHYSX5_DIR as a cache variable +(it's how a prebuilt PhysX install overrides the FetchContent +download), but setup.py never threads anything into it -- there is no +CLI flag and no environment variable read anywhere in the file. Add +--physx5-dir (falling back to the SAPIEN_PHYSX5_DIR environment +variable, so CI can just export it) and pass it through as +-DSAPIEN_PHYSX5_DIR=... on both cmake invocations: build_sapien() +(where physx5 is actually linked) and CMakeBuild.build_pybind() (kept +in sync for consistency, even though the pybind step only needs +sapien_DIR from the already-built install). + +Signed-off-by: Ludovic Henry +--- + setup.py | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/setup.py b/setup.py +index 0000000..0000000 100644 +--- a/setup.py ++++ b/setup.py +@@ -32,6 +32,12 @@ + help="directory to put build files", + ) + parser.add_argument( ++ "--physx5-dir", ++ type=str, ++ default=os.environ.get("SAPIEN_PHYSX5_DIR", ""), ++ help="directory containing a prebuilt PhysX 5 install (also read from SAPIEN_PHYSX5_DIR)", ++) ++parser.add_argument( + "--get-version", + action="store_true", + help="print version string and exit immediately", +@@ -131,6 +137,8 @@ + cmake_args += ["-DSAPIEN_CUDA=ON"] + else: + cmake_args += ["-DSAPIEN_CUDA=OFF"] ++ if args.physx5_dir: ++ cmake_args += [f"-DSAPIEN_PHYSX5_DIR={args.physx5_dir}"] + + cmake_args += [ + f"-DCMAKE_BUILD_TYPE={cfg}", +@@ -257,6 +265,8 @@ + cmake_args += [ + "-Dsapien_DIR=" + os.path.join(sapien_install_dir, "lib/cmake/sapien") + ] ++ if args.physx5_dir: ++ cmake_args += [f"-DSAPIEN_PHYSX5_DIR={args.physx5_dir}"] + + if platform.system() == "Darwin": + cmake_args += ["-DCMAKE_TOOLCHAIN_FILE=../toolchains/macos.toolchain.cmake"] +-- +2.50.1 diff --git a/patches/sapien/3.0.3/0007-svulkan2-openvr-add-riscv64-branch.patch b/patches/sapien/3.0.3/0007-svulkan2-openvr-add-riscv64-branch.patch new file mode 100644 index 000000000000..6da2c7c36e9f --- /dev/null +++ b/patches/sapien/3.0.3/0007-svulkan2-openvr-add-riscv64-branch.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ludovic Henry +Date: Thu, 15 Oct 2026 00:00:00 +0000 +Subject: [PATCH] svulkan2/openvr: add riscv64 branch + +Upstream-Status: Inappropriate [riscv64 build infra detail, out of scope for the comoco-xiao/openvr fork sapien-vulkan-2 pins] + +openvr's own CMakeLists.txt picks -DLINUXARM64 only for +CMAKE_SYSTEM_PROCESSOR=="aarch64" and otherwise -DLINUX64 for any +other 64-bit unix target, so riscv64 silently takes the x86_64-labeled +branch today. openvr_api is linked into svulkan2 but only exercised +with real VR hardware, which none of our runners have, so this is +unlikely to matter in practice -- added anyway for correctness rather +than leaving riscv64 mislabeled as LINUX64 in a dependency we vendor. + +We don't control the comoco-xiao/openvr fork directly (it's fetched +fresh via FetchContent at configure time, not vendored in this repo), +so patch cmake/openvr.cmake's FetchContent_Declare to add a +PATCH_COMMAND that rewrites the one line in its CMakeLists.txt right +after the source is populated. + +Signed-off-by: Ludovic Henry +--- + 3rd_party/sapien-vulkan-2/cmake/openvr.cmake | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/3rd_party/sapien-vulkan-2/cmake/openvr.cmake b/3rd_party/sapien-vulkan-2/cmake/openvr.cmake +index 0000000..0000000 100644 +--- a/3rd_party/sapien-vulkan-2/cmake/openvr.cmake ++++ b/3rd_party/sapien-vulkan-2/cmake/openvr.cmake +@@ -5,6 +5,15 @@ + GIT_TAG v0.0.1 + GIT_SHALLOW TRUE + GIT_PROGRESS TRUE ++ PATCH_COMMAND python3 -c [[ ++import pathlib ++p = pathlib.Path("CMakeLists.txt") ++s = p.read_text() ++old = 'elseif(PROCESSOR_ARCH MATCHES "64")' ++new = 'elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "riscv64")\n add_definitions(-DLINUXRISCV64)\n elseif(PROCESSOR_ARCH MATCHES "64")' ++assert old in s ++p.write_text(s.replace(old, new, 1)) ++]] + ) + + # FetchContent_MakeAvailable(openvr) +-- +2.50.1 From 9f1d8810df857a0cd1e85df2c8b378ab352d1ec5 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Sun, 25 Oct 2026 17:59:19 +0000 Subject: [PATCH 2/2] sapien: fix PhysX cmake build by setting PX_OUTPUT_LIB_DIR/PX_OUTPUT_BIN_DIR PhysX's NvidiaBuildOptions.cmake hard-requires PX_OUTPUT_LIB_DIR and PX_OUTPUT_BIN_DIR to be defined (its GameWorks output structure), else it fails with a CMake FATAL_ERROR before configuration completes. The riscv64 PhysX cmake invocation was missing both, causing the build job to fail immediately during PhysX configure. Upstream's own buildtools/cmake_generate_projects.py always passes both, pointed at PHYSX_ROOT_DIR, so the find/cp step right after that expects libraries under /physx-src/physx/bin/... works as intended. --- .github/workflows/build-sapien.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build-sapien.yml b/.github/workflows/build-sapien.yml index ed0934a7e0b3..c868adab628c 100644 --- a/.github/workflows/build-sapien.yml +++ b/.github/workflows/build-sapien.yml @@ -153,6 +153,8 @@ jobs: cmake -S /physx-src/physx/compiler/public -B /tmp/physx_build -G Ninja \ -DTARGET_BUILD_PLATFORM=linux \ -DPHYSX_ROOT_DIR=/physx-src/physx \ + -DPX_OUTPUT_LIB_DIR=/physx-src/physx \ + -DPX_OUTPUT_BIN_DIR=/physx-src/physx \ -DPX_GENERATE_STATIC_LIBRARIES=1 \ -DPX_BUILDSNIPPETS=0 \ -DPX_BUILDPVDRUNTIME=0 \