From 3b17a2f5542aa3a66b2feb8ebe666a051fb7c141 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Thu, 10 Sep 2026 12:11:06 +0200 Subject: [PATCH 1/7] shiboken6: add build-shiboken6.yml for riscv64 wheels Builds the shiboken6 module wheel from pyside/pyside-setup's git checkout. shiboken6's own Python bindings are self-generated by shiboken6-generator (needs Qt6Core + libclang), so the workflow builds and pip-installs that first, using Rocky 10's AppStream clang-devel/llvm-devel/qt6-qtbase-devel packages instead of compiling LLVM/Clang or Qt from source. --- .github/workflows/build-shiboken6.yml | 106 ++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 .github/workflows/build-shiboken6.yml diff --git a/.github/workflows/build-shiboken6.yml b/.github/workflows/build-shiboken6.yml new file mode 100644 index 000000000..583f9ffaf --- /dev/null +++ b/.github/workflows/build-shiboken6.yml @@ -0,0 +1,106 @@ +# SPDX-FileCopyrightText: 2026 The RISE Project +# SPDX-License-Identifier: MIT +--- +# Based on: https://code.qt.io/cgit/pyside/pyside-setup.git/tree/build_scripts/main.py?h=6.11.2 +name: Build shiboken6 wheels (riscv64) + +on: + workflow_dispatch: + inputs: + version: + description: 'shiboken6/pyside-setup tag to build (e.g. 6.11.2)' + required: true + default: '6.11.2' + pull_request: + paths: + - '.github/workflows/build-shiboken6.yml' + +concurrency: + group: ${{ github.workflow }}-${{ inputs.version || '6.11.2' }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read # to fetch code (actions/checkout) + +env: + SHIBOKEN_VERSION: ${{ inputs.version || '6.11.2' }} + MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64 + +jobs: + setup: + uses: $/.github/workflows/_setup.yml + + build_wheels: + needs: [setup] + name: Build shiboken6 ${{ inputs.version || '6.11.2' }} cp310-abi3-manylinux_riscv64 + runs-on: ubuntu-24.04-riscv + timeout-minutes: 360 + + steps: + - name: Checkout pyside-setup ${{ env.SHIBOKEN_VERSION }} + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + repository: pyside/pyside-setup + ref: ${{ env.SHIBOKEN_VERSION }} + persist-credentials: false + + - name: Pull manylinux_riscv64 image + run: docker pull "${MANYLINUX_RISCV64_IMAGE}" + + # shiboken6's own Python bindings are self-generated: shiboken6-generator (needs + # Qt6Core + libclang, both in Rocky 10's AppStream repo already) must be built and + # pip-installed first so `--build-type=shiboken6` can invoke it against + # typesystem_shiboken.xml. The generator wheel itself is never published (out of + # scope - see pyside6-essentials' queue entry). + - name: Build shiboken6-generator, then shiboken6 + run: | + docker run --rm -v "$(pwd):/work" -w /work \ + -e PIP_EXTRA_INDEX_URL=https://pypi.riseproject.dev/simple/ \ + "${MANYLINUX_RISCV64_IMAGE}" bash -c ' + set -euxo pipefail + dnf -y install clang-devel llvm-devel qt6-qtbase-devel + pybin=/opt/python/cp312-cp312/bin + "$pybin/pip" install -q \ + "setuptools==78.1.0" "packaging==24.2" "build==1.2.2.post1" \ + "wheel==0.46.3" "distro==1.9.0" "patchelf==0.17.2" + "$pybin/python3" setup.py bdist_wheel \ + --build-type=shiboken6-generator \ + --qtpaths=/usr/bin/qtpaths6 \ + --cmake=/usr/bin/cmake \ + --parallel="$(nproc)" \ + --skip-docs \ + --limited-api=yes \ + --plat-name=manylinux_2_39_riscv64 + "$pybin/pip" install -q dist/shiboken6_generator-*.whl + "$pybin/python3" setup.py bdist_wheel \ + --build-type=shiboken6 \ + --qtpaths=/usr/bin/qtpaths6 \ + --cmake=/usr/bin/cmake \ + --parallel="$(nproc)" \ + --skip-docs \ + --limited-api=yes \ + --plat-name=manylinux_2_39_riscv64 + "$pybin/pip" install -q auditwheel + "$pybin/python3" -m auditwheel repair --plat manylinux_2_39_riscv64 \ + -w audited dist/shiboken6-*.whl + rm -f dist/shiboken6-*.whl + mv audited/*.whl dist/ + "$pybin/pip" install -q dist/shiboken6-*.whl + "$pybin/python3" -c "import shiboken6; print(\"shiboken6 import OK\")" + ' + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: shiboken6-${{ env.SHIBOKEN_VERSION }}-cp310-abi3-manylinux_riscv64 + path: dist/shiboken6-*.whl + if-no-files-found: error + + publish: + name: Publish shiboken6 ${{ inputs.version || '6.11.2' }} + needs: [setup, build_wheels] + permissions: + contents: write + pull-requests: write + uses: $/.github/workflows/_publish-wheel.yml + with: + artifact-pattern: shiboken6-${{ inputs.version || '6.11.2' }}-*-manylinux_riscv64 From 9f366fe061afd78196a89580421754c735b095b5 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Thu, 10 Sep 2026 12:32:52 +0200 Subject: [PATCH 2/7] shiboken6: fetch patchelf's riscv64 release binary instead of building from PyPI Rocky 10's riscv64 repos ship no patchelf package (gotcha 95), so pip installing the patchelf PyPI package builds NixOS/patchelf from source, which runs its own `make check` and fails 8/48 tests on riscv64. pyside-setup's build_patchelf() only needs the binary on PATH, so fetch NixOS/patchelf's own riscv64 release asset instead. --- .github/workflows/build-shiboken6.yml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-shiboken6.yml b/.github/workflows/build-shiboken6.yml index 583f9ffaf..c24981d4f 100644 --- a/.github/workflows/build-shiboken6.yml +++ b/.github/workflows/build-shiboken6.yml @@ -25,6 +25,12 @@ permissions: env: SHIBOKEN_VERSION: ${{ inputs.version || '6.11.2' }} MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64 + # Rocky 10's riscv64 repos ship no patchelf package (gotcha 95), and pip installing + # the `patchelf` PyPI package builds NixOS/patchelf from source, which runs its own + # `make check` and fails 8/48 tests on riscv64. pyside-setup's build_patchelf() just + # needs the binary on PATH, so fetch NixOS/patchelf's own riscv64 release instead. + PATCHELF_VERSION: '0.17.2' + PATCHELF_SHA256: '4b28f7bc890c42076b2955be2229ac1607aa9a6d4ee40e33d69517ef0c403a56' jobs: setup: @@ -56,13 +62,20 @@ jobs: run: | docker run --rm -v "$(pwd):/work" -w /work \ -e PIP_EXTRA_INDEX_URL=https://pypi.riseproject.dev/simple/ \ + -e PATCHELF_VERSION="${PATCHELF_VERSION}" \ + -e PATCHELF_SHA256="${PATCHELF_SHA256}" \ "${MANYLINUX_RISCV64_IMAGE}" bash -c ' set -euxo pipefail dnf -y install clang-devel llvm-devel qt6-qtbase-devel + curl -fsSL -o /tmp/patchelf.tar.gz \ + "https://github.com/NixOS/patchelf/releases/download/${PATCHELF_VERSION}/patchelf-${PATCHELF_VERSION}-riscv64.tar.gz" + echo "${PATCHELF_SHA256} /tmp/patchelf.tar.gz" | sha256sum -c - + tar xzf /tmp/patchelf.tar.gz -C /usr/local + rm -f /tmp/patchelf.tar.gz pybin=/opt/python/cp312-cp312/bin "$pybin/pip" install -q \ "setuptools==78.1.0" "packaging==24.2" "build==1.2.2.post1" \ - "wheel==0.46.3" "distro==1.9.0" "patchelf==0.17.2" + "wheel==0.46.3" "distro==1.9.0" "$pybin/python3" setup.py bdist_wheel \ --build-type=shiboken6-generator \ --qtpaths=/usr/bin/qtpaths6 \ From b07650e4d60e0fa58bd1d168d9878ea16a2e1a02 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Thu, 10 Sep 2026 13:06:01 +0200 Subject: [PATCH 3/7] shiboken6: pip-install ninja and put it on PATH for cmake's -G Ninja pyside-setup defaults to the Ninja CMake generator on Linux (_AVAILABLE_MKSPECS[0]), but no ninja binary is present in the manylinux_riscv64 image and upstream's requirements.txt doesn't list one either (their own CI images ship it). PyPI publishes a riscv64 ninja wheel, but CMake's generator search needs it on PATH, not just reachable via the venv's bin dir. --- .github/workflows/build-shiboken6.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-shiboken6.yml b/.github/workflows/build-shiboken6.yml index c24981d4f..5a4844d52 100644 --- a/.github/workflows/build-shiboken6.yml +++ b/.github/workflows/build-shiboken6.yml @@ -73,9 +73,12 @@ jobs: tar xzf /tmp/patchelf.tar.gz -C /usr/local rm -f /tmp/patchelf.tar.gz pybin=/opt/python/cp312-cp312/bin + export PATH="$pybin:$PATH" + # pyside-setup defaults to -G Ninja on Linux; PATH needs $pybin so the + # cmake subprocess can find the pip-installed ninja binary. "$pybin/pip" install -q \ "setuptools==78.1.0" "packaging==24.2" "build==1.2.2.post1" \ - "wheel==0.46.3" "distro==1.9.0" + "wheel==0.46.3" "distro==1.9.0" "ninja==1.13.2" "$pybin/python3" setup.py bdist_wheel \ --build-type=shiboken6-generator \ --qtpaths=/usr/bin/qtpaths6 \ From 3e26c20c4323c2eb09e0ce637f31bdd23174ad4a Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Thu, 10 Sep 2026 13:34:52 +0200 Subject: [PATCH 4/7] shiboken6: link the manylinux static libpython into LIBDIR manylinux's CPython is built --disable-shared, so libpythonX.Y.a is installed under sysconfig's LIBPL (lib/pythonX.Y/config-*/), not LIBDIR or the Debian-style LIBDIR/MULTIARCH path that pyside-setup's build_info_collector.py searches, so its Python-library discovery fails. Symlink the static archive into LIBDIR where that search looks first; get_py_library() already accepts a static .a as a fallback. --- .github/workflows/build-shiboken6.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/build-shiboken6.yml b/.github/workflows/build-shiboken6.yml index 5a4844d52..0ac80c67d 100644 --- a/.github/workflows/build-shiboken6.yml +++ b/.github/workflows/build-shiboken6.yml @@ -79,6 +79,12 @@ jobs: "$pybin/pip" install -q \ "setuptools==78.1.0" "packaging==24.2" "build==1.2.2.post1" \ "wheel==0.46.3" "distro==1.9.0" "ninja==1.13.2" + # manylinux CPython is built --disable-shared: libpythonX.Y.a lands under + # sysconfig LIBPL (lib/pythonX.Y/config-*/), not LIBDIR or the Debian-style + # LIBDIR/MULTIARCH paths build_info_collector.py searches. Link it into LIBDIR. + libpl=$("$pybin/python3" -c "import sysconfig; print(sysconfig.get_config_var(\"LIBPL\"))") + libdir=$("$pybin/python3" -c "import sysconfig; print(sysconfig.get_config_var(\"LIBDIR\"))") + for f in "$libpl"/libpython*.a; do ln -sf "$f" "$libdir/$(basename "$f")"; done "$pybin/python3" setup.py bdist_wheel \ --build-type=shiboken6-generator \ --qtpaths=/usr/bin/qtpaths6 \ From 74238849c706b886eefbfefd8f5a3cfaf7ecc412 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Thu, 10 Sep 2026 14:03:30 +0200 Subject: [PATCH 5/7] shiboken6: restore libpython3.12.a from manylinux's own embedding tarball The previous symlink from sysconfig LIBPL was wrong: manylinux's finalize.sh strips every libpythonX.Y.a from lib/ to save space (before that, per its own build, the .a lives flat in LIBDIR, not under LIBPL), archiving them first into static-libs-for-embedding-only.tar.xz. Extracting that tarball puts libpython3.12.a back at the exact flat LIBDIR path build_info_collector.py's primary search checks first. Verified natively against the aarch64 manylinux_2_39 image (same finalize.sh, same layout) since riscv64 needs emulation locally. --- .github/workflows/build-shiboken6.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-shiboken6.yml b/.github/workflows/build-shiboken6.yml index 0ac80c67d..cc3860663 100644 --- a/.github/workflows/build-shiboken6.yml +++ b/.github/workflows/build-shiboken6.yml @@ -79,12 +79,10 @@ jobs: "$pybin/pip" install -q \ "setuptools==78.1.0" "packaging==24.2" "build==1.2.2.post1" \ "wheel==0.46.3" "distro==1.9.0" "ninja==1.13.2" - # manylinux CPython is built --disable-shared: libpythonX.Y.a lands under - # sysconfig LIBPL (lib/pythonX.Y/config-*/), not LIBDIR or the Debian-style - # LIBDIR/MULTIARCH paths build_info_collector.py searches. Link it into LIBDIR. - libpl=$("$pybin/python3" -c "import sysconfig; print(sysconfig.get_config_var(\"LIBPL\"))") - libdir=$("$pybin/python3" -c "import sysconfig; print(sysconfig.get_config_var(\"LIBDIR\"))") - for f in "$libpl"/libpython*.a; do ln -sf "$f" "$libdir/$(basename "$f")"; done + # manylinux finalize.sh strips every libpython*.a to save space, after + # archiving them into this tarball; shiboken6-generator embeds CPython and + # needs one back, at the flat LIBDIR path build_info_collector.py searches first. + tar xJf /opt/_internal/static-libs-for-embedding-only.tar.xz -C /opt/_internal "$pybin/python3" setup.py bdist_wheel \ --build-type=shiboken6-generator \ --qtpaths=/usr/bin/qtpaths6 \ From d1f34d1fd5f4784102c484a135f4c19fecdfb92e Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Thu, 10 Sep 2026 14:17:17 +0200 Subject: [PATCH 6/7] shiboken6: drop --plat-name from both setup.py bdist_wheel invocations PysideBuild.finalize_options() only fakes os.name to "nt" (to dodge distutils build.finalize_options' Windows-only --plat-name check) when cross-compiling or on macOS; on a native, non-cross-compiling Linux build --plat-name always hits that check and raises. auditwheel repair already retags the final wheel to manylinux_2_39_riscv64, and the shiboken6-generator wheel is never published, so the flag is not needed on either invocation. --- .github/workflows/build-shiboken6.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-shiboken6.yml b/.github/workflows/build-shiboken6.yml index cc3860663..8de4c1cb8 100644 --- a/.github/workflows/build-shiboken6.yml +++ b/.github/workflows/build-shiboken6.yml @@ -83,14 +83,16 @@ jobs: # archiving them into this tarball; shiboken6-generator embeds CPython and # needs one back, at the flat LIBDIR path build_info_collector.py searches first. tar xJf /opt/_internal/static-libs-for-embedding-only.tar.xz -C /opt/_internal + # --plat-name is only safe on Windows or macOS builds (PysideBuild finalize_options + # os-name hack does not cover native, non-cross-compiling Linux); auditwheel repair + # below retags the wheel to manylinux_2_39_riscv64 regardless. "$pybin/python3" setup.py bdist_wheel \ --build-type=shiboken6-generator \ --qtpaths=/usr/bin/qtpaths6 \ --cmake=/usr/bin/cmake \ --parallel="$(nproc)" \ --skip-docs \ - --limited-api=yes \ - --plat-name=manylinux_2_39_riscv64 + --limited-api=yes "$pybin/pip" install -q dist/shiboken6_generator-*.whl "$pybin/python3" setup.py bdist_wheel \ --build-type=shiboken6 \ @@ -98,8 +100,7 @@ jobs: --cmake=/usr/bin/cmake \ --parallel="$(nproc)" \ --skip-docs \ - --limited-api=yes \ - --plat-name=manylinux_2_39_riscv64 + --limited-api=yes "$pybin/pip" install -q auditwheel "$pybin/python3" -m auditwheel repair --plat manylinux_2_39_riscv64 \ -w audited dist/shiboken6-*.whl From 3761be9b4e210c61ca76d9ce02b27d52a59762dc Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Thu, 10 Sep 2026 14:43:32 +0200 Subject: [PATCH 7/7] shiboken6: install shiboken6-generator with --no-deps shiboken6-generator's wheel declares shiboken6==6.11.2 as a runtime dependency, but shiboken6 is not built yet at this point (it is the very next step), so pip fails to resolve it. --no-deps breaks the cycle; the generator install here only needs its CLI tool and typesystem files for the following setup.py invocation. --- .github/workflows/build-shiboken6.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-shiboken6.yml b/.github/workflows/build-shiboken6.yml index 8de4c1cb8..98d7e3e82 100644 --- a/.github/workflows/build-shiboken6.yml +++ b/.github/workflows/build-shiboken6.yml @@ -93,7 +93,9 @@ jobs: --parallel="$(nproc)" \ --skip-docs \ --limited-api=yes - "$pybin/pip" install -q dist/shiboken6_generator-*.whl + # shiboken6_generator declares a shiboken6==6.11.2 runtime dependency, which is + # not built yet (that is the next step); --no-deps breaks that build cycle. + "$pybin/pip" install -q --no-deps dist/shiboken6_generator-*.whl "$pybin/python3" setup.py bdist_wheel \ --build-type=shiboken6 \ --qtpaths=/usr/bin/qtpaths6 \