From 886197b2e7add31fda81e3be2aa7978fcdadb4e7 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Thu, 15 Oct 2026 04:45:49 +0000 Subject: [PATCH 1/8] quadrants: port to riscv64 Genesis-AI's fork of taichi: a scikit-build-core C++ compiler with an LLVM JIT CPU backend. Compared with the parked taichi entry, two of taichi's three walls are gone here: quadrants targets LLVM 22.1.0 (opaque pointers; RuntimeDyldELF has real RISC-V relocation handling since LLVM 20, confirmed directly against llvmorg-22.1.0 source: 42 riscv hits, a real resolveRISCVRelocation()) and finds clang via clang-22/21/20. The remaining wall is quadrants having no riscv64 CPU arch and no riscv64 LLVM to build against: - patches/quadrants/1.3.3/0001 adds a riscv64 CPU arch alongside x64/arm64 everywhere they're handled (CXXFlags, the arch enum, rhi/arch.cpp, and four scattered "is this a CPU arch" checks in the LLVM codegen/transforms). - 0002/0003 patch the CI build scripts: no riscv64 LLVM/sccache release exists to download, so setup_llvm() expects LLVM_DIR to already point at the LLVM we build ourselves, setup_sccache() no-ops (ccache from the manylinux image covers it instead), CUDA/ AMDGPU/Vulkan (no riscv64 backend for any of them) are turned off, and the dev dependency group is trimmed to what the build actually needs (full --group dev pulls pyright, which has no riscv64 wheel or sdist). build-quadrants.yml builds LLVM+clang 22.1.0 from source once (RISCV target only, matching build-libclang.yml's from-source precedent but also linking OrcJIT/ExecutionEngine/RuntimeDyld, which libclang.so doesn't need), then reuses it across the cp310/cp311/cp312/cp313 matrix - mirroring upstream's own manylinux_wheel.yml scripts (1_prerequisites.sh/2_build.sh/3_check.sh) almost verbatim, pointed at our own LLVM instead of their quadrants-sdk-builds releases. GCC (not our built clang) still compiles the bulk of the project, same as upstream; clang only compiles the LLVM JIT's runtime.cpp bitcode, and the main library links the static LLVM libraries GCC-side, which is an ordinary cross-compiler-ABI link on Linux. No gpl_sources job: the build doesn't statically link libstdc++ into the wheel (that flag is MinGW-only in QuadrantsCXXFlags.cmake), and glibc-based manylinux auditwheel doesn't bundle it either. --- .github/workflows/build-quadrants.yml | 169 ++++++++++++++++ docs/packages/quadrants.yaml | 5 + .../1.3.3/0001-Add-a-riscv64-CPU-arch.patch | 181 ++++++++++++++++++ ...LLVM-sccache-manylinux-build-scripts.patch | 112 +++++++++++ ...up-install-and-drop-submodule-reinit.patch | 68 +++++++ 5 files changed, 535 insertions(+) create mode 100644 .github/workflows/build-quadrants.yml create mode 100644 docs/packages/quadrants.yaml create mode 100644 patches/quadrants/1.3.3/0001-Add-a-riscv64-CPU-arch.patch create mode 100644 patches/quadrants/1.3.3/0002-CI-support-riscv64-in-the-LLVM-sccache-manylinux-build-scripts.patch create mode 100644 patches/quadrants/1.3.3/0003-CI-trim-riscv64-dev-group-install-and-drop-submodule-reinit.patch diff --git a/.github/workflows/build-quadrants.yml b/.github/workflows/build-quadrants.yml new file mode 100644 index 000000000000..03ea1f48f10b --- /dev/null +++ b/.github/workflows/build-quadrants.yml @@ -0,0 +1,169 @@ +# SPDX-FileCopyrightText: 2026 The RISE Project +# SPDX-License-Identifier: MIT +# +# This workflow is based on: https://github.com/Genesis-Embodied-AI/quadrants/blob/v1.3.3/.github/workflows/manylinux_wheel.yml +name: Build quadrants wheels (riscv64) + +on: + workflow_dispatch: + inputs: + version: + description: 'Version glob to (re)build; empty builds every version of docs/packages/quadrants.yaml not released yet' + required: false + default: '' + pull_request: + branches: [main] + paths: + - '.github/workflows/build-quadrants.yml' + - 'docs/packages/quadrants.yaml' + - 'patches/quadrants/**' + push: + branches: [main] + paths: + - '.github/workflows/build-quadrants.yml' + - 'docs/packages/quadrants.yaml' + - 'patches/quadrants/**' + +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 + LLVM_VERSION: 22.1.0 + +jobs: + setup: + uses: $/.github/workflows/_setup.yml + with: + package: quadrants + version: ${{ inputs.version }} + + build_llvm: + needs: [setup] + if: needs.setup.outputs.versions != '[]' + name: Build LLVM ${{ env.LLVM_VERSION }} for quadrants (riscv64) + runs-on: ubuntu-24.04-riscv + container: ${{ env.MANYLINUX_RISCV64_IMAGE }} + timeout-minutes: 1440 # full LLVM+clang compile from source + + steps: + # quadrants-sdk-builds (download_llvm.py's own release bucket) ships no riscv64 LLVM; + # build LLVM+clang 22.1.0 ourselves with only the RISCV target and the components + # quadrants's QuadrantsCore.cmake links (Core/ExecutionEngine/OrcJIT/RuntimeDyld/...). + # No CUDA/AMDGPU/Vulkan backend exists for riscv64 (patches/quadrants disables them), so + # NVPTX/AMDGPU targets are left out too. + - name: Build and install LLVM+clang + run: | + set -euxo pipefail + dnf -y install ninja-build lld + curl -fsSL -o llvm-project.src.tar.xz \ + "https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VERSION}/llvm-project-${LLVM_VERSION}.src.tar.xz" + tar xf llvm-project.src.tar.xz + cmake -S "llvm-project-${LLVM_VERSION}.src/llvm" -B build -G Ninja \ + -DLLVM_ENABLE_PROJECTS=clang \ + -DLLVM_TARGETS_TO_BUILD=RISCV \ + -DBUILD_SHARED_LIBS=OFF \ + -DLLVM_ENABLE_ZLIB=OFF \ + -DLLVM_ENABLE_ZSTD=OFF \ + -DLLVM_ENABLE_TERMINFO=OFF \ + -DLLVM_ENABLE_LIBXML2=OFF \ + -DLLVM_INCLUDE_TESTS=OFF \ + -DLLVM_INCLUDE_EXAMPLES=OFF \ + -DLLVM_INCLUDE_BENCHMARKS=OFF \ + -DLLVM_USE_LINKER=lld \ + -DLLVM_PARALLEL_LINK_JOBS=1 \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX="$(pwd)/llvm-install" + cmake --build build --target install -j"$(nproc)" + tar czf llvm-install.tar.gz llvm-install + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: quadrants-llvm-${{ env.LLVM_VERSION }}-riscv64 + path: llvm-install.tar.gz + if-no-files-found: error + retention-days: 1 + + build_wheels: + needs: [setup, build_llvm] + if: needs.setup.outputs.versions != '[]' + strategy: + fail-fast: false + matrix: + version: ${{ fromJSON(needs.setup.outputs.versions) }} + python: ["cp310", "cp311", "cp312", "cp313"] + name: Build quadrants ${{ matrix.version }} ${{ matrix.python }}-manylinux_riscv64 + runs-on: ubuntu-24.04-riscv + container: ${{ env.MANYLINUX_RISCV64_IMAGE }} + timeout-minutes: 360 + + env: + QUADRANTS_VERSION: ${{ matrix.version }} + PIP_EXTRA_INDEX_URL: https://pypi.riseproject.dev/simple/ + + steps: + - name: Checkout quadrants v${{ env.QUADRANTS_VERSION }} + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + repository: Genesis-Embodied-AI/quadrants + ref: v${{ env.QUADRANTS_VERSION }} + submodules: recursive + persist-credentials: false + + - name: Checkout python-wheels + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + path: python-wheels + persist-credentials: false + + - name: Patch quadrants source + run: git apply python-wheels/patches/quadrants/${{ env.QUADRANTS_VERSION }}/*.patch + + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: quadrants-llvm-${{ env.LLVM_VERSION }}-riscv64 + + - name: Unpack LLVM, select the interpreter + run: | + tar xzf llvm-install.tar.gz + echo "LLVM_DIR=$(pwd)/llvm-install" >> "$GITHUB_ENV" + echo "/opt/python/${{ matrix.python }}-${{ matrix.python }}/bin" >> "$GITHUB_PATH" + + - name: Build and check wheel + run: | + bash .github/workflows/scripts_new/manylinux_wheel/1_prerequisites.sh + bash .github/workflows/scripts_new/manylinux_wheel/2_build.sh + bash .github/workflows/scripts_new/manylinux_wheel/3_check.sh + + - name: Smoke-test wheel + run: | + rm -f dist/*.whl + cp wheelhouse/*.whl dist/ + bash .github/workflows/scripts_new/manylinux_wheel/4_install_wheel.sh + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: quadrants-${{ matrix.version }}-${{ matrix.python }}-manylinux_riscv64 + path: wheelhouse/*.whl + if-no-files-found: error + + publish: + name: Publish quadrants ${{ 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: quadrants-${{ matrix.version }}-*-manylinux_riscv64 diff --git a/docs/packages/quadrants.yaml b/docs/packages/quadrants.yaml new file mode 100644 index 000000000000..af00d984a3ff --- /dev/null +++ b/docs/packages/quadrants.yaml @@ -0,0 +1,5 @@ +package-name: quadrants +source-code: https://github.com/Genesis-Embodied-AI/quadrants +license: Apache-2.0 +versions: +- version: 1.3.3 diff --git a/patches/quadrants/1.3.3/0001-Add-a-riscv64-CPU-arch.patch b/patches/quadrants/1.3.3/0001-Add-a-riscv64-CPU-arch.patch new file mode 100644 index 000000000000..0d6d2c26de75 --- /dev/null +++ b/patches/quadrants/1.3.3/0001-Add-a-riscv64-CPU-arch.patch @@ -0,0 +1,181 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: RISE Project CI +Date: Thu, 15 Oct 2026 00:00:00 +0000 +Subject: [PATCH] Add a riscv64 CPU arch + +Quadrants' CPU-arch enum (quadrants/inc/archs.inc.h) only lists x64 and +arm64; cmake/QuadrantsCXXFlags.cmake FATAL_ERRORs on any other +CMAKE_SYSTEM_PROCESSOR, and rhi/arch.cpp's host_arch()/ +default_simd_width()/arch_is_cpu()/arch_uses_llvm() hit +RHI_NOT_IMPLEMENTED or silently exclude riscv64 from the CPU-backend +checks scattered through the LLVM codegen (program/extension.cpp, +runtime/llvm/llvm_context.cpp, runtime/llvm/adstack_lazy_claim/ +bound_eval.cpp, transforms/make_mesh_block_local.cpp). Add a riscv64 +case everywhere x64/arm64 are handled as CPU archs, so the LLVM CPU +JIT backend (orc::RTDyldObjectLinkingLayer on Linux) is reachable on +riscv64. default_simd_width() uses 4, matching arm64's conservative +choice since RV64GC has no fixed-width SIMD without RVV. The nanobind +enum binding in quadrants/python/export_lang.cpp regenerates from +archs.inc.h via the same PER_ARCH macro, so quadrants.riscv64 needs no +separate binding. + +Upstream-Status: To upstream + +Signed-off-by: RISE Project CI +--- + cmake/QuadrantsCXXFlags.cmake | 5 ++++- + quadrants/inc/archs.inc.h | 1 + + quadrants/program/extension.cpp | 3 +++ + quadrants/rhi/arch.cpp | 11 +++++++++-- + .../runtime/llvm/adstack_lazy_claim/bound_eval.cpp | 2 +- + quadrants/runtime/llvm/llvm_context.cpp | 2 +- + quadrants/transforms/make_mesh_block_local.cpp | 6 +++--- + 7 files changed, 22 insertions(+), 8 deletions(-) + +diff --git a/cmake/QuadrantsCXXFlags.cmake b/cmake/QuadrantsCXXFlags.cmake +index e4eb937..c78fbab 100644 +--- a/cmake/QuadrantsCXXFlags.cmake ++++ b/cmake/QuadrantsCXXFlags.cmake +@@ -132,12 +132,15 @@ elseif ("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "aarch64" OR "${CMAKE_SYSTEM_PROCES + elseif ("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQD_ARCH_x86") + set(ARCH "x86") ++elseif ("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "riscv64") ++ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQD_ARCH_riscv64") ++ set(ARCH "riscv64") + else() + message(FATAL_ERROR "Unknown processor type ${CMAKE_SYSTEM_PROCESSOR}") + endif() + set(HOST_ARCH ${ARCH} CACHE INTERNAL "Host arch") + +-if (LINUX AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64") ++if (LINUX AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|riscv64)$") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -latomic") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -latomic") + endif() +diff --git a/quadrants/inc/archs.inc.h b/quadrants/inc/archs.inc.h +index 919673a..7b60fa6 100644 +--- a/quadrants/inc/archs.inc.h ++++ b/quadrants/inc/archs.inc.h +@@ -3,6 +3,7 @@ + // CPU archs + PER_ARCH(x64) // a.k.a. AMD64/x86_64 + PER_ARCH(arm64) // a.k.a. Aarch64, WIP ++PER_ARCH(riscv64) // RV64GC + PER_ARCH(js) // Javascript, N/A + PER_ARCH(python) // Python + +diff --git a/quadrants/program/extension.cpp b/quadrants/program/extension.cpp +index 9a51bc2..90cf6cc 100644 +--- a/quadrants/program/extension.cpp ++++ b/quadrants/program/extension.cpp +@@ -13,6 +13,9 @@ bool is_extension_supported(Arch arch, Extension ext) { + {Arch::arm64, + {Extension::sparse, Extension::quant, Extension::quant_basic, Extension::data64, Extension::adstack, + Extension::assertion, Extension::mesh}}, ++ {Arch::riscv64, ++ {Extension::sparse, Extension::quant, Extension::quant_basic, Extension::data64, Extension::adstack, ++ Extension::assertion, Extension::mesh}}, + {Arch::cuda, + {Extension::sparse, Extension::quant, Extension::quant_basic, Extension::data64, Extension::adstack, + Extension::bls, Extension::assertion, Extension::mesh}}, +diff --git a/quadrants/rhi/arch.cpp b/quadrants/rhi/arch.cpp +index b9a4822..db48549 100644 +--- a/quadrants/rhi/arch.cpp ++++ b/quadrants/rhi/arch.cpp +@@ -39,7 +39,8 @@ Arch arch_from_name(const std::string &arch_name) { + + // Assuming a processor is either a CPU or a GPU. DSP/TPUs not considered. + bool arch_is_cpu(Arch arch) { +- if (arch == Arch::x64 || arch == Arch::arm64 || arch == Arch::js || arch == Arch::python) { ++ if (arch == Arch::x64 || arch == Arch::arm64 || arch == Arch::riscv64 || arch == Arch::js || ++ arch == Arch::python) { + return true; + } else { + return false; +@@ -59,7 +60,8 @@ bool arch_is_metal(Arch arch) { + } + + bool arch_uses_llvm(Arch arch) { +- return (arch == Arch::x64 || arch == Arch::arm64 || arch == Arch::cuda || arch == Arch::amdgpu); ++ return (arch == Arch::x64 || arch == Arch::arm64 || arch == Arch::riscv64 || arch == Arch::cuda || ++ arch == Arch::amdgpu); + } + + bool arch_is_gpu(Arch arch) { +@@ -76,6 +78,9 @@ Arch host_arch() { + #endif + #if defined(QD_ARCH_ARM) + return Arch::arm64; ++#endif ++#if defined(QD_ARCH_riscv64) ++ return Arch::riscv64; + #endif + RHI_NOT_IMPLEMENTED + } +@@ -91,6 +96,8 @@ int default_simd_width(Arch arch) { + return 32; + } else if (arch == Arch::arm64) { + return 4; ++ } else if (arch == Arch::riscv64) { ++ return 4; + } else { + RHI_NOT_IMPLEMENTED; + return -1; +diff --git a/quadrants/runtime/llvm/adstack_lazy_claim/bound_eval.cpp b/quadrants/runtime/llvm/adstack_lazy_claim/bound_eval.cpp +index 0b62054..4849e62 100644 +--- a/quadrants/runtime/llvm/adstack_lazy_claim/bound_eval.cpp ++++ b/quadrants/runtime/llvm/adstack_lazy_claim/bound_eval.cpp +@@ -38,7 +38,7 @@ uint32_t LlvmRuntimeExecutor::publish_per_task_bound_count_cpu(std::size_t task_ + // Default to UINT32_MAX (no clamp); only override on a successful host evaluation. The codegen-emitted bounds clamp + // at the float LCA-block claim site stays inert when the slot holds UINT32_MAX, so this fall-through is a no-op that + // preserves the existing behaviour. +- if (config_.arch != Arch::x64 && config_.arch != Arch::arm64) { ++ if (config_.arch != Arch::x64 && config_.arch != Arch::arm64 && config_.arch != Arch::riscv64) { + return std::numeric_limits::max(); + } + if (!ad_stack.bound_expr.has_value()) { +diff --git a/quadrants/runtime/llvm/llvm_context.cpp b/quadrants/runtime/llvm/llvm_context.cpp +index d116503..ef7070c 100644 +--- a/quadrants/runtime/llvm/llvm_context.cpp ++++ b/quadrants/runtime/llvm/llvm_context.cpp +@@ -725,7 +725,7 @@ std::unique_ptr QuadrantsLLVMContext::module_from_file(const std:: + } + + // CPU-specific intrinsics +- if (arch_ == Arch::x64 || arch_ == Arch::arm64) { ++ if (arch_ == Arch::x64 || arch_ == Arch::arm64 || arch_ == Arch::riscv64) { + auto func = module->getFunction("cpu_clock_i64"); + if (func) { + func->deleteBody(); +diff --git a/quadrants/transforms/make_mesh_block_local.cpp b/quadrants/transforms/make_mesh_block_local.cpp +index 69d713f..60724b0 100644 +--- a/quadrants/transforms/make_mesh_block_local.cpp ++++ b/quadrants/transforms/make_mesh_block_local.cpp +@@ -110,7 +110,7 @@ void MakeMeshBlockLocal::replace_global_ptrs(SNode *snode) { + } + + // in the cpu backend, atomic op in body block could be demoted to non-atomic +- if (config_.arch != Arch::x64 && config_.arch != Arch::arm64) { ++ if (config_.arch != Arch::x64 && config_.arch != Arch::arm64 && config_.arch != Arch::riscv64) { + return; + } + std::vector atomic_ops; +@@ -144,7 +144,7 @@ Stmt *MakeMeshBlockLocal::create_xlogue(Stmt *start_val, + Stmt *idx = block_->push_back(mapping_data_type_); + [[maybe_unused]] Stmt *init_val = block_->push_back(idx, start_val); + Stmt *block_dim_val; +- if (config_.arch == Arch::x64 || config_.arch == Arch::arm64) { ++ if (config_.arch == Arch::x64 || config_.arch == Arch::arm64 || config_.arch == Arch::riscv64) { + block_dim_val = block_->push_back(TypedConstant(1)); + } else { + block_dim_val = block_->push_back(TypedConstant{offload_->block_dim}); +@@ -272,7 +272,7 @@ void MakeMeshBlockLocal::fetch_mapping( + std::function)> mapping_callback_handler, + std::function attr_callback_handler) { + Stmt *thread_idx_stmt; +- if (config_.arch == Arch::x64 || config_.arch == Arch::arm64) { ++ if (config_.arch == Arch::x64 || config_.arch == Arch::arm64 || config_.arch == Arch::riscv64) { + thread_idx_stmt = block_->push_back(TypedConstant(0)); + } else { + thread_idx_stmt = block_->push_back(offload_); // Equivalent to CUDA threadIdx diff --git a/patches/quadrants/1.3.3/0002-CI-support-riscv64-in-the-LLVM-sccache-manylinux-build-scripts.patch b/patches/quadrants/1.3.3/0002-CI-support-riscv64-in-the-LLVM-sccache-manylinux-build-scripts.patch new file mode 100644 index 000000000000..9f267451d12d --- /dev/null +++ b/patches/quadrants/1.3.3/0002-CI-support-riscv64-in-the-LLVM-sccache-manylinux-build-scripts.patch @@ -0,0 +1,112 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: RISE Project CI +Date: Thu, 15 Oct 2026 00:05:00 +0000 +Subject: [PATCH] CI: support riscv64 in the LLVM/sccache/manylinux build + scripts + +quadrants-sdk-builds (the GitHub release bucket .github/workflows/ +scripts/qd_build/llvm.py downloads a prebuilt LLVM 22.1.0 from) ships +only linux-x86_64/linux-aarch64/macos-arm64/windows-amd64 archives, and +mozilla/sccache's v0.10.0 release has no riscv64 binary either. On +riscv64, setup_llvm() now expects the caller to build LLVM+clang 22.1.0 +itself and export LLVM_DIR before build.py runs, and setup_sccache() +skips the compiler-launcher wrapping instead of trying to download a +binary that doesn't exist (CMakeLists.txt's own find_program(ccache) +still caches the per-interpreter rebuilds when the image has ccache +installed). + +scripts_new/manylinux_wheel/2_build.sh's PLATFORM allowlist rejects +every arch but x86_64/aarch64; add riscv64. There is no riscv64 +CUDA/AMDGPU/Vulkan backend (the LLVM CPU JIT is the only backend +riscv64 has), so turn those three off instead of upstream's CI default +of on, and skip QD_BUILD_TESTS (a CPU-only riscv64 leg doesn't need +the GPU-aware cpp test binary) and the gcc-toolset-14 include-path +workaround (that SCL package is x86_64/aarch64-only on the manylinux +images; riscv64 needs no such workaround since it only ever uses the +clang we ourselves just built). + +Upstream-Status: Inappropriate [no riscv64 LLVM/sccache release exists to point at; this wires our own from-source riscv64 LLVM build in instead] + +Signed-off-by: RISE Project CI +--- + .github/workflows/scripts/qd_build/llvm.py | 7 +++++++ + .github/workflows/scripts/qd_build/sccache.py | 8 ++++++++ + .../scripts_new/manylinux_wheel/2_build.sh | 20 ++++++++++++------- + 3 files changed, 28 insertions(+), 7 deletions(-) + +diff --git a/.github/workflows/scripts/qd_build/llvm.py b/.github/workflows/scripts/qd_build/llvm.py +index dbb9891..487c487 100644 +--- a/.github/workflows/scripts/qd_build/llvm.py ++++ b/.github/workflows/scripts/qd_build/llvm.py +@@ -28,6 +28,13 @@ def setup_llvm() -> str: + ) + + match (u.system, u.machine): ++ case ("Linux", "riscv64"): ++ # quadrants-sdk-builds ships no riscv64 LLVM; the caller builds LLVM itself and ++ # points LLVM_DIR at the install prefix before this runs. ++ out = os.environ.get("LLVM_DIR") ++ if not out: ++ raise RuntimeError("LLVM_DIR must be set to a prebuilt LLVM install on riscv64") ++ return out + case ("Linux", "x86_64"): + out = get_cache_home() / f"llvm-{llvm_version}-x86-{build_version}" + url = release_url_template.format(platform="linux-x86_64") +diff --git a/.github/workflows/scripts/qd_build/sccache.py b/.github/workflows/scripts/qd_build/sccache.py +index b5561c7..cce2b1e 100644 +--- a/.github/workflows/scripts/qd_build/sccache.py ++++ b/.github/workflows/scripts/qd_build/sccache.py +@@ -30,6 +30,14 @@ def setup_sccache() -> Command: + else: + raise RuntimeError(f"Unsupported platform: {u.system} {u.machine}") + ++ if (u.system, u.machine) == ("Linux", "riscv64"): ++ # mozilla/sccache publishes no riscv64 binary (v0.10.0 release assets checked). Skip the ++ # compiler-launcher wrapping (entry.py's action_wheel still calls the returned command ++ # with --start-server / -s, so it must accept and ignore arbitrary args) and let ccache ++ # (installed from the manylinux image, found by CMakeLists.txt's own find_program) cache ++ # the per-interpreter rebuilds instead. ++ return sh.bake("true") ++ + if not exe.exists(): + if (u.system, u.machine) == ("Linux", "x86_64"): + url = "https://github.com/mozilla/sccache/releases/download/v0.10.0/sccache-v0.10.0-x86_64-unknown-linux-musl.tar.gz" +diff --git a/.github/workflows/scripts_new/manylinux_wheel/2_build.sh b/.github/workflows/scripts_new/manylinux_wheel/2_build.sh +index 3c030bb..3561a10 100644 +--- a/.github/workflows/scripts_new/manylinux_wheel/2_build.sh ++++ b/.github/workflows/scripts_new/manylinux_wheel/2_build.sh +@@ -3,7 +3,7 @@ + set -ex + + PLATFORM=$(uname -m) +-if [[ ! "$PLATFORM" =~ ^(x86_64|aarch64)$ ]]; then ++if [[ ! "$PLATFORM" =~ ^(x86_64|aarch64|riscv64)$ ]]; then + echo "Unsupported architecture: $PLATFORM" + exit 1 + fi +@@ -18,13 +18,19 @@ echo "Detected platform: $PLATFORM" + # Add Taichi LLVM toolchain to PATH + export PATH="$PWD/taichi-llvm-15.0.7-linux-${PLATFORM}/bin:$PATH" + +-# Taichi build options +-export CMAKE_ARGS="-DQD_WITH_VULKAN:BOOL=ON -DQD_WITH_CUDA:BOOL=ON -DQD_WITH_AMDGPU:BOOL=ON -DQD_BUILD_TESTS:BOOL=ON" ++if [[ "$PLATFORM" == "riscv64" ]]; then ++ # No riscv64 CUDA/AMDGPU/Vulkan backend exists; the LLVM CPU JIT is the only one riscv64 ++ # needs (gotcha "Add a riscv64 CPU arch" patch). ++ export CMAKE_ARGS="-DQD_WITH_VULKAN:BOOL=OFF -DQD_WITH_CUDA:BOOL=OFF -DQD_WITH_AMDGPU:BOOL=OFF -DQD_BUILD_TESTS:BOOL=OFF" ++else ++ # Taichi build options ++ export CMAKE_ARGS="-DQD_WITH_VULKAN:BOOL=ON -DQD_WITH_CUDA:BOOL=ON -DQD_WITH_AMDGPU:BOOL=ON -DQD_BUILD_TESTS:BOOL=ON" + +-# GCC toolset include paths +-inc_base="/opt/rh/gcc-toolset-14/root/usr/include/c++/14" +-extra="$inc_base:$inc_base/${PLATFORM}-redhat-linux:$inc_base/backward" ++ # GCC toolset include paths ++ inc_base="/opt/rh/gcc-toolset-14/root/usr/include/c++/14" ++ extra="$inc_base:$inc_base/${PLATFORM}-redhat-linux:$inc_base/backward" + +-export CPLUS_INCLUDE_PATH="${CPLUS_INCLUDE_PATH:+$CPLUS_INCLUDE_PATH:}$extra" ++ export CPLUS_INCLUDE_PATH="${CPLUS_INCLUDE_PATH:+$CPLUS_INCLUDE_PATH:}$extra" ++fi + + ./build.py wheel diff --git a/patches/quadrants/1.3.3/0003-CI-trim-riscv64-dev-group-install-and-drop-submodule-reinit.patch b/patches/quadrants/1.3.3/0003-CI-trim-riscv64-dev-group-install-and-drop-submodule-reinit.patch new file mode 100644 index 000000000000..19469741e348 --- /dev/null +++ b/patches/quadrants/1.3.3/0003-CI-trim-riscv64-dev-group-install-and-drop-submodule-reinit.patch @@ -0,0 +1,68 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: RISE Project CI +Date: Thu, 15 Oct 2026 00:10:00 +0000 +Subject: [PATCH] CI: trim riscv64's dev-group install and drop its submodule + re-init + +pyproject.toml's dev dependency group (installed wholesale by +1_prerequisites.sh) pulls in pyright, which ships no riscv64 wheel and +has no sdist to fall back to (it wraps a prebuilt Node binary per +platform) -- `pip install --group dev` has no partial-success mode, so +one unresolvable package fails the whole install. On riscv64, install +only what build.py's `pip wheel --no-build-isolation` actually needs: +build-system.requires (scikit-build-core, nanobind, numpy, +setuptools_scm), the cmake/ninja it drives them with, and +psutil/requests (qd_build's own non-stdlib imports). Install ccache +too: setup_sccache() (patched earlier) no-ops on riscv64, and +CMakeLists.txt's own find_program(ccache) is what caches the +per-interpreter rebuilds instead. + +The hardcoded `git config --global --add safe.directory +/__w/quadrants/quadrants` assumes upstream's own checkout path; our +workflow checks quadrants out under python-wheels' own job workspace, +not /__w/quadrants/quadrants, and actions/checkout already ran with +submodules: recursive, so the follow-up `git submodule update` is +both redundant and pointed at a path that doesn't exist here. Skip +both on riscv64. + +Upstream-Status: Inappropriate [riscv64 has no pyright wheel, and our workflow checks the repo out at a different path than upstream's own CI does] + +Signed-off-by: RISE Project CI +--- + .../manylinux_wheel/1_prerequisites.sh | 21 +++++++++++++++---- + 1 file changed, 17 insertions(+), 4 deletions(-) + +diff --git a/.github/workflows/scripts_new/manylinux_wheel/1_prerequisites.sh b/.github/workflows/scripts_new/manylinux_wheel/1_prerequisites.sh +index 03ca845..76157e2 100644 +--- a/.github/workflows/scripts_new/manylinux_wheel/1_prerequisites.sh ++++ b/.github/workflows/scripts_new/manylinux_wheel/1_prerequisites.sh +@@ -3,12 +3,25 @@ + set -ex + + pip install -U pip +-pip install --group dev ++if [[ "$(uname -m)" == "riscv64" ]]; then ++ # --group dev also pulls pyright, which ships no riscv64 wheel and no sdist to fall back ++ # to (it wraps a prebuilt Node binary); install only what `pip wheel --no-build-isolation` ++ # below actually needs: build.py's own [build-system].requires, plus the cmake/ninja it ++ # drives them with, plus psutil/requests (qd_build's own non-stdlib imports). ++ pip install "cmake<4.0.0" ninja "nanobind>=2.0.0,<2.14.0" "scikit-build-core>=0.10" \ ++ "setuptools_scm>=6.0" "numpy>=2.0.0" psutil requests ++ yum install -y ccache # setup_sccache() no-ops on riscv64; CMakeLists.txt's own ++ # find_program(ccache) picks this up as the compiler launcher instead. ++else ++ pip install --group dev ++fi + + yum install -y git wget +-# Note: following depends on the name of the repo: +-git config --global --add safe.directory /__w/quadrants/quadrants +-git submodule update --init --jobs 2 ++if [[ "$(uname -m)" != "riscv64" ]]; then ++ # Note: following depends on the name of the repo: ++ git config --global --add safe.directory /__w/quadrants/quadrants ++ git submodule update --init --jobs 2 ++fi + + LLVM_DIR=$(python download_llvm.py | tail -n 1) + export PATH=${LLVM_DIR}/bin:$PATH From ac6a6d82e4e7030db7587f6687a45b87d6239d0e Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Thu, 15 Oct 2026 04:50:02 +0000 Subject: [PATCH 2/8] build-quadrants.yml: fix job-level container/name using the env context jobs..container and jobs..name don't have the env context available (only github/needs/strategy/matrix/inputs/vars), so ${{ env.MANYLINUX_RISCV64_IMAGE }} in container: and ${{ env.LLVM_VERSION }} in a job name failed workflow validation outright (zero jobs scheduled, run marked failed). Hardcode the image literal in both container blocks, matching build-openmm.yml/build-syntaqlite.yml, and drop the now-unused MANYLINUX_RISCV64_IMAGE workflow env (LLVM_VERSION stays - run/with contexts do have env available). --- .github/workflows/build-quadrants.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-quadrants.yml b/.github/workflows/build-quadrants.yml index 03ea1f48f10b..4d95e5c79b12 100644 --- a/.github/workflows/build-quadrants.yml +++ b/.github/workflows/build-quadrants.yml @@ -32,7 +32,6 @@ permissions: contents: read env: - MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64 LLVM_VERSION: 22.1.0 jobs: @@ -45,9 +44,10 @@ jobs: build_llvm: needs: [setup] if: needs.setup.outputs.versions != '[]' - name: Build LLVM ${{ env.LLVM_VERSION }} for quadrants (riscv64) + name: Build LLVM 22.1.0 for quadrants (riscv64) runs-on: ubuntu-24.04-riscv - container: ${{ env.MANYLINUX_RISCV64_IMAGE }} + container: + image: quay.io/pypa/manylinux_2_39_riscv64 timeout-minutes: 1440 # full LLVM+clang compile from source steps: @@ -98,7 +98,8 @@ jobs: python: ["cp310", "cp311", "cp312", "cp313"] name: Build quadrants ${{ matrix.version }} ${{ matrix.python }}-manylinux_riscv64 runs-on: ubuntu-24.04-riscv - container: ${{ env.MANYLINUX_RISCV64_IMAGE }} + container: + image: quay.io/pypa/manylinux_2_39_riscv64 timeout-minutes: 360 env: From a938217c6638f5882c31d575c6641ac4981d0bbf Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Sun, 25 Oct 2026 18:01:05 +0000 Subject: [PATCH 3/8] patches/quadrants: pin cmake to the riscv64-wheel version we host All four riscv64 build legs (cp310-cp313) failed identically in 1_prerequisites.sh's `pip install "cmake<4.0.0" ...` with: -- Could NOT find OpenSSL ... CMake Error at Utilities/cmcurl/CMakeLists.txt:772 (message): Could not find OpenSSL. Install an OpenSSL development package ... ERROR: Failed building wheel for cmake With PIP_EXTRA_INDEX_URL set, pip resolves the highest version satisfying a constraint across both the public index and ours, and an sdist-only candidate still counts as resolvable. PyPI's cmake publishes no riscv64 wheel for any release (checked its JSON: only macOS/Windows/manylinux x86_64/aarch64/ppc64le/s390x/armv7l and musllinux), and the newest release under "<4.0.0" at the time of this PR, 3.31.10, is newer than the 3.31.6 we mirror -- so pip picked 3.31.10's sdist over our riscv64 wheel and tried to build CMake itself from source, which fails configuring its bundled cmcurl for lack of OpenSSL dev headers in the manylinux_riscv64 image. Pin to "cmake==3.31.6", the exact version docs/packages/cmake.yaml publishes a manylinux_2_39_riscv64 wheel for (same fix shape as patches/ouster-sdk/1.0.1/0002-build-use-a-cmake-release-with-a-riscv64-wheel.patch, the porting skill's gotcha 30: "the version has to line up, not just the name"). --- ...up-install-and-drop-submodule-reinit.patch | 36 ++++++++++++++----- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/patches/quadrants/1.3.3/0003-CI-trim-riscv64-dev-group-install-and-drop-submodule-reinit.patch b/patches/quadrants/1.3.3/0003-CI-trim-riscv64-dev-group-install-and-drop-submodule-reinit.patch index 19469741e348..4797ad8a1316 100644 --- a/patches/quadrants/1.3.3/0003-CI-trim-riscv64-dev-group-install-and-drop-submodule-reinit.patch +++ b/patches/quadrants/1.3.3/0003-CI-trim-riscv64-dev-group-install-and-drop-submodule-reinit.patch @@ -25,20 +25,32 @@ submodules: recursive, so the follow-up `git submodule update` is both redundant and pointed at a path that doesn't exist here. Skip both on riscv64. -Upstream-Status: Inappropriate [riscv64 has no pyright wheel, and our workflow checks the repo out at a different path than upstream's own CI does] +cmake is pinned to the exact 3.31.6 release we publish a riscv64 +wheel for (CLAUDE.md gotcha 30). With PIP_EXTRA_INDEX_URL set, pip +resolves the highest version satisfying a constraint across *both* +indexes and treats a sdist-only candidate as resolvable -- PyPI's +cmake ships no riscv64 wheel for any release, so an unpinned +"cmake<4.0.0" lets pip pick a newer PyPI-only sdist (3.31.10 as of +this port) over our wheel and build CMake itself from source. That +source build FATAL_ERRORs configuring its bundled cmcurl ("Could NOT +find OpenSSL ... Could not find OpenSSL. Install an OpenSSL +development package"), since the manylinux_riscv64 image carries no +OpenSSL dev headers. + +Upstream-Status: Inappropriate [riscv64 has no pyright wheel, our workflow checks the repo out at a different path than upstream's own CI does, and PyPI's cmake ships no riscv64 wheel for any release] Signed-off-by: RISE Project CI --- - .../manylinux_wheel/1_prerequisites.sh | 21 +++++++++++++++---- - 1 file changed, 17 insertions(+), 4 deletions(-) + .../manylinux_wheel/1_prerequisites.sh | 27 +++++++++++++++++---- + 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/.github/workflows/scripts_new/manylinux_wheel/1_prerequisites.sh b/.github/workflows/scripts_new/manylinux_wheel/1_prerequisites.sh -index 03ca845..76157e2 100644 +index 03ca845..eea10bb 100644 --- a/.github/workflows/scripts_new/manylinux_wheel/1_prerequisites.sh +++ b/.github/workflows/scripts_new/manylinux_wheel/1_prerequisites.sh -@@ -3,12 +3,25 @@ +@@ -3,12 +3,31 @@ set -ex - + pip install -U pip -pip install --group dev +if [[ "$(uname -m)" == "riscv64" ]]; then @@ -46,14 +58,20 @@ index 03ca845..76157e2 100644 + # to (it wraps a prebuilt Node binary); install only what `pip wheel --no-build-isolation` + # below actually needs: build.py's own [build-system].requires, plus the cmake/ninja it + # drives them with, plus psutil/requests (qd_build's own non-stdlib imports). -+ pip install "cmake<4.0.0" ninja "nanobind>=2.0.0,<2.14.0" "scikit-build-core>=0.10" \ ++ # Pinned to the exact version we publish a riscv64 wheel for: with PIP_EXTRA_INDEX_URL ++ # pip resolves the highest version across *both* indexes, and PyPI's cmake has no ++ # riscv64 wheel for any release (not even the one we mirror) -- an unpinned "cmake<4.0.0" ++ # lets pip land on a newer PyPI-only sdist (3.31.10 at the time of writing) and build ++ # CMake itself from source, which FATAL_ERRORs configuring its bundled cmcurl because ++ # this image carries no OpenSSL development headers. ++ pip install "cmake==3.31.6" ninja "nanobind>=2.0.0,<2.14.0" "scikit-build-core>=0.10" \ + "setuptools_scm>=6.0" "numpy>=2.0.0" psutil requests + yum install -y ccache # setup_sccache() no-ops on riscv64; CMakeLists.txt's own + # find_program(ccache) picks this up as the compiler launcher instead. +else + pip install --group dev +fi - + yum install -y git wget -# Note: following depends on the name of the repo: -git config --global --add safe.directory /__w/quadrants/quadrants @@ -63,6 +81,6 @@ index 03ca845..76157e2 100644 + git config --global --add safe.directory /__w/quadrants/quadrants + git submodule update --init --jobs 2 +fi - + LLVM_DIR=$(python download_llvm.py | tail -n 1) export PATH=${LLVM_DIR}/bin:$PATH From c97d220a4fde786b277806266d48b005604a4e4a Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Thu, 5 Nov 2026 08:24:59 -0800 Subject: [PATCH 4/8] quadrants: Record target Python versions --- .github/workflows/build-quadrants.yml | 3 +-- docs/packages/quadrants.yaml | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-quadrants.yml b/.github/workflows/build-quadrants.yml index 4d95e5c79b12..b6f9884a0894 100644 --- a/.github/workflows/build-quadrants.yml +++ b/.github/workflows/build-quadrants.yml @@ -94,8 +94,7 @@ jobs: strategy: fail-fast: false matrix: - version: ${{ fromJSON(needs.setup.outputs.versions) }} - python: ["cp310", "cp311", "cp312", "cp313"] + include: ${{ fromJSON(needs.setup.outputs.matrix) }} name: Build quadrants ${{ matrix.version }} ${{ matrix.python }}-manylinux_riscv64 runs-on: ubuntu-24.04-riscv container: diff --git a/docs/packages/quadrants.yaml b/docs/packages/quadrants.yaml index af00d984a3ff..126320523014 100644 --- a/docs/packages/quadrants.yaml +++ b/docs/packages/quadrants.yaml @@ -3,3 +3,4 @@ source-code: https://github.com/Genesis-Embodied-AI/quadrants license: Apache-2.0 versions: - version: 1.3.3 + python-versions: ['3.10', '3.11', '3.12', '3.13'] From 1e9a752ccf7e24abe1416a1eefa59ae3e51ba36c Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Fri, 6 Nov 2026 09:22:51 -0800 Subject: [PATCH 5/8] quadrants: Use target file metadata --- docs/packages/quadrants.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/packages/quadrants.yaml b/docs/packages/quadrants.yaml index 126320523014..c7aaff366c80 100644 --- a/docs/packages/quadrants.yaml +++ b/docs/packages/quadrants.yaml @@ -3,4 +3,8 @@ source-code: https://github.com/Genesis-Embodied-AI/quadrants license: Apache-2.0 versions: - version: 1.3.3 - python-versions: ['3.10', '3.11', '3.12', '3.13'] + files: + - python: 3.10:manylinux + - python: 3.11:manylinux + - python: 3.12:manylinux + - python: 3.13:manylinux From 51092e0130b535826f826835c86fab46d15d6c00 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Sun, 8 Nov 2026 12:14:04 +0000 Subject: [PATCH 6/8] patches/quadrants: drop the EPEL-only ccache install on riscv64 1_prerequisites.sh ran `yum install -y ccache` on riscv64, but ccache is EPEL-only on RHEL derivatives and manylinux_2_39_riscv64 ships no EPEL (gotcha 51), so every interpreter leg failed with "Unable to find a match: ccache". Upstream never installs ccache; drop the line and build uncached, and update the sccache.py comment in 0002 that relied on it. --- ...n-the-LLVM-sccache-manylinux-build-scripts.patch | 12 ++++++------ ...ev-group-install-and-drop-submodule-reinit.patch | 13 ++++--------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/patches/quadrants/1.3.3/0002-CI-support-riscv64-in-the-LLVM-sccache-manylinux-build-scripts.patch b/patches/quadrants/1.3.3/0002-CI-support-riscv64-in-the-LLVM-sccache-manylinux-build-scripts.patch index 9f267451d12d..147cdae54980 100644 --- a/patches/quadrants/1.3.3/0002-CI-support-riscv64-in-the-LLVM-sccache-manylinux-build-scripts.patch +++ b/patches/quadrants/1.3.3/0002-CI-support-riscv64-in-the-LLVM-sccache-manylinux-build-scripts.patch @@ -11,9 +11,9 @@ mozilla/sccache's v0.10.0 release has no riscv64 binary either. On riscv64, setup_llvm() now expects the caller to build LLVM+clang 22.1.0 itself and export LLVM_DIR before build.py runs, and setup_sccache() skips the compiler-launcher wrapping instead of trying to download a -binary that doesn't exist (CMakeLists.txt's own find_program(ccache) -still caches the per-interpreter rebuilds when the image has ccache -installed). +binary that doesn't exist. riscv64 builds uncached: ccache, the +other launcher CMakeLists.txt's find_program() looks for, is EPEL-only +and the manylinux riscv64 image ships no EPEL. scripts_new/manylinux_wheel/2_build.sh's PLATFORM allowlist rejects every arch but x86_64/aarch64; add riscv64. There is no riscv64 @@ -63,9 +63,9 @@ index b5561c7..cce2b1e 100644 + if (u.system, u.machine) == ("Linux", "riscv64"): + # mozilla/sccache publishes no riscv64 binary (v0.10.0 release assets checked). Skip the + # compiler-launcher wrapping (entry.py's action_wheel still calls the returned command -+ # with --start-server / -s, so it must accept and ignore arbitrary args) and let ccache -+ # (installed from the manylinux image, found by CMakeLists.txt's own find_program) cache -+ # the per-interpreter rebuilds instead. ++ # with --start-server / -s, so it must accept and ignore arbitrary args) and build ++ # uncached: ccache is EPEL-only and the manylinux riscv64 image ships no EPEL, so ++ # there is no compiler cache to fall back to either. + return sh.bake("true") + if not exe.exists(): diff --git a/patches/quadrants/1.3.3/0003-CI-trim-riscv64-dev-group-install-and-drop-submodule-reinit.patch b/patches/quadrants/1.3.3/0003-CI-trim-riscv64-dev-group-install-and-drop-submodule-reinit.patch index 4797ad8a1316..908fb803ad5f 100644 --- a/patches/quadrants/1.3.3/0003-CI-trim-riscv64-dev-group-install-and-drop-submodule-reinit.patch +++ b/patches/quadrants/1.3.3/0003-CI-trim-riscv64-dev-group-install-and-drop-submodule-reinit.patch @@ -12,10 +12,7 @@ one unresolvable package fails the whole install. On riscv64, install only what build.py's `pip wheel --no-build-isolation` actually needs: build-system.requires (scikit-build-core, nanobind, numpy, setuptools_scm), the cmake/ninja it drives them with, and -psutil/requests (qd_build's own non-stdlib imports). Install ccache -too: setup_sccache() (patched earlier) no-ops on riscv64, and -CMakeLists.txt's own find_program(ccache) is what caches the -per-interpreter rebuilds instead. +psutil/requests (qd_build's own non-stdlib imports). The hardcoded `git config --global --add safe.directory /__w/quadrants/quadrants` assumes upstream's own checkout path; our @@ -41,14 +38,14 @@ Upstream-Status: Inappropriate [riscv64 has no pyright wheel, our workflow check Signed-off-by: RISE Project CI --- - .../manylinux_wheel/1_prerequisites.sh | 27 +++++++++++++++++---- - 1 file changed, 23 insertions(+), 4 deletions(-) + .../manylinux_wheel/1_prerequisites.sh | 25 +++++++++++++++++---- + 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/.github/workflows/scripts_new/manylinux_wheel/1_prerequisites.sh b/.github/workflows/scripts_new/manylinux_wheel/1_prerequisites.sh index 03ca845..eea10bb 100644 --- a/.github/workflows/scripts_new/manylinux_wheel/1_prerequisites.sh +++ b/.github/workflows/scripts_new/manylinux_wheel/1_prerequisites.sh -@@ -3,12 +3,31 @@ +@@ -3,12 +3,29 @@ set -ex pip install -U pip @@ -66,8 +63,6 @@ index 03ca845..eea10bb 100644 + # this image carries no OpenSSL development headers. + pip install "cmake==3.31.6" ninja "nanobind>=2.0.0,<2.14.0" "scikit-build-core>=0.10" \ + "setuptools_scm>=6.0" "numpy>=2.0.0" psutil requests -+ yum install -y ccache # setup_sccache() no-ops on riscv64; CMakeLists.txt's own -+ # find_program(ccache) picks this up as the compiler launcher instead. +else + pip install --group dev +fi From ca63d39ac69530fd3e89ea200d8076c1cfbbe012 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Tue, 10 Nov 2026 00:48:57 +0000 Subject: [PATCH 7/8] quadrants: pass matrix input to _publish-wheel.yml _publish-wheel.yml now requires a matrix input (main's "publish: Validate effective wheel targets"), but this PR branch forked before that landed and quadrants has never been merged to main, so build-quadrants.yml never picked up the matching one-line update every already-published package's workflow got. The merge ref combines the new required-input _publish-wheel.yml with this branch's old build-quadrants.yml, so any run has failed startup with "Input matrix is required, but not provided". Pass it the same way the mass-update commit did for every other package's publish job. --- .github/workflows/build-quadrants.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-quadrants.yml b/.github/workflows/build-quadrants.yml index b6f9884a0894..c5a0f4a5f54d 100644 --- a/.github/workflows/build-quadrants.yml +++ b/.github/workflows/build-quadrants.yml @@ -166,4 +166,5 @@ jobs: secrets: app-private-key: ${{ secrets.RISEPROJECT_APP_PRIVATE_KEY }} with: + matrix: ${{ needs.setup.outputs.matrix }} artifact-pattern: quadrants-${{ matrix.version }}-*-manylinux_riscv64 From f46d9891b110ed34ebde3fa1583b5a7abf80467d Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Wed, 11 Nov 2026 00:39:15 +0000 Subject: [PATCH 8/8] quadrants: mark our actual checkout path git-safe on riscv64 Runs 42731185766's cp311 and cp313 build jobs both failed CMake configure identically: "Commit" printed blank and "CMake Error at CMakeLists.txt:35 (string): string sub-command STRIP requires two arguments.", followed later by "Configuring incomplete, errors occurred!" (cp310 and cp312 failed earlier in the same run, to an LLVM artifact download timeout and a GitLab submodule-fetch overload respectively -- unrelated transient infra, rerun rather than patched). 1_prerequisites.sh's riscv64 branch dropped the upstream `git config --global --add safe.directory /__w/quadrants/quadrants` call outright instead of replacing it, reasoning that the hardcoded path doesn't match our checkout layout. But this job runs inside a `container:`, which doesn't see the safe.directory entry actions/checkout already added to the *runner's* own host gitconfig; without an equivalent here, the `git` this script installs refuses every command against the checkout as "dubious ownership" -- including CMakeLists.txt's own `git rev-parse` for the build's commit string, which swallows that failure and leaves the variable unset instead of erroring, surfacing two lines later as the STRIP argument error instead. Add the safe.directory call back on riscv64, pointed at $GITHUB_WORKSPACE (our actual checkout path, under any job's container) instead of upstream's hardcoded one. --- ...up-install-and-drop-submodule-reinit.patch | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/patches/quadrants/1.3.3/0003-CI-trim-riscv64-dev-group-install-and-drop-submodule-reinit.patch b/patches/quadrants/1.3.3/0003-CI-trim-riscv64-dev-group-install-and-drop-submodule-reinit.patch index 908fb803ad5f..a2d0cbdf6644 100644 --- a/patches/quadrants/1.3.3/0003-CI-trim-riscv64-dev-group-install-and-drop-submodule-reinit.patch +++ b/patches/quadrants/1.3.3/0003-CI-trim-riscv64-dev-group-install-and-drop-submodule-reinit.patch @@ -20,7 +20,18 @@ workflow checks quadrants out under python-wheels' own job workspace, not /__w/quadrants/quadrants, and actions/checkout already ran with submodules: recursive, so the follow-up `git submodule update` is both redundant and pointed at a path that doesn't exist here. Skip -both on riscv64. +the submodule re-init on riscv64, but replace the safe.directory call +with one that marks our actual checkout path (`$GITHUB_WORKSPACE`) +safe instead of dropping it outright: actions/checkout's own +safe.directory entry lives in the *runner's* host gitconfig, which +this `container:` job doesn't see, so without an equivalent here the +`git` this script just installed refuses every command against the +checkout as "dubious ownership". CMakeLists.txt's own `git rev-parse` +for the build's commit string swallows that failure and returns +nothing instead of erroring, which only surfaces two lines later as +"string sub-command STRIP requires two arguments" ("Commit" prints +blank right above it) -- a CMake configure failure that reproduced +identically on both cp311 and cp313. cmake is pinned to the exact 3.31.6 release we publish a riscv64 wheel for (CLAUDE.md gotcha 30). With PIP_EXTRA_INDEX_URL set, pip @@ -34,18 +45,18 @@ find OpenSSL ... Could not find OpenSSL. Install an OpenSSL development package"), since the manylinux_riscv64 image carries no OpenSSL dev headers. -Upstream-Status: Inappropriate [riscv64 has no pyright wheel, our workflow checks the repo out at a different path than upstream's own CI does, and PyPI's cmake ships no riscv64 wheel for any release] +Upstream-Status: Inappropriate [riscv64 has no pyright wheel, our workflow checks the repo out at a different path than upstream's own CI does and runs this inside a container that doesn't see the runner's own safe.directory entry, and PyPI's cmake ships no riscv64 wheel for any release] Signed-off-by: RISE Project CI --- - .../manylinux_wheel/1_prerequisites.sh | 25 +++++++++++++++++---- - 1 file changed, 21 insertions(+), 4 deletions(-) + .../manylinux_wheel/1_prerequisites.sh | 33 +++++++++++++++++++++---- + 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/.github/workflows/scripts_new/manylinux_wheel/1_prerequisites.sh b/.github/workflows/scripts_new/manylinux_wheel/1_prerequisites.sh index 03ca845..eea10bb 100644 --- a/.github/workflows/scripts_new/manylinux_wheel/1_prerequisites.sh +++ b/.github/workflows/scripts_new/manylinux_wheel/1_prerequisites.sh -@@ -3,12 +3,29 @@ +@@ -3,12 +3,37 @@ set -ex pip install -U pip @@ -71,7 +82,15 @@ index 03ca845..eea10bb 100644 -# Note: following depends on the name of the repo: -git config --global --add safe.directory /__w/quadrants/quadrants -git submodule update --init --jobs 2 -+if [[ "$(uname -m)" != "riscv64" ]]; then ++if [[ "$(uname -m)" == "riscv64" ]]; then ++ # actions/checkout's own safe.directory entry lives in the runner's host ++ # gitconfig, which this container doesn't see; without an equivalent here, ++ # git (just installed by `yum install -y git` above) refuses every command ++ # against the checkout as "dubious ownership", and CMakeLists.txt's own ++ # `git rev-parse` for the commit string silently returns nothing instead ++ # of failing the build, later erroring as a missing string(STRIP) argument. ++ git config --global --add safe.directory "$GITHUB_WORKSPACE" ++else + # Note: following depends on the name of the repo: + git config --global --add safe.directory /__w/quadrants/quadrants + git submodule update --init --jobs 2