From a24ddb650fd6d8e05ef694b11be683945cad83a7 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Wed, 30 Sep 2026 14:42:10 +0000 Subject: [PATCH 1/3] ale-py: Add version 0.12.1 Build ale-py (Arcade Learning Environment) riscv64 wheels for cp312/cp313/cp314 from the upstream v0.12.1 checkout, mirroring the build-wheels/test-wheels jobs of upstream's build-python.yml. Upstream builds in a manylinux vcpkg image with no riscv64 variant, so CIBW_BEFORE_ALL builds the same vcpkg.json dependencies from their release tarballs: SDL2 2.30.11 (shared, shipped next to the extension for SDL_DYNLOAD) and OpenCV 4.10.0 core/imgproc (static), with zlib from the image. The XLA vector interface is turned off: it needs jaxlib's FFI headers and jaxlib has no riscv64 build. jax is therefore dropped from the build by preinstalling scikit-build-core and nanobind (capped at the 2.x series 0.12.1 was released with) and building with pip --no-build-isolation. Tests run upstream's pytest suite with the `test` extra minus jax/chex; the XLA test module importorskips them. A patch widens project.license-files to LICENSE* so the SDL2, OpenCV and nanobind notices staged at the project root ship in the wheel. --- .github/workflows/build-ale-py.yml | 168 ++++++++++++++++++ docs/packages/ale-py.yaml | 6 + ...nse-files-to-cover-bundled-libraries.patch | 40 +++++ 3 files changed, 214 insertions(+) create mode 100644 .github/workflows/build-ale-py.yml create mode 100644 docs/packages/ale-py.yaml create mode 100644 patches/ale-py/0.12.1/0001-pyproject-widen-license-files-to-cover-bundled-libraries.patch diff --git a/.github/workflows/build-ale-py.yml b/.github/workflows/build-ale-py.yml new file mode 100644 index 00000000000..d8099083533 --- /dev/null +++ b/.github/workflows/build-ale-py.yml @@ -0,0 +1,168 @@ +# SPDX-FileCopyrightText: 2026 The RISE Project +# SPDX-License-Identifier: MIT +--- +# This workflow is based on the `build-wheels` and `test-wheels` jobs of +# https://github.com/Farama-Foundation/Arcade-Learning-Environment/blob/v0.12.1/.github/workflows/build-python.yml +name: Build ale-py wheels (riscv64) + +on: + workflow_dispatch: + inputs: + version: + description: 'Version glob to (re)build; empty builds every version of docs/packages/ale-py.yaml not released yet' + required: false + default: '' + pull_request: + branches: [main] + paths: + - '.github/workflows/build-ale-py.yml' + - 'docs/packages/ale-py.yaml' + push: + branches: [main] + paths: + - '.github/workflows/build-ale-py.yml' + - 'docs/packages/ale-py.yaml' + +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: ale-py + version: ${{ inputs.version }} + + build_wheels: + needs: [setup] + if: needs.setup.outputs.versions != '[]' + name: Build ale-py ${{ matrix.version }} ${{ matrix.python }}-manylinux_riscv64 + runs-on: ubuntu-24.04-riscv + timeout-minutes: 180 + strategy: + fail-fast: false + matrix: + version: ${{ fromJSON(needs.setup.outputs.versions) }} + # Upstream's [tool.cibuildwheel] skip list excludes cp314t. + python: ["cp312", "cp313", "cp314"] + + env: + ALE_PY_VERSION: ${{ matrix.version }} + + steps: + - name: Checkout ale-py ${{ env.ALE_PY_VERSION }} + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + repository: Farama-Foundation/Arcade-Learning-Environment + ref: v${{ env.ALE_PY_VERSION }} + persist-credentials: false + + - name: Checkout python-wheels + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + path: python-wheels + persist-credentials: false + + - name: Patch ale-py source + run: git apply python-wheels/patches/ale-py/${{ env.ALE_PY_VERSION }}/00*.patch + + - name: Download and unpack ROMs + run: ./scripts/download_unpack_roms.sh + + - name: Build wheels + uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0 + with: + output-dir: wheelhouse/ + only: ${{ matrix.python }}-manylinux_riscv64 + env: + CIBW_MANYLINUX_RISCV64_IMAGE: ${{ env.MANYLINUX_RISCV64_IMAGE }} + # Upstream's manylinux--vcpkg image has no riscv64 build; this builds the + # same vcpkg.json dependencies (SDL2 2.30.11 shared, OpenCV 4.10.0 static) from + # their release tarballs, with zlib from the image. + CIBW_BEFORE_ALL: | + set -e + dnf install -y -q ninja-build zlib-devel \ + libX11-devel libXext-devel libXcursor-devel libXi-devel libXrandr-devel \ + libXinerama-devel libXxf86vm-devel libxkbcommon-devel \ + wayland-devel wayland-protocols-devel alsa-lib-devel + mkdir -p /tmp/ale-deps && cd /tmp/ale-deps + + curl -fsSL --retry 5 -o SDL2.tar.gz https://github.com/libsdl-org/SDL/releases/download/release-2.30.11/SDL2-2.30.11.tar.gz + tar xzf SDL2.tar.gz + cmake -S SDL2-2.30.11 -B sdl2-build -G Ninja -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_INSTALL_LIBDIR=lib \ + -DSDL_SHARED=ON -DSDL_STATIC=OFF -DSDL_TEST=OFF \ + -DSDL_DBUS=OFF -DSDL_IBUS=OFF -DSDL_LIBSAMPLERATE=OFF -DSDL_VULKAN=OFF + cmake --build sdl2-build && cmake --install sdl2-build + cp SDL2-2.30.11/LICENSE.txt {project}/LICENSE.SDL2.txt + + curl -fsSL --retry 5 -o opencv.tar.gz https://github.com/opencv/opencv/archive/refs/tags/4.10.0.tar.gz + tar xzf opencv.tar.gz + cmake -S opencv-4.10.0 -B opencv-build -G Ninja -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_INSTALL_LIBDIR=lib \ + -DBUILD_SHARED_LIBS=OFF -DBUILD_LIST=core,imgproc \ + -DBUILD_TESTS=OFF -DBUILD_PERF_TESTS=OFF -DBUILD_EXAMPLES=OFF -DBUILD_opencv_apps=OFF \ + -DBUILD_JAVA=OFF -DBUILD_opencv_python3=OFF \ + -DWITH_ITT=OFF -DWITH_IPP=OFF -DWITH_OPENCL=OFF -DWITH_LAPACK=OFF -DWITH_EIGEN=OFF + cmake --build opencv-build && cmake --install opencv-build + cp opencv-4.10.0/LICENSE {project}/LICENSE.opencv.txt + # jax is a build requirement only for the XLA vector interface, which needs + # jaxlib's FFI headers; jaxlib has no riscv64 build, so that interface is off + # and pip's no-isolation mode skips resolving jax (gotcha 76). + # nanobind is capped at the 2.x series ale-py 0.12.1 was released with. + CIBW_BUILD_FRONTEND: "pip; args: --no-build-isolation" + CIBW_BEFORE_BUILD: | + python -m pip install "scikit-build-core>=0.10" "nanobind>=2.5.0,<3" + python -c "import importlib.metadata as m, shutil; shutil.copy(next(f.locate() for f in m.files('nanobind') if f.name == 'LICENSE'), '{project}/LICENSE.nanobind')" + CIBW_ENVIRONMENT: >- + SKBUILD_CMAKE_ARGS="-DSDL_SUPPORT=ON;-DSDL_DYNLOAD=ON;-DBUILD_CPP_LIB=OFF;-DBUILD_PYTHON_LIB=ON;-DBUILD_VECTOR_LIB=ON;-DBUILD_VECTOR_XLA_LIB=OFF" + PIP_EXTRA_INDEX_URL=https://pypi.riseproject.dev/simple/ + PIP_ONLY_BINARY=numpy,opencv-python + # Upstream's `test` extra minus jax and chex (jaxlib again); the XLA test + # module importorskips them. + CIBW_TEST_REQUIRES: pytest>=7.0 gymnasium>=1.1.0 opencv-python>=3.0 + CIBW_TEST_SOURCES: tests pyproject.toml + CIBW_TEST_COMMAND: python -m pytest + + - name: Check the bundled licences made it into the wheel + run: | + python3 - wheelhouse/*.whl <<'EOF' + import sys, zipfile + expected = {"LICENSE.md", "LICENSE.SDL2.txt", "LICENSE.opencv.txt", "LICENSE.nanobind"} + for whl in sys.argv[1:]: + names = zipfile.ZipFile(whl).namelist() + found = {n.rsplit("/", 1)[1] for n in names if ".dist-info/licenses/" in n} + assert expected <= found, f"{whl}: missing {expected - found}" + assert not any(n.startswith("ale_py.libs/") for n in names), f"{whl}: auditwheel grafted libraries" + print(whl, "ok") + EOF + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: ale-py-${{ env.ALE_PY_VERSION }}-${{ matrix.python }}-manylinux_riscv64 + path: wheelhouse/*.whl + if-no-files-found: error + + publish: + name: Publish ale-py ${{ 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: ale-py-${{ matrix.version }}-*-manylinux_riscv64 diff --git a/docs/packages/ale-py.yaml b/docs/packages/ale-py.yaml new file mode 100644 index 00000000000..1a25574d86b --- /dev/null +++ b/docs/packages/ale-py.yaml @@ -0,0 +1,6 @@ +package-name: ale-py +source-code: https://github.com/Farama-Foundation/Arcade-Learning-Environment +license: GPL-2.0-only +versions: +- version: 0.12.1 + patched: true diff --git a/patches/ale-py/0.12.1/0001-pyproject-widen-license-files-to-cover-bundled-libraries.patch b/patches/ale-py/0.12.1/0001-pyproject-widen-license-files-to-cover-bundled-libraries.patch new file mode 100644 index 00000000000..569b33489c0 --- /dev/null +++ b/patches/ale-py/0.12.1/0001-pyproject-widen-license-files-to-cover-bundled-libraries.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ludovic Henry +Date: Wed, 30 Sep 2026 00:00:00 +0000 +Subject: [PATCH] pyproject: widen license-files to cover bundled libraries + +`license-files = ["LICENSE.md"]` is an explicit PEP 639 list, so it has +no default glob behind it: a `LICENSE.` dropped at the project root +for a library compiled into the wheel is silently ignored. The wheel +ships libSDL2 (zlib) next to the extension, and `_ale_py` statically +links OpenCV core/imgproc (Apache-2.0) and nanobind (BSD-3-Clause), yet +only ALE's own GPL-2.0 notice lands in dist-info/licenses. scikit-build-core +refuses the SKBUILD_WHEEL_LICENSE_FILES override while project.license-files +is set, so the list itself has to change. + +`LICENSE*` still matches only LICENSE.md in a clean checkout, so the sdist +is unchanged; the staged `LICENSE.` files are picked up in the wheel. + +Upstream's own wheels carry the same gap: only LICENSE.md ships in +dist-info/licenses, with no notice for the bundled SDL2 or the statically +linked OpenCV and nanobind. + +Upstream-Status: To upstream [not submitted from this automated port run; needs a pull request against Farama-Foundation/Arcade-Learning-Environment] +--- + pyproject.toml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/pyproject.toml b/pyproject.toml +--- a/pyproject.toml ++++ b/pyproject.toml +@@ -12,7 +12,7 @@ + readme = "README.md" + requires-python = ">=3.10" + license = "GPL-2.0-only" +-license-files = ["LICENSE.md"] ++license-files = ["LICENSE*"] + keywords = ["reinforcement-learning", "arcade-learning-environment", "atari"] + authors = [ + {name = "Marc G. Bellemare"}, +-- +2.43.0 From 2d7603f28a83ed9f91f7f7b3d1b42483daaac0a7 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Wed, 30 Sep 2026 20:38:48 +0200 Subject: [PATCH 2/3] build-ale-py: disable OpenCV's unused 3rdparty image-format libs All three build legs failed identically at CMake configure: CMake Error ... OpenCVModules.cmake:131 The imported target "libtiff" references the file "/usr/local/lib/opencv4/3rdparty/liblibtiff.a" but this file does not exist. BUILD_LIST=core,imgproc excludes imgcodecs (the module that would actually use libtiff/libjpeg/libpng/etc for image I/O), but OpenCV's default WITH_TIFF=ON (and the other WITH_* format flags) still makes it register those 3rdparty static-lib targets in the exported OpenCVConfig/OpenCVModules cmake files -- it just never builds them, since nothing in the core/imgproc-only build consumes them. ale-py's own CMakeLists.txt find_package(OpenCV)'s just importing that config is enough to hit the dangling target. Turn the format libs off explicitly, matching what's actually needed for core/imgproc. Signed-off-by: Ludovic Henry --- .github/workflows/build-ale-py.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-ale-py.yml b/.github/workflows/build-ale-py.yml index d8099083533..8dc4442765e 100644 --- a/.github/workflows/build-ale-py.yml +++ b/.github/workflows/build-ale-py.yml @@ -110,7 +110,9 @@ jobs: -DBUILD_SHARED_LIBS=OFF -DBUILD_LIST=core,imgproc \ -DBUILD_TESTS=OFF -DBUILD_PERF_TESTS=OFF -DBUILD_EXAMPLES=OFF -DBUILD_opencv_apps=OFF \ -DBUILD_JAVA=OFF -DBUILD_opencv_python3=OFF \ - -DWITH_ITT=OFF -DWITH_IPP=OFF -DWITH_OPENCL=OFF -DWITH_LAPACK=OFF -DWITH_EIGEN=OFF + -DWITH_ITT=OFF -DWITH_IPP=OFF -DWITH_OPENCL=OFF -DWITH_LAPACK=OFF -DWITH_EIGEN=OFF \ + -DWITH_TIFF=OFF -DWITH_JPEG=OFF -DWITH_PNG=OFF -DWITH_WEBP=OFF \ + -DWITH_OPENJPEG=OFF -DWITH_JASPER=OFF -DWITH_OPENEXR=OFF -DWITH_GTK=OFF -DWITH_FFMPEG=OFF cmake --build opencv-build && cmake --install opencv-build cp opencv-4.10.0/LICENSE {project}/LICENSE.opencv.txt # jax is a build requirement only for the XLA vector interface, which needs From 77388111d014346c63e57e84841b42d9aa54f7c1 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Wed, 30 Sep 2026 22:38:21 +0200 Subject: [PATCH 3/3] build-ale-py: disable more of OpenCV's unused optional 3rdparty libs libtiff is fixed, but the rebuild hit the identical dangling-target pattern on a different library: CMake Error ... OpenCVModules.cmake:96 The imported target "libprotobuf" references the file "/usr/local/lib/opencv4/3rdparty/liblibprotobuf.a" but this file does not exist. WITH_* defaults to ON and gets registered as a 3rdparty cmake target regardless of BUILD_LIST -- only consumption by an actually-built module decides whether it gets built, so any left-on default that a core/imgproc-only build never touches leaves the same kind of dangling reference behind. Turn off the rest of the ones that only matter to modules this port doesn't build (dnn/objdetect/highgui/gapi/etc), not just the image-format ones already off, so this doesn't keep coming back one library at a time. Signed-off-by: Ludovic Henry --- .github/workflows/build-ale-py.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-ale-py.yml b/.github/workflows/build-ale-py.yml index 8dc4442765e..92268f81d6d 100644 --- a/.github/workflows/build-ale-py.yml +++ b/.github/workflows/build-ale-py.yml @@ -112,7 +112,12 @@ jobs: -DBUILD_JAVA=OFF -DBUILD_opencv_python3=OFF \ -DWITH_ITT=OFF -DWITH_IPP=OFF -DWITH_OPENCL=OFF -DWITH_LAPACK=OFF -DWITH_EIGEN=OFF \ -DWITH_TIFF=OFF -DWITH_JPEG=OFF -DWITH_PNG=OFF -DWITH_WEBP=OFF \ - -DWITH_OPENJPEG=OFF -DWITH_JASPER=OFF -DWITH_OPENEXR=OFF -DWITH_GTK=OFF -DWITH_FFMPEG=OFF + -DWITH_OPENJPEG=OFF -DWITH_JASPER=OFF -DWITH_OPENEXR=OFF -DWITH_GTK=OFF -DWITH_FFMPEG=OFF \ + -DWITH_PROTOBUF=OFF -DWITH_QUIRC=OFF -DWITH_ADE=OFF -DWITH_GDCM=OFF \ + -DWITH_GSTREAMER=OFF -DWITH_V4L=OFF -DWITH_1394=OFF -DWITH_GPHOTO2=OFF \ + -DWITH_OPENVX=OFF -DWITH_VA=OFF -DWITH_VA_INTEL=OFF -DWITH_GDAL=OFF \ + -DWITH_OPENGL=OFF -DWITH_QT=OFF -DWITH_TBB=OFF -DWITH_VTK=OFF -DWITH_IMGCODEC_HDR=OFF \ + -DWITH_IMGCODEC_SUNRASTER=OFF -DWITH_IMGCODEC_PXM=OFF -DWITH_IMGCODEC_PFM=OFF cmake --build opencv-build && cmake --install opencv-build cp opencv-4.10.0/LICENSE {project}/LICENSE.opencv.txt # jax is a build requirement only for the XLA vector interface, which needs