From 43c24739e49eb894f437b1e9796f2508d2d3a9ee Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Tue, 13 Oct 2026 12:02:00 +0000 Subject: [PATCH 1/4] Add riscv64 build for epam-indigo 1.46.0 The py3-none- wheel ships four C++ libraries loaded via ctypes (not CPython extensions), so one wheel serves every interpreter. Builds the libraries in the manylinux_riscv64 image with BUILD_STANDALONE's vendored cairo/freetype/pixman/zlib/etc (no SIMD gates in any of them), then patches setup.py's hardcoded --plat-name list to add riscv64. Stages licence texts for every statically linked third-party library, none of which ship in upstream's own wheel. --- .github/workflows/build-epam-indigo.yml | 178 ++++++++++++++++++ docs/packages/epam-indigo.yaml | 6 + ...ize-manylinux_2_39_riscv64-plat-name.patch | 43 +++++ 3 files changed, 227 insertions(+) create mode 100644 .github/workflows/build-epam-indigo.yml create mode 100644 docs/packages/epam-indigo.yaml create mode 100644 patches/epam-indigo/1.46.0/0001-python-recognize-manylinux_2_39_riscv64-plat-name.patch diff --git a/.github/workflows/build-epam-indigo.yml b/.github/workflows/build-epam-indigo.yml new file mode 100644 index 000000000000..7c433f12d309 --- /dev/null +++ b/.github/workflows/build-epam-indigo.yml @@ -0,0 +1,178 @@ +# SPDX-FileCopyrightText: 2026 The RISE Project +# SPDX-License-Identifier: MIT +--- +# This workflow is based on the `build_indigo_libs_x86_64` and `build_indigo_wrappers` jobs of +# https://github.com/epam/indigo/blob/indigo-1.46.0/.github/workflows/indigo-ci.yaml +name: Build epam-indigo wheels (riscv64) + +on: + workflow_dispatch: + inputs: + version: + description: 'Version glob to (re)build; empty builds every version of docs/packages/epam-indigo.yaml not released yet' + required: false + default: '' + pull_request: + branches: [main] + paths: + - '.github/workflows/build-epam-indigo.yml' + - 'docs/packages/epam-indigo.yaml' + - 'patches/epam-indigo/**' + push: + branches: [main] + paths: + - '.github/workflows/build-epam-indigo.yml' + - 'docs/packages/epam-indigo.yaml' + - 'patches/epam-indigo/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read # to fetch code (actions/checkout) + +jobs: + setup: + uses: $/.github/workflows/_setup.yml + with: + package: epam-indigo + version: ${{ inputs.version }} + + # setup.py loads the four C++ libraries via ctypes (ctypes.CDLL), keyed off + # platform.machine(), not the CPython ABI, so one py3-none wheel serves every + # interpreter - matching upstream's own fixed --plat-name list (api/python/setup.py), + # which this patches to add riscv64. + build_wheels: + needs: [setup] + if: needs.setup.outputs.versions != '[]' + name: Build epam-indigo ${{ matrix.version }} py3-none-manylinux_riscv64 + runs-on: ubuntu-24.04-riscv + timeout-minutes: 180 + container: + image: quay.io/pypa/manylinux_2_39_riscv64 + strategy: + fail-fast: false + matrix: + version: ${{ fromJSON(needs.setup.outputs.versions) }} + defaults: + run: + shell: bash + env: + EPAM_INDIGO_VERSION: ${{ matrix.version }} + + steps: + - name: Checkout indigo indigo-${{ env.EPAM_INDIGO_VERSION }} + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + repository: epam/indigo + ref: indigo-${{ env.EPAM_INDIGO_VERSION }} + persist-credentials: false + + - name: Checkout python-wheels + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + path: python-wheels + persist-credentials: false + + - name: Patch indigo source + run: git apply python-wheels/patches/epam-indigo/${{ env.EPAM_INDIGO_VERSION }}/*.patch + + - name: Use manylinux Python + run: echo "/opt/python/cp312-cp312/bin" >> "$GITHUB_PATH" + + - name: Install cmake + run: dnf install -y -q cmake + + # BUILD_STANDALONE (default ON) builds cairo/freetype/libpng/pixman/zlib/rapidjson/ + # lunasvg/tinyxml2 from the vendored third_party/ sources instead of linking the + # image's own, so the wheel's only runtime dependency beyond glibc is itself. None of + # them ship a LICENSE file in third_party/ except freetype, libpng, tinyxml2, inchi, + # cppcodec and object_threadsafe (copied as-is below); the rest are fetched from their + # upstream release matching the vendored third_party/ version. + - name: Stage bundled licences + run: | + cp LICENSE api/python/ + for f in \ + third_party/freetype/LICENSE.TXT \ + third_party/libpng/LICENSE \ + third_party/tinyxml2/LICENSE.txt \ + third_party/cppcodec/LICENSE \ + third_party/object_threadsafe/LICENSE \ + third_party/inchi/LICENCE \ + ; do + cp "$f" "api/python/LICENSE.$(basename "$(dirname "$f")")" + done + curl -fsSL -o api/python/LICENSE.cairo "https://gitlab.freedesktop.org/cairo/cairo/-/raw/1.18.4/COPYING" + curl -fsSL -o api/python/LICENSE.pixman "https://gitlab.freedesktop.org/pixman/pixman/-/raw/pixman-0.40.0/COPYING" + curl -fsSL -o api/python/LICENSE.zlib "https://raw.githubusercontent.com/madler/zlib/v1.3.1/LICENSE" + curl -fsSL -o api/python/LICENSE.rapidjson "https://raw.githubusercontent.com/Tencent/rapidjson/v1.1.0/license.txt" + curl -fsSL -o api/python/LICENSE.lunasvg "https://raw.githubusercontent.com/sammycage/lunasvg/v3.0.0/LICENSE" + + - name: Build the native libraries + run: | + mkdir build && cd build + cmake .. -DBUILD_INDIGO=ON -DBUILD_INDIGO_WRAPPERS=OFF -DBUILD_INDIGO_UTILS=OFF -DBUILD_BINGO=OFF -DBUILD_BINGO_ELASTIC=OFF -DENABLE_TESTS=OFF + cmake --build . --config Release --target all -- -j"$(nproc)" + + - name: Build the wheel + working-directory: api/python + run: | + pip install -q -U setuptools wheel + python3 setup.py bdist_wheel --python-tag py3 --plat-name manylinux_2_39_riscv64 + + - name: Check the wheel carries the native libraries and their licences + run: | + python3 - api/python/dist/*.whl <<'EOF' + import sys, zipfile + + libs = { + "indigo/lib/linux-riscv64/libindigo.so", + "indigo/lib/linux-riscv64/libindigo-inchi.so", + "indigo/lib/linux-riscv64/libindigo-renderer.so", + "indigo/lib/linux-riscv64/libbingo-nosql.so", + } + licences = { + "LICENSE", "LICENSE.freetype", "LICENSE.libpng", "LICENSE.tinyxml2", + "LICENSE.cppcodec", "LICENSE.object_threadsafe", "LICENSE.inchi", + "LICENSE.cairo", "LICENSE.pixman", "LICENSE.zlib", "LICENSE.rapidjson", + "LICENSE.lunasvg", + } + for whl in sys.argv[1:]: + names = zipfile.ZipFile(whl).namelist() + assert libs <= set(names), (whl, libs - set(names)) + found = {n.rsplit("/", 1)[-1] for n in names if ".dist-info/licenses/" in n} + assert found == licences, (whl, licences - found, found - licences) + print(whl, "ok") + EOF + + - name: Smoke-test the wheel + run: | + pip install -q --extra-index-url https://pypi.riseproject.dev/simple/ \ + api/python/dist/*.whl Pillow==10.3.0 "pytest==7.3.1" + cp -r api/python/tests /tmp/indigo-tests + cd /tmp/indigo-tests + python3 -m pytest -v + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: epam-indigo-${{ env.EPAM_INDIGO_VERSION }}-py3-none-manylinux_riscv64 + path: api/python/dist/*.whl + if-no-files-found: error + + publish: + name: Publish epam-indigo ${{ 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: epam-indigo-${{ matrix.version }}-*-manylinux_riscv64 diff --git a/docs/packages/epam-indigo.yaml b/docs/packages/epam-indigo.yaml new file mode 100644 index 000000000000..1af51b0cc628 --- /dev/null +++ b/docs/packages/epam-indigo.yaml @@ -0,0 +1,6 @@ +package-name: epam-indigo +source-code: https://github.com/epam/indigo/ +license: Apache-2.0 +versions: +- version: 1.46.0 + patched: true diff --git a/patches/epam-indigo/1.46.0/0001-python-recognize-manylinux_2_39_riscv64-plat-name.patch b/patches/epam-indigo/1.46.0/0001-python-recognize-manylinux_2_39_riscv64-plat-name.patch new file mode 100644 index 000000000000..1d6cbb9efba1 --- /dev/null +++ b/patches/epam-indigo/1.46.0/0001-python-recognize-manylinux_2_39_riscv64-plat-name.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ludovic Henry +Date: Tue, 13 Oct 2026 00:00:00 +0000 +Subject: [PATCH] python: recognize manylinux_2_39_riscv64 --plat-name + +Upstream-Status: Inappropriate [riscv64 is not one of setup.py's hardcoded --plat-name values] + +api/python/setup.py maps bdist_wheel's --plat-name to the +indigo/lib/-/*.so glob it bundles, from a hardcoded list of +platform strings (one per OS/arch upstream builds for in CI) and raises +ValueError for anything else. Add the riscv64 case, mapping +manylinux_2_39_riscv64 to lib/linux-riscv64/*.so, matching the existing +manylinux2014_aarch64 entry. + +Signed-off-by: Ludovic Henry +--- + api/python/setup.py | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/api/python/setup.py b/api/python/setup.py +index b3d934b..37f3390 100644 +--- a/api/python/setup.py ++++ b/api/python/setup.py +@@ -62,6 +62,8 @@ if sys.argv[1] == "bdist_wheel": + INDIGO_LIBS = "lib/darwin-aarch64/*.dylib" + elif PLATFORM_NAME == "manylinux2014_aarch64": + INDIGO_LIBS = "lib/linux-aarch64/*.so" ++ elif PLATFORM_NAME == "manylinux_2_39_riscv64": ++ INDIGO_LIBS = "lib/linux-riscv64/*.so" + elif PLATFORM_NAME == "manylinux1_x86_64": + INDIGO_LIBS = "lib/linux-x86_64/*.so" + elif PLATFORM_NAME == "manylinux1_i686": +@@ -78,7 +80,7 @@ if sys.argv[1] == "bdist_wheel": + raise ValueError( + "Wrong --plat-name value! Should be one of: macosx_11_0_arm64, " + "macosx_11_0_x86_64, manylinux1_x86_64, manylinux2014_aarch64, " +- "manylinux1_i686, win_amd64, win32" ++ "manylinux_2_39_riscv64, manylinux1_i686, win_amd64, win32" + ) + + if not glob.glob(os.path.join(indigo_python_directory, INDIGO_LIBS)): +-- +2.43.0 From efdea77d99068f2f107b54d31b5b1d46cbbf2fef Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Fri, 16 Oct 2026 01:05:51 +0000 Subject: [PATCH 2/4] build-epam-indigo: install freetype-devel and fontconfig-devel third_party/cairo/CMakeLists.txt links the system freetype and fontconfig (and hardcodes -I/usr/include/freetype2) on any non-Emscripten Unix build. The riscv64 job only installed cmake, so the cairo build failed with 'fatal error: ft2build.h: No such file or directory'. Both packages ship in Rocky's own repos on riscv64, no EPEL/CRB needed. --- .github/workflows/build-epam-indigo.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-epam-indigo.yml b/.github/workflows/build-epam-indigo.yml index 7c433f12d309..a304a01ba15b 100644 --- a/.github/workflows/build-epam-indigo.yml +++ b/.github/workflows/build-epam-indigo.yml @@ -81,8 +81,11 @@ jobs: - name: Use manylinux Python run: echo "/opt/python/cp312-cp312/bin" >> "$GITHUB_PATH" - - name: Install cmake - run: dnf install -y -q cmake + # third_party/cairo/CMakeLists.txt links the system freetype/fontconfig (and + # hardcodes -I/usr/include/freetype2) on any non-Emscripten Unix build; both + # ship in Rocky's own repos, no EPEL/CRB needed. + - name: Install build dependencies + run: dnf install -y -q cmake freetype-devel fontconfig-devel # BUILD_STANDALONE (default ON) builds cairo/freetype/libpng/pixman/zlib/rapidjson/ # lunasvg/tinyxml2 from the vendored third_party/ sources instead of linking the From 64b5a534b1c22b567cd4a55b5e3a72e5d88648d4 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Thu, 22 Oct 2026 10:38:41 +0000 Subject: [PATCH 3/4] build-epam-indigo: install libstdc++-static for -static-libstdc++ link --- .github/workflows/build-epam-indigo.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-epam-indigo.yml b/.github/workflows/build-epam-indigo.yml index a304a01ba15b..bc7e68919b03 100644 --- a/.github/workflows/build-epam-indigo.yml +++ b/.github/workflows/build-epam-indigo.yml @@ -83,9 +83,10 @@ jobs: # third_party/cairo/CMakeLists.txt links the system freetype/fontconfig (and # hardcodes -I/usr/include/freetype2) on any non-Emscripten Unix build; both - # ship in Rocky's own repos, no EPEL/CRB needed. + # ship in Rocky's own repos. cmake/setup.cmake links -static-libstdc++ under + # BUILD_STANDALONE, and Rocky 10 ships libstdc++.a separately in libstdc++-static (CRB). - name: Install build dependencies - run: dnf install -y -q cmake freetype-devel fontconfig-devel + run: dnf install -y -q cmake freetype-devel fontconfig-devel libstdc++-static # BUILD_STANDALONE (default ON) builds cairo/freetype/libpng/pixman/zlib/rapidjson/ # lunasvg/tinyxml2 from the vendored third_party/ sources instead of linking the From 58b4a577034b8f7e594ceeddc0123d58362fd8e4 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Fri, 23 Oct 2026 15:59:57 +0000 Subject: [PATCH 4/4] build-epam-indigo: pass --plat-name= to setup.py, install unpinned Pillow api/python/setup.py reads the platform with opt.split("=")[1], so "--plat-name manylinux_2_39_riscv64" (space-separated) raised IndexError. Use the --plat-name= --python-tag=py3 form of upstream's own api/python/CMakeLists.txt. The smoke test pinned Pillow==10.3.0 from requirements_dev.txt, which has no riscv64 wheel; its sdist build needs libjpeg headers the manylinux image lacks. Install Pillow unpinned, as upstream's test_indigo_python_* jobs do, with PIP_ONLY_BINARY=Pillow. --- .github/workflows/build-epam-indigo.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-epam-indigo.yml b/.github/workflows/build-epam-indigo.yml index bc7e68919b03..5aeb92f7dcf5 100644 --- a/.github/workflows/build-epam-indigo.yml +++ b/.github/workflows/build-epam-indigo.yml @@ -123,7 +123,7 @@ jobs: working-directory: api/python run: | pip install -q -U setuptools wheel - python3 setup.py bdist_wheel --python-tag py3 --plat-name manylinux_2_39_riscv64 + python3 setup.py bdist_wheel --plat-name=manylinux_2_39_riscv64 --python-tag=py3 - name: Check the wheel carries the native libraries and their licences run: | @@ -150,10 +150,14 @@ jobs: print(whl, "ok") EOF + # Unpinned Pillow as upstream's test_indigo_python_* jobs install it; requirements_dev.txt's + # Pillow==10.3.0 has no riscv64 wheel and its sdist needs libjpeg headers the image lacks. - name: Smoke-test the wheel + env: + PIP_ONLY_BINARY: Pillow run: | pip install -q --extra-index-url https://pypi.riseproject.dev/simple/ \ - api/python/dist/*.whl Pillow==10.3.0 "pytest==7.3.1" + api/python/dist/*.whl Pillow "pytest==7.3.1" cp -r api/python/tests /tmp/indigo-tests cd /tmp/indigo-tests python3 -m pytest -v