From 8399d3f41078aee882149148272ade139635a7b1 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Thu, 15 Oct 2026 02:54:51 +0000 Subject: [PATCH 1/2] Add riscv64 build for panda3d 1.10.16 Panda3D's own makepanda.py build/wheel tooling probes each native dependency (OpenGL, X11, audio, physics, Cg shaders, ...) and silently drops the feature when it's missing rather than failing the build, the same way upstream's own Linux CI already drops features it has no dev package for (Bullet). That makes the port tractable: install the subset of upstream's apt-get list that Rocky 10 riscv64 actually has (bison/flex/freetype/mesa-libGL/libjpeg-turbo/libpng/libvorbis/libX11 family/openal-soft/zlib/openssl), drop ode-devel (not packaged for Rocky 10) and nvidia-cg-toolkit (x86-only, never had a riscv64 build), and let SmartPkgEnable skip ODE/Cg gracefully. The one real blocker is makepanda's own --wheel platform-tag detection: it recognizes manylinux1/2010/2014/2_24/2_28 by checking for a specific versioned glibc file, none of which exist in manylinux_2_39_riscv64, so it falls through to a plain (non-manylinux) linux_riscv64 tag - confirmed locally against an x86_64 Ubuntu host, which hits the exact same fallback. patches/panda3d/1.10.16 adds a branch keyed on the target arch instead. A single job builds cp312/cp313/cp314/cp314t in one container invocation, reusing makepanda's own outputdir-keyed dependency cache across interpreters (matching upstream's own CI, which loops the same --outputdir across every Python version it supports) rather than rebuilding the ~700k-line engine from scratch per interpreter. --- .github/workflows/build-panda3d.yml | 174 ++++++++++++++++++ docs/packages/panda3d.yaml | 13 ++ ...epanda-detect-manylinux_2_39_riscv64.patch | 40 ++++ 3 files changed, 227 insertions(+) create mode 100644 .github/workflows/build-panda3d.yml create mode 100644 docs/packages/panda3d.yaml create mode 100644 patches/panda3d/1.10.16/0001-makepanda-detect-manylinux_2_39_riscv64.patch diff --git a/.github/workflows/build-panda3d.yml b/.github/workflows/build-panda3d.yml new file mode 100644 index 000000000000..72bbda55a82b --- /dev/null +++ b/.github/workflows/build-panda3d.yml @@ -0,0 +1,174 @@ +# SPDX-FileCopyrightText: 2026 The RISE Project +# SPDX-License-Identifier: MIT +--- +# This workflow is based on the `makepanda` job of +# https://github.com/panda3d/panda3d/blob/v1.10.16/.github/workflows/ci.yml +name: Build panda3d wheels (riscv64) + +on: + workflow_dispatch: + inputs: + version: + description: 'Version glob to (re)build; empty builds every version of docs/packages/panda3d.yaml not released yet' + required: false + default: '' + pull_request: + branches: [main] + paths: + - '.github/workflows/build-panda3d.yml' + - 'docs/packages/panda3d.yaml' + - 'patches/panda3d/**' + push: + branches: [main] + paths: + - '.github/workflows/build-panda3d.yml' + - 'docs/packages/panda3d.yaml' + - 'patches/panda3d/**' + +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: panda3d + version: ${{ inputs.version }} + + build_wheels: + needs: [setup] + if: needs.setup.outputs.versions != '[]' + strategy: + fail-fast: false + matrix: + version: ${{ fromJSON(needs.setup.outputs.versions) }} + name: Build panda3d ${{ matrix.version }} manylinux_riscv64 + runs-on: ubuntu-24.04-riscv + timeout-minutes: 600 + + env: + PANDA3D_VERSION: ${{ matrix.version }} + + steps: + - name: Checkout panda3d v${{ env.PANDA3D_VERSION }} + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + repository: panda3d/panda3d + ref: v${{ env.PANDA3D_VERSION }} + 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: git apply -v python-wheels/patches/panda3d/${{ env.PANDA3D_VERSION }}/*.patch + + - name: Build and test wheels + run: | + mkdir -p wheelhouse + docker run --rm -i --network=host \ + -v "$(pwd):/work" \ + -w /work \ + -e PANDA3D_VERSION \ + "${MANYLINUX_RISCV64_IMAGE}" \ + bash <<'SCRIPT' + set -eux + + # Matches upstream's own Ubuntu apt-get list (build-essential bison flex + # libfreetype6-dev libgl1-mesa-dev libjpeg-dev libode-dev libopenal-dev + # libpng-dev libssl-dev libvorbis-dev libx11-dev libxcursor-dev + # libxrandr-dev nvidia-cg-toolkit zlib1g-dev), minus ode-devel (not + # packaged for Rocky 10) and nvidia-cg-toolkit (x86-only, no riscv64 + # build ever existed) -- makepanda's SmartPkgEnable probes for each + # package and silently drops the feature (ODE physics, Cg shaders) + # rather than failing when one is missing, the same way it already + # does for Bullet on upstream's own Linux CI. + dnf install -y --setopt=install_weak_deps=False \ + bison flex freetype-devel mesa-libGL-devel libjpeg-turbo-devel \ + libpng-devel openssl-devel libvorbis-devel libogg-devel \ + libX11-devel libXcursor-devel libXrandr-devel openal-soft-devel zlib-devel + + for pydir in cp312-cp312 cp313-cp313 cp314-cp314 cp314-cp314t; do + PY="/opt/python/${pydir}/bin/python3" + "${PY}" makepanda/makepanda.py --everything --no-eigen --wheel \ + --outputdir=built --version="${PANDA3D_VERSION}" \ + --threads="$(nproc)" --verbose + + whl=$(ls panda3d-*.whl) + mv "${whl}" wheelhouse/ + + "${PY}" -m venv /tmp/test-venv + /tmp/test-venv/bin/pip install -q "wheelhouse/${whl}" pytest + /tmp/test-venv/bin/python -m pytest -x -q + rm -rf /tmp/test-venv + done + SCRIPT + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: panda3d-${{ env.PANDA3D_VERSION }}-manylinux_riscv64 + path: wheelhouse/*.whl + if-no-files-found: error + + gpl_sources: + needs: [setup] + if: needs.setup.outputs.versions != '[]' + strategy: + fail-fast: false + matrix: + version: ${{ fromJSON(needs.setup.outputs.versions) }} + name: Collect GPL sources for panda3d ${{ matrix.version }} + runs-on: ubuntu-24.04-riscv + + env: + PANDA3D_VERSION: ${{ matrix.version }} + + steps: + - name: Checkout python-wheels + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + # The engine is compiled with the image's GCC and links its libstdc++; + # freetype's Rocky 10 build resolves to its GPLv2 option (same as + # build-pygame.yml's freetype entry, from the same image). + - uses: ./actions/collect-gpl-sources + with: + image: ${{ env.MANYLINUX_RISCV64_IMAGE }} + packages: gcc freetype + output: gpl-sources.tar + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: panda3d-${{ env.PANDA3D_VERSION }}-gpl-sources + path: gpl-sources.tar + if-no-files-found: error + + publish: + name: Publish panda3d ${{ matrix.version }} + needs: [setup, build_wheels, gpl_sources] + 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: panda3d-${{ matrix.version }}-manylinux_riscv64 + gpl-sources-artifact: panda3d-${{ matrix.version }}-gpl-sources + gpl-sources-description: gcc and freetype diff --git a/docs/packages/panda3d.yaml b/docs/packages/panda3d.yaml new file mode 100644 index 000000000000..591f71701fa9 --- /dev/null +++ b/docs/packages/panda3d.yaml @@ -0,0 +1,13 @@ +package-name: panda3d +source-code: https://github.com/panda3d/panda3d +license: BSD-3-Clause +versions: +- version: 1.10.16 + patched: true + comment: >- + makepanda's own --wheel platform-tag detection only recognizes + manylinux1/2010/2014/2_24/2_28 by checking for a specific glibc file that + quay.io/pypa/manylinux_2_39_riscv64 (Rocky 10) doesn't have; the patch adds a + branch keyed on the target arch instead. ODE physics and Cg shader support + are dropped (no riscv64 package for either), matching how upstream's own + Linux wheels already drop Bullet for the same reason. diff --git a/patches/panda3d/1.10.16/0001-makepanda-detect-manylinux_2_39_riscv64.patch b/patches/panda3d/1.10.16/0001-makepanda-detect-manylinux_2_39_riscv64.patch new file mode 100644 index 000000000000..7af89a6d9c81 --- /dev/null +++ b/patches/panda3d/1.10.16/0001-makepanda-detect-manylinux_2_39_riscv64.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ludovic Henry +Date: Mon, 21 Sep 2026 00:00:00 +0000 +Subject: [PATCH] makepanda: detect manylinux_2_39_riscv64 + +makepanda.py's own PLATFORM detection (used for --wheel's platform tag) +recognizes manylinux1/2010/2014/2_24/2_28 by checking for a specific +versioned /lib64/libc-X.Y.so file plus, for 2_28, /etc/almalinux-release. +None of those checks can ever match quay.io/pypa/manylinux_2_39_riscv64 +(Rocky 10): modern glibc no longer ships a libc-X.Y.so symlink at all, and +riscv64 isn't one of the arches any existing branch maps to a tag (the +2_28 branch's "else" even raises for an unrecognized arch). Detection +falls through to the generic, non-cross-compiling branch, which just +takes sysconfig.get_platform() verbatim ("linux-riscv64"), so --wheel +produces a plain linux_riscv64-tagged wheel instead of a manylinux one. + +Add a branch keyed on the target arch instead of a libc filename, mirroring +the existing per-release branches' shape. + +Upstream-Status: To upstream [not yet submitted; needs a riscv64 CI leg upstream doesn't have yet to validate against] + +Signed-off-by: Ludovic Henry +--- +diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py +index ad6230f..c80e4c6 100755 +--- a/makepanda/makepanda.py ++++ b/makepanda/makepanda.py +@@ -533,6 +533,12 @@ elif target == 'linux' and os.path.isfile("/lib64/libc-2.28.so") and os.path.isf + else: + raise RuntimeError('Unhandled arch %s, please file a bug report!' % (target_arch)) + ++elif target == 'linux' and target_arch == 'riscv64' and os.path.isdir("/opt/python"): ++ # manylinux_2_39_riscv64 (quay.io/pypa/manylinux_2_39_riscv64, Rocky 10): glibc ++ # no longer ships the versioned libc-X.Y.so file the checks above rely on, so ++ # detect this image by arch instead. ++ PLATFORM = 'manylinux_2_39-riscv64' ++ + elif not CrossCompiling(): + if HasTargetArch(): + # Replace the architecture in the platform string. From 2ba2e7aeae344fb39e87ec3752c99efa8d2120dc Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Sun, 25 Oct 2026 17:57:58 +0000 Subject: [PATCH 2/2] panda3d: drop openal-soft-devel, EPEL-only and absent on riscv64 dnf fails with "Unable to find a match: openal-soft-devel": the package exists only in EPEL on RHEL derivatives, and manylinux installs no EPEL on riscv64 (and Rocky 10's own BaseOS/AppStream/CRB for riscv64 carry no openal package under any name either). Drop it from the install list, same treatment already given to ode-devel and nvidia-cg-toolkit -- makepanda's SmartPkgEnable will probe for OpenAL, find it missing, and silently skip audio support instead of failing the build. --- .github/workflows/build-panda3d.yml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-panda3d.yml b/.github/workflows/build-panda3d.yml index 72bbda55a82b..38d2ebe32a28 100644 --- a/.github/workflows/build-panda3d.yml +++ b/.github/workflows/build-panda3d.yml @@ -88,15 +88,18 @@ jobs: # libfreetype6-dev libgl1-mesa-dev libjpeg-dev libode-dev libopenal-dev # libpng-dev libssl-dev libvorbis-dev libx11-dev libxcursor-dev # libxrandr-dev nvidia-cg-toolkit zlib1g-dev), minus ode-devel (not - # packaged for Rocky 10) and nvidia-cg-toolkit (x86-only, no riscv64 - # build ever existed) -- makepanda's SmartPkgEnable probes for each - # package and silently drops the feature (ODE physics, Cg shaders) - # rather than failing when one is missing, the same way it already - # does for Bullet on upstream's own Linux CI. + # packaged for Rocky 10), nvidia-cg-toolkit (x86-only, no riscv64 + # build ever existed), and openal-soft-devel (EPEL-only on RHEL + # derivatives -- manylinux installs no EPEL on riscv64 -- and not + # present under any name in Rocky 10's own BaseOS/AppStream/CRB for + # riscv64 either) -- makepanda's SmartPkgEnable probes for each + # package and silently drops the feature (ODE physics, Cg shaders, + # OpenAL audio) rather than failing when one is missing, the same + # way it already does for Bullet on upstream's own Linux CI. dnf install -y --setopt=install_weak_deps=False \ bison flex freetype-devel mesa-libGL-devel libjpeg-turbo-devel \ libpng-devel openssl-devel libvorbis-devel libogg-devel \ - libX11-devel libXcursor-devel libXrandr-devel openal-soft-devel zlib-devel + libX11-devel libXcursor-devel libXrandr-devel zlib-devel for pydir in cp312-cp312 cp313-cp313 cp314-cp314 cp314-cp314t; do PY="/opt/python/${pydir}/bin/python3"