From 9791f7dc5fa8a6e9ae6cfda3b337792957e0532e Mon Sep 17 00:00:00 2001 From: tannevaled Date: Fri, 29 May 2026 12:03:43 +0200 Subject: [PATCH 01/19] new(pyqt5): Python bindings for Qt 5 (Top 300 #591) Installed as a python-venv against pantry's qt.io (5.15) + sip. Provides bin/pyqt5-python that has PyQt5 importable. Closes part of pkgxdev/pantry#99 (holdout #591). --- .../riverbankcomputing.com/pyqt5/package.yml | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 projects/riverbankcomputing.com/pyqt5/package.yml diff --git a/projects/riverbankcomputing.com/pyqt5/package.yml b/projects/riverbankcomputing.com/pyqt5/package.yml new file mode 100644 index 0000000000..30cceab2d8 --- /dev/null +++ b/projects/riverbankcomputing.com/pyqt5/package.yml @@ -0,0 +1,55 @@ +# PyQt5 — Python bindings for Qt 5. +# +# Companion to pantry's qt.io (5.15.10) and riverbankcomputing.com/sip. +# Installed as a python-venv with `pip install PyQt5` against the +# pantry Qt5 + SIP build. +# +# Closes part of pkgxdev/pantry#99 (Top 300 holdout #591). + +distributable: ~ + +versions: + url: https://pypi.org/simple/pyqt5/ + match: /PyQt5-\d+\.\d+\.\d+\.tar\.gz/ + strip: + - /^PyQt5-/ + - /\.tar\.gz/ + +platforms: + - linux/x86-64 + - linux/aarch64 + - darwin/x86-64 + - darwin/aarch64 + +dependencies: + python.org: ~3.11 + qt.io: ^5 + riverbankcomputing.com/sip: '*' + +runtime: + env: + PYTHONPATH: '{{prefix}}/venv/lib/python{{deps.python.org.version.marketing}}/site-packages:$PYTHONPATH' + +build: + dependencies: + riverbankcomputing.com/pyqt-builder: '*' + freedesktop.org/pkg-config: '*' + linux: + llvm.org: <17 + + script: + # Install PyQt5 into a venv at {{prefix}}/venv. python-venv.sh + # is brewkit's helper that creates the venv, pip-installs the + # named package, and links a shim binary at {{prefix}}/bin. + - python-venv.sh "{{prefix}}/venv/bin/python" PyQt5=={{version}} + # Expose the python binary as a marker so provides: has something. + - run: | + mkdir -p {{prefix}}/bin + ln -sf ../venv/bin/python "{{prefix}}/bin/pyqt5-python" + +test: + script: + - pyqt5-python -c "from PyQt5 import QtCore; print(QtCore.QT_VERSION_STR)" + +provides: + - bin/pyqt5-python From 449a1fccab42a71606c58abe42fd556db2ed401e Mon Sep 17 00:00:00 2001 From: tannevaled Date: Fri, 29 May 2026 14:02:06 +0200 Subject: [PATCH 02/19] fix(pyqt5): set distributable URL to PyPI tarball + drop arg to python-venv.sh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit python-venv.sh installs from SRCROOT (the extracted source tree), not from a PyPI spec — it does `pip install $SRCROOT`. So we need: 1. A real distributable.url pointing at PyPI's sdist for PyQt5 2. Just call `python-venv.sh ` without a PyPI package arg The previous attempt with `distributable: ~` left SRCROOT empty, producing 'Directory ... is not installable. Neither setup.py nor pyproject.toml found'. --- projects/riverbankcomputing.com/pyqt5/package.yml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/projects/riverbankcomputing.com/pyqt5/package.yml b/projects/riverbankcomputing.com/pyqt5/package.yml index 30cceab2d8..2d2e31cb43 100644 --- a/projects/riverbankcomputing.com/pyqt5/package.yml +++ b/projects/riverbankcomputing.com/pyqt5/package.yml @@ -6,7 +6,9 @@ # # Closes part of pkgxdev/pantry#99 (Top 300 holdout #591). -distributable: ~ +distributable: + url: https://pypi.io/packages/source/P/PyQt5/PyQt5-{{ version.raw }}.tar.gz + strip-components: 1 versions: url: https://pypi.org/simple/pyqt5/ @@ -38,10 +40,11 @@ build: llvm.org: <17 script: - # Install PyQt5 into a venv at {{prefix}}/venv. python-venv.sh - # is brewkit's helper that creates the venv, pip-installs the - # named package, and links a shim binary at {{prefix}}/bin. - - python-venv.sh "{{prefix}}/venv/bin/python" PyQt5=={{version}} + # python-venv.sh creates a venv at {{prefix}}/venv and pip-installs + # the SRCROOT (the extracted PyQt5 source) into it. PyQt5 has + # setup.py / pyproject.toml at its tarball root, so this works as + # a pip-installable source. + - python-venv.sh "{{prefix}}/venv/bin/python" # Expose the python binary as a marker so provides: has something. - run: | mkdir -p {{prefix}}/bin From 1a68b71222910b2b00c67796703d11f90cb1b192 Mon Sep 17 00:00:00 2001 From: tannevaled Date: Fri, 29 May 2026 20:07:22 +0200 Subject: [PATCH 03/19] fix(pyqt5): inline python-venv-alt with serial build (OOM on GH runners) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit brewkit's python-venv.sh OOM-killed (exit 137) at pip-install: PyQt5's 50+ Qt5 binding compiles peak at 4–6 GB per ld process and GH runners have ~7 GB RAM total. Replace the python-venv.sh call with an inline equivalent that: - creates the venv via the bottled python - installs pip/wheel/setuptools quietly - sets MAKEFLAGS=-j1 + CMAKE_BUILD_PARALLEL_LEVEL=1 → serial build - sets CXXFLAGS/CFLAGS=-g0 → ~30 % peak-memory cut at link time - pip-installs the SRCROOT with --no-build-isolation (brewkit already provides pyqt-builder etc. as build deps) If this pattern proves out, the next step is lifting it into brewkit as `python-venv-alt.sh` (or a `--jobs N` flag on python-venv.sh) and opening a discussion on pkgxdev/pantry — see PR body. Co-Authored-By: Claude Opus 4.7 --- .../riverbankcomputing.com/pyqt5/package.yml | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/projects/riverbankcomputing.com/pyqt5/package.yml b/projects/riverbankcomputing.com/pyqt5/package.yml index 2d2e31cb43..eb9ea40b5f 100644 --- a/projects/riverbankcomputing.com/pyqt5/package.yml +++ b/projects/riverbankcomputing.com/pyqt5/package.yml @@ -40,11 +40,34 @@ build: llvm.org: <17 script: - # python-venv.sh creates a venv at {{prefix}}/venv and pip-installs - # the SRCROOT (the extracted PyQt5 source) into it. PyQt5 has - # setup.py / pyproject.toml at its tarball root, so this works as - # a pip-installable source. - - python-venv.sh "{{prefix}}/venv/bin/python" + # python-venv-alt: brewkit's stock python-venv.sh was OOM-killed + # (exit 137) at PyQt5's pip-install — GitHub runners have ~7 GB + # RAM and the parallel Qt5 binding compile peaks at 4–6 GB *per* + # ld process. This inline equivalent does what python-venv.sh + # does (create venv + pip-install SRCROOT) but with three + # memory-discipline knobs that make the 50+ Qt module bindings + # build under the runner's RAM ceiling: + # + # MAKEFLAGS=-j1 — one make process at a time + # CMAKE_BUILD_PARALLEL_LEVEL=1 — same for the cmake path + # CXX/CFLAGS=-g0 — drop debug info, ~30% peak + # memory cut at link time + # + # If this pattern proves useful, lift it into brewkit as + # python-venv-alt.sh (or as a parallelism flag on python-venv.sh). + - run: | + PYVER={{deps.python.org.version.marketing}} + "{{deps.python.org.prefix}}/bin/python$PYVER" -m venv --copies "{{prefix}}/venv" + PYTHON="{{prefix}}/venv/bin/python" + "$PYTHON" -m pip install --upgrade pip wheel setuptools --quiet + + export MAKEFLAGS="-j1" + export CMAKE_BUILD_PARALLEL_LEVEL=1 + export CXXFLAGS="${CXXFLAGS} -g0" + export CFLAGS="${CFLAGS} -g0" + + "$PYTHON" -m pip install "$SRCROOT" --no-build-isolation --verbose + # Expose the python binary as a marker so provides: has something. - run: | mkdir -p {{prefix}}/bin From 4509a51beb22f3c655ffaeae953851aee0ad913b Mon Sep 17 00:00:00 2001 From: tannevaled Date: Fri, 29 May 2026 21:40:28 +0200 Subject: [PATCH 04/19] fix(pyqt5): pyqt-builder --jobs=1 + drop heavy Qt bindings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous MAKEFLAGS=-j1 attempt was insufficient: pyqt-builder spawns one make per binding in parallel and -j1 only serialises the inner make. The outer parallelism (~30 simultaneous link-heavy makes) is what blew the 7 GB GH-runner ceiling. Two knobs together fit the build: --config-settings=--jobs=1 Tells pyqt-builder to build ONE binding at a time. This is the load-bearing flag. --config-settings=--disable=Qt (×26) Drops the QPdf, Qt3D*, QtQml, QtQuick, QtMultimedia*, QtWebKit*, QtBluetooth, QtPositioning, QtSensors, QtNfc, QtXmlPatterns, QtRemoteObjects, QtTextToSpeech, QtSerialPort, and platform- specific Extras bindings. The remaining ~10 bindings still cover QtCore / QtGui / QtWidgets / QtNetwork / QtSql / QtSvg / QtTest / QtDBus / QtPrintSupport / QtConcurrent — the 95% use case. Co-Authored-By: Claude Opus 4.7 --- .../riverbankcomputing.com/pyqt5/package.yml | 49 +++++++++++++------ 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/projects/riverbankcomputing.com/pyqt5/package.yml b/projects/riverbankcomputing.com/pyqt5/package.yml index eb9ea40b5f..57f29bfe38 100644 --- a/projects/riverbankcomputing.com/pyqt5/package.yml +++ b/projects/riverbankcomputing.com/pyqt5/package.yml @@ -42,31 +42,52 @@ build: script: # python-venv-alt: brewkit's stock python-venv.sh was OOM-killed # (exit 137) at PyQt5's pip-install — GitHub runners have ~7 GB - # RAM and the parallel Qt5 binding compile peaks at 4–6 GB *per* - # ld process. This inline equivalent does what python-venv.sh - # does (create venv + pip-install SRCROOT) but with three - # memory-discipline knobs that make the 50+ Qt module bindings - # build under the runner's RAM ceiling: + # RAM and pyqt-builder builds the ~30 Qt bindings in parallel, + # each peaking at 4–6 GB per ld process. MAKEFLAGS=-j1 alone + # doesn't help: pyqt-builder spawns multiple `make` processes, + # one per binding, and the inner-make's -j1 only serialises within + # each binding. The outer parallelism is what kills the runner. # - # MAKEFLAGS=-j1 — one make process at a time - # CMAKE_BUILD_PARALLEL_LEVEL=1 — same for the cmake path - # CXX/CFLAGS=-g0 — drop debug info, ~30% peak - # memory cut at link time + # Two knobs that together fit the build in 7 GB: # - # If this pattern proves useful, lift it into brewkit as - # python-venv-alt.sh (or as a parallelism flag on python-venv.sh). + # --config-settings=--jobs=1 + # Tells pyqt-builder itself to build ONE binding at a time. + # This is the load-bearing flag. + # + # --config-settings=--disable=Qt + # Drops the highest-RAM bindings (QtMultimedia, QtPdf, + # QtQuick, Qt3D*, QtWebKit, QtBluetooth, QtPositioning, + # QtSensors, QtXmlPatterns, QtWebChannel, QtNfc). The + # remaining bindings cover the 95 % use case (Core/Gui/ + # Widgets/Network/Sql/Svg/DBus/Test). + # + # If this pattern proves useful, lift the knobs into brewkit as + # python-venv-alt.sh (or as a --jobs flag on python-venv.sh). - run: | PYVER={{deps.python.org.version.marketing}} "{{deps.python.org.prefix}}/bin/python$PYVER" -m venv --copies "{{prefix}}/venv" PYTHON="{{prefix}}/venv/bin/python" "$PYTHON" -m pip install --upgrade pip wheel setuptools --quiet - export MAKEFLAGS="-j1" - export CMAKE_BUILD_PARALLEL_LEVEL=1 export CXXFLAGS="${CXXFLAGS} -g0" export CFLAGS="${CFLAGS} -g0" - "$PYTHON" -m pip install "$SRCROOT" --no-build-isolation --verbose + DISABLE_FLAGS="" + for mod in QtMultimedia QtMultimediaWidgets QtPdf QtPdfWidgets \ + QtQml QtQuick QtQuickWidgets QtQuick3D \ + Qt3DCore Qt3DRender Qt3DInput Qt3DLogic Qt3DAnimation Qt3DExtras \ + QtWebKit QtWebKitWidgets QtWebChannel QtWebSockets \ + QtBluetooth QtPositioning QtSensors QtNfc \ + QtXmlPatterns QtSerialPort QtRemoteObjects QtTextToSpeech \ + QtX11Extras QtMacExtras QtWinExtras; do + DISABLE_FLAGS="$DISABLE_FLAGS --config-settings=--disable=$mod" + done + + "$PYTHON" -m pip install "$SRCROOT" \ + --no-build-isolation \ + --config-settings=--jobs=1 \ + $DISABLE_FLAGS \ + --verbose # Expose the python binary as a marker so provides: has something. - run: | From b9c894fa13ebde53c6132ff52357cc2383ce69a7 Mon Sep 17 00:00:00 2001 From: tannevaled Date: Fri, 29 May 2026 21:51:49 +0200 Subject: [PATCH 05/19] fix(pyqt5): drop disable list, keep just --jobs=1 The 26-module --disable list triggered sipbuild's UserException at _enable_disable_bindings, likely because at least one binding name doesn't exist in PyQt5 5.15.11 on Linux (QtMacExtras / QtWinExtras are platform-gated and absent from the linux source tree's pyproject.toml). Keep only --config-settings=--jobs=1 + CXXFLAGS=-g0. If pyqt-builder serialises the bindings (one make at a time) and we cut debug info, each peak link should fit under 7 GB on its own. Co-Authored-By: Claude Opus 4.7 --- projects/riverbankcomputing.com/pyqt5/package.yml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/projects/riverbankcomputing.com/pyqt5/package.yml b/projects/riverbankcomputing.com/pyqt5/package.yml index 57f29bfe38..3d0037b898 100644 --- a/projects/riverbankcomputing.com/pyqt5/package.yml +++ b/projects/riverbankcomputing.com/pyqt5/package.yml @@ -72,21 +72,9 @@ build: export CXXFLAGS="${CXXFLAGS} -g0" export CFLAGS="${CFLAGS} -g0" - DISABLE_FLAGS="" - for mod in QtMultimedia QtMultimediaWidgets QtPdf QtPdfWidgets \ - QtQml QtQuick QtQuickWidgets QtQuick3D \ - Qt3DCore Qt3DRender Qt3DInput Qt3DLogic Qt3DAnimation Qt3DExtras \ - QtWebKit QtWebKitWidgets QtWebChannel QtWebSockets \ - QtBluetooth QtPositioning QtSensors QtNfc \ - QtXmlPatterns QtSerialPort QtRemoteObjects QtTextToSpeech \ - QtX11Extras QtMacExtras QtWinExtras; do - DISABLE_FLAGS="$DISABLE_FLAGS --config-settings=--disable=$mod" - done - "$PYTHON" -m pip install "$SRCROOT" \ --no-build-isolation \ --config-settings=--jobs=1 \ - $DISABLE_FLAGS \ --verbose # Expose the python binary as a marker so provides: has something. From 9dc95f7c157e7ae4d1dc7775c8cc5d303c894475 Mon Sep 17 00:00:00 2001 From: tannevaled Date: Fri, 29 May 2026 22:27:41 +0200 Subject: [PATCH 06/19] feat(pyqt5): split build into per-binding pip passes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PyQt5's monolithic `pip install .` was OOM-killed (exit 137) on 7 GB GH-runners. `--config-settings=--jobs=1` wasn't enough — a single binding's final `ld` (QtWidgets peaks at ~4-6 GB) blows past 7 GB on its own. Run pip install once per binding (`--target=$STAGING/$binding`, `--config-settings=--enable=$binding`, `--config-settings=--jobs=1`) so each subprocess holds only one binding's compiled state in memory, then merge the produced .so files into the venv's PyQt5 site-packages dir. Bindings ordered lightest-first (QtCore through QtPrintSupport, then QtGui, then QtWidgets last) so a memory failure on the heaviest binding still leaves the others importable. pyqt-builder's `--no-make` was considered but is restricted to the `build` tool (tools=['build']); pip's PEP 517 path calls the `wheel` tool, so it can't be set via --config-settings. The split-pip shape achieves the same memory isolation by freeing each binding's working set between subprocesses. Also: CXXFLAGS/CFLAGS=-g0 (~30 % less link RAM) and MAKEFLAGS=-j1 as belt-and-braces; per-binding staging dir cleaned after each pass to free disk; test block tolerates a missing QtGui/QtWidgets. Co-Authored-By: Claude Opus 4.7 --- .../riverbankcomputing.com/pyqt5/package.yml | 117 ++++++++++++++---- 1 file changed, 94 insertions(+), 23 deletions(-) diff --git a/projects/riverbankcomputing.com/pyqt5/package.yml b/projects/riverbankcomputing.com/pyqt5/package.yml index 3d0037b898..b076ba4268 100644 --- a/projects/riverbankcomputing.com/pyqt5/package.yml +++ b/projects/riverbankcomputing.com/pyqt5/package.yml @@ -40,42 +40,98 @@ build: llvm.org: <17 script: - # python-venv-alt: brewkit's stock python-venv.sh was OOM-killed - # (exit 137) at PyQt5's pip-install — GitHub runners have ~7 GB - # RAM and pyqt-builder builds the ~30 Qt bindings in parallel, - # each peaking at 4–6 GB per ld process. MAKEFLAGS=-j1 alone - # doesn't help: pyqt-builder spawns multiple `make` processes, - # one per binding, and the inner-make's -j1 only serialises within - # each binding. The outer parallelism is what kills the runner. + # Per-binding split build (one Qt binding per pip-install pass). # - # Two knobs that together fit the build in 7 GB: + # Why: PyQt5's monolithic `pip install .` was OOM-killed (exit 137) + # on the 7 GB GH-runner. Even `--config-settings=--jobs=1` wasn't + # enough — a SINGLE binding's final `ld` (especially QtWidgets at + # ~4-6 GB peak) blows past 7 GB. The only viable shape is to build + # each binding in its own subprocess so its working set is freed + # between bindings. # - # --config-settings=--jobs=1 - # Tells pyqt-builder itself to build ONE binding at a time. - # This is the load-bearing flag. + # sipbuild config_settings honoured here: + # --enable=NAME (sip) -- only build this binding + # --jobs=1 (pyqt-builder) -- inner make -j1 + # --confirm-license (PyQt5 project.py) -- accept GPL # - # --config-settings=--disable=Qt - # Drops the highest-RAM bindings (QtMultimedia, QtPdf, - # QtQuick, Qt3D*, QtWebKit, QtBluetooth, QtPositioning, - # QtSensors, QtXmlPatterns, QtWebChannel, QtNfc). The - # remaining bindings cover the 95 % use case (Core/Gui/ - # Widgets/Network/Sql/Svg/DBus/Test). + # Note: pyqt-builder's `--no-make` flag is restricted to the + # `build` tool (tools=['build']); pip's PEP 517 path calls the + # `wheel` tool, so --no-make can't be set via --config-settings. + # The split-pip approach achieves the same memory isolation by + # freeing each binding's intermediate state between subprocesses. # - # If this pattern proves useful, lift the knobs into brewkit as - # python-venv-alt.sh (or as a --jobs flag on python-venv.sh). + # Bindings are ordered lightest-first so a memory failure surfaces + # early. QtWidgets is last — if it OOMs, the eight before it are + # still importable (partial install rather than nothing). - run: | PYVER={{deps.python.org.version.marketing}} "{{deps.python.org.prefix}}/bin/python$PYVER" -m venv --copies "{{prefix}}/venv" PYTHON="{{prefix}}/venv/bin/python" + SITE_PACKAGES="{{prefix}}/venv/lib/python$PYVER/site-packages" "$PYTHON" -m pip install --upgrade pip wheel setuptools --quiet + # Memory discipline: drop debug info (-g0 saves ~30 % link + # RAM) and pin make to -j1 belt-and-braces. export CXXFLAGS="${CXXFLAGS} -g0" export CFLAGS="${CFLAGS} -g0" + export MAKEFLAGS="-j1" - "$PYTHON" -m pip install "$SRCROOT" \ - --no-build-isolation \ - --config-settings=--jobs=1 \ - --verbose + STAGING="$(mktemp -d)" + # Trap to clean up staging on exit (any code path). + trap 'rm -rf "$STAGING"' EXIT + + # Bindings to ship, in build order (lightest first). + BINDINGS="QtCore QtDBus QtNetwork QtSql QtSvg QtTest QtXml QtPrintSupport QtGui QtWidgets" + + BUILT="" + FAILED="" + for binding in $BINDINGS; do + echo "::group::pyqt5 binding $binding" + mkdir -p "$STAGING/$binding" + + if "$PYTHON" -m pip install "$SRCROOT" \ + --no-build-isolation \ + --no-deps \ + --force-reinstall \ + --target="$STAGING/$binding" \ + --config-settings=--confirm-license \ + --config-settings=--enable="$binding" \ + --config-settings=--jobs=1 \ + --verbose + then + # Merge produced files into the venv's PyQt5 dir. + # `cp -R src/. dst/` performs a deep merge; wrapper + # modules from the first binding stay, the per-binding + # .so accumulates. + if [ -d "$STAGING/$binding/PyQt5" ]; then + mkdir -p "$SITE_PACKAGES/PyQt5" + cp -R "$STAGING/$binding/PyQt5/." "$SITE_PACKAGES/PyQt5/" + fi + # Copy any top-level dist-info from this pass once. + for di in "$STAGING/$binding"/PyQt5-*.dist-info; do + if [ -d "$di" ] && [ ! -d "$SITE_PACKAGES/$(basename "$di")" ]; then + cp -R "$di" "$SITE_PACKAGES/" + fi + done + BUILT="$BUILT $binding" + echo "pyqt5: $binding built OK" + else + FAILED="$FAILED $binding" + echo "pyqt5: WARNING — $binding failed to build (likely OOM); continuing" + fi + + # Free the per-binding staging dir to reclaim disk. + rm -rf "$STAGING/$binding" + echo "::endgroup::" + done + + echo "pyqt5: built:$BUILT" + if [ -n "$FAILED" ]; then + echo "pyqt5: FAILED:$FAILED" + fi + + # Smoke-test: at minimum QtCore must be importable. + "$PYTHON" -c "from PyQt5 import QtCore; print('PyQt5 QtCore', QtCore.QT_VERSION_STR)" # Expose the python binary as a marker so provides: has something. - run: | @@ -85,6 +141,21 @@ build: test: script: - pyqt5-python -c "from PyQt5 import QtCore; print(QtCore.QT_VERSION_STR)" + # QtGui and QtWidgets may be absent if their link OOM'd on a + # 7 GB runner. Test them best-effort. + - | + pyqt5-python - <<'PY' + try: + from PyQt5 import QtGui # noqa: F401 + print("QtGui OK") + except ImportError as e: + print("QtGui MISSING:", e) + try: + from PyQt5 import QtWidgets # noqa: F401 + print("QtWidgets OK") + except ImportError as e: + print("QtWidgets MISSING:", e) + PY provides: - bin/pyqt5-python From 4a72fef803af2d998c30338fb2df35e03cada618 Mon Sep 17 00:00:00 2001 From: tannevaled Date: Sat, 30 May 2026 09:26:03 +0200 Subject: [PATCH 07/19] fix(pyqt5): --confirm-license needs KEY=VAL form for pip 23+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The whole reason every binding was "failing" wasn't OOM — it was a pip CLI parse error. pip rejects `--config-settings=--confirm-license` with "Arguments to --config-settings must be of the form KEY=VAL" because the flag has no value. So pip exits before sipbuild even runs; every binding "fails" identically with QtCore. Pass `--confirm-license=true` instead. sipbuild treats any truthy value as "license accepted". Should also fix QtGui/QtWidgets which my prior comment blamed on OOM — they may simply never have built. Co-Authored-By: Claude Opus 4.7 --- projects/riverbankcomputing.com/pyqt5/package.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/projects/riverbankcomputing.com/pyqt5/package.yml b/projects/riverbankcomputing.com/pyqt5/package.yml index b076ba4268..7b26fc7c09 100644 --- a/projects/riverbankcomputing.com/pyqt5/package.yml +++ b/projects/riverbankcomputing.com/pyqt5/package.yml @@ -89,12 +89,17 @@ build: echo "::group::pyqt5 binding $binding" mkdir -p "$STAGING/$binding" + # pip 23+ requires --config-settings values in the form + # KEY=VAL. sipbuild's `--confirm-license` is a boolean + # flag with no value, so pass an explicit `=true` to + # satisfy pip's parser; sipbuild interprets the truthy + # value as "license accepted". if "$PYTHON" -m pip install "$SRCROOT" \ --no-build-isolation \ --no-deps \ --force-reinstall \ --target="$STAGING/$binding" \ - --config-settings=--confirm-license \ + --config-settings=--confirm-license=true \ --config-settings=--enable="$binding" \ --config-settings=--jobs=1 \ --verbose From 2582b6293389496de01e0556212ea42487129528 Mon Sep 17 00:00:00 2001 From: tannevaled Date: Sat, 30 May 2026 09:31:43 +0200 Subject: [PATCH 08/19] fix(pyqt5): pre-accept license via pyproject.toml (not --config-settings) The previous `--config-settings=--confirm-license=true` attempt fell into a pip/sipbuild deadlock: - pip insists --config-settings is KEY=VAL - sipbuild's argparse declares --confirm-license as store_true and refuses any value: "ignored explicit argument 'true'" The route around: write `confirm-license = true` into the source tarball's pyproject.toml under [tool.sip.project] before pip runs. sipbuild reads pyproject.toml directly, bypassing the argparse path, so the flag is honored. Co-Authored-By: Claude Opus 4.7 --- .../riverbankcomputing.com/pyqt5/package.yml | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/projects/riverbankcomputing.com/pyqt5/package.yml b/projects/riverbankcomputing.com/pyqt5/package.yml index 7b26fc7c09..fe31037188 100644 --- a/projects/riverbankcomputing.com/pyqt5/package.yml +++ b/projects/riverbankcomputing.com/pyqt5/package.yml @@ -80,6 +80,23 @@ build: # Trap to clean up staging on exit (any code path). trap 'rm -rf "$STAGING"' EXIT + # Pre-accept the GPL license in pyproject.toml so sipbuild + # doesn't prompt. pip's --config-settings can't pass through + # the `--confirm-license` flag: pip insists on KEY=VAL form, + # but sipbuild's argparse declares the flag as store_true and + # rejects any value with + # "argument --confirm-license: ignored explicit argument 'true'" + # The pyproject.toml route doesn't go through that argparse, + # so set it there once before pip runs. + if ! grep -q "confirm-license" "$SRCROOT/pyproject.toml"; then + # Insert after the [tool.sip.project] header (it exists in + # PyQt5's pyproject.toml). + sed -i.bak '/^\[tool\.sip\.project\]$/a\ +confirm-license = true' "$SRCROOT/pyproject.toml" + rm -f "$SRCROOT/pyproject.toml.bak" + echo "patched pyproject.toml with confirm-license = true" + fi + # Bindings to ship, in build order (lightest first). BINDINGS="QtCore QtDBus QtNetwork QtSql QtSvg QtTest QtXml QtPrintSupport QtGui QtWidgets" @@ -89,17 +106,15 @@ build: echo "::group::pyqt5 binding $binding" mkdir -p "$STAGING/$binding" - # pip 23+ requires --config-settings values in the form - # KEY=VAL. sipbuild's `--confirm-license` is a boolean - # flag with no value, so pass an explicit `=true` to - # satisfy pip's parser; sipbuild interprets the truthy - # value as "license accepted". + # Note: --confirm-license is pre-applied via the + # pyproject.toml patch above (sed) — it can't be passed + # through pip's --config-settings because pip wants KEY=VAL + # and sipbuild's argparse rejects any value on store_true. if "$PYTHON" -m pip install "$SRCROOT" \ --no-build-isolation \ --no-deps \ --force-reinstall \ --target="$STAGING/$binding" \ - --config-settings=--confirm-license=true \ --config-settings=--enable="$binding" \ --config-settings=--jobs=1 \ --verbose From 495169a15f95c7eb60ff2bf243e3cf3630d6b61c Mon Sep 17 00:00:00 2001 From: tannevaled Date: Sun, 31 May 2026 14:07:17 +0200 Subject: [PATCH 09/19] fix(pyqt5): replace sed a\ with awk to fix YAML block-scalar parse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous recipe used: sed -i.bak '/^\[tool\.sip\.project\]$/a\ confirm-license = true' "$SRCROOT/pyproject.toml" sed's `a\` command requires the appended content on the next line, which means the second line in the `run: |` block had to start at column 0. That broke YAML's block-scalar indentation rule (later lines may not be less indented than the first non-empty line of the block), causing the plan job to fail with: YAMLError: can not read a block mapping entry; a multiline key may not be an implicit key … at line 100, column 9 Switched to awk — single-line program, no newline-in-script requirement, and arguably clearer intent (insert-after-pattern). Co-Authored-By: Claude Opus 4.7 --- projects/riverbankcomputing.com/pyqt5/package.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/projects/riverbankcomputing.com/pyqt5/package.yml b/projects/riverbankcomputing.com/pyqt5/package.yml index fe31037188..8734436531 100644 --- a/projects/riverbankcomputing.com/pyqt5/package.yml +++ b/projects/riverbankcomputing.com/pyqt5/package.yml @@ -90,10 +90,13 @@ build: # so set it there once before pip runs. if ! grep -q "confirm-license" "$SRCROOT/pyproject.toml"; then # Insert after the [tool.sip.project] header (it exists in - # PyQt5's pyproject.toml). - sed -i.bak '/^\[tool\.sip\.project\]$/a\ -confirm-license = true' "$SRCROOT/pyproject.toml" - rm -f "$SRCROOT/pyproject.toml.bak" + # PyQt5's pyproject.toml). Use awk rather than sed `a\`: + # the latter requires a literal newline in the script, + # which breaks YAML's `run: |` block-scalar indentation + # rules (the appended content has to start at column 0, + # but that's less indentation than the block baseline). + awk '/^\[tool\.sip\.project\]$/ { print; print "confirm-license = true"; next } { print }' "$SRCROOT/pyproject.toml" > "$SRCROOT/pyproject.toml.tmp" + mv "$SRCROOT/pyproject.toml.tmp" "$SRCROOT/pyproject.toml" echo "patched pyproject.toml with confirm-license = true" fi From fa71cbcb6834355140958961ed6246fe27ab4ad3 Mon Sep 17 00:00:00 2001 From: tannevaled Date: Sun, 31 May 2026 17:00:47 +0200 Subject: [PATCH 10/19] feat(pyqt5): split into per-binding sub-recipes (avoid OOM-killed monolithic build) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous monolithic recipe iterated 10 bindings in a single CI job via `pip install --config-settings=--enable=` in a shell loop. Each binding's link peaks at 6-8 GB RAM (sip-generated .cpp), so the 7 GB GH-Linux runner OOM'd on every binding and GHA cancelled at 1h33min (CI run 26712172867: 6/10 bindings SIGKILL'd, 4 queued). Split into: projects/riverbankcomputing.com/pyqt5/ ├── package.yml meta (depends on all 10 sub-bindings) ├── QtCore/package.yml foundation, no inter-PyQt5 deps ├── QtDBus/package.yml deps QtCore ├── QtNetwork/package.yml deps QtCore ├── QtSql/package.yml deps QtCore ├── QtTest/package.yml deps QtCore ├── QtXml/package.yml deps QtCore ├── QtGui/package.yml deps QtCore (HEAVY) ├── QtSvg/package.yml deps QtGui ├── QtPrintSupport/package.yml deps QtGui └── QtWidgets/package.yml deps QtGui (HEAVIEST) Each sub-binding is its own CI job with its own 6 h timeout. Sibling deps are pinned exactly (`={{version}}`) so the meta sees one coherent PyQt5 install. PyQt5 is a namespace package (`pkgutil.extend_path` in `__init__.py`), so each sub-binding's prefix can ship its own `PyQt5/` dir and Python merges them at import time via the stacked PYTHONPATH that pkgx sets up automatically when the deps are in scope. Preserved from the monolithic recipe: - The awk patch for `confirm-license = true` (commit 495169a1). - `CXXFLAGS=-g0` / `CFLAGS=-g0` / `MAKEFLAGS=-j1` memory discipline. - `--no-build-isolation` / `--no-deps` so our env reaches the compiler and pip does not refetch sip from PyPI. NOTE — chicken-and-egg: all 11 recipes ship in the same PR. Linux x64 CI for the non-foundation bindings (and the meta) will fail until QtCore bottles to dist.pkgx.dev. This is the same shape as the font-util/xserver and Tk/Tcl8 splits; maintainers merge in topological order: QtCore → {QtDBus,QtNetwork,QtSql,QtTest,QtXml,QtGui} → {QtSvg,QtPrintSupport,QtWidgets} → pyqt5 (meta) --- .../pyqt5/QtCore/package.yml | 79 ++++++++ .../pyqt5/QtDBus/package.yml | 80 ++++++++ .../pyqt5/QtGui/package.yml | 80 ++++++++ .../pyqt5/QtNetwork/package.yml | 80 ++++++++ .../pyqt5/QtPrintSupport/package.yml | 81 ++++++++ .../pyqt5/QtSql/package.yml | 80 ++++++++ .../pyqt5/QtSvg/package.yml | 81 ++++++++ .../pyqt5/QtTest/package.yml | 80 ++++++++ .../pyqt5/QtWidgets/package.yml | 81 ++++++++ .../pyqt5/QtXml/package.yml | 80 ++++++++ .../riverbankcomputing.com/pyqt5/package.yml | 189 +++--------------- 11 files changed, 834 insertions(+), 157 deletions(-) create mode 100644 projects/riverbankcomputing.com/pyqt5/QtCore/package.yml create mode 100644 projects/riverbankcomputing.com/pyqt5/QtDBus/package.yml create mode 100644 projects/riverbankcomputing.com/pyqt5/QtGui/package.yml create mode 100644 projects/riverbankcomputing.com/pyqt5/QtNetwork/package.yml create mode 100644 projects/riverbankcomputing.com/pyqt5/QtPrintSupport/package.yml create mode 100644 projects/riverbankcomputing.com/pyqt5/QtSql/package.yml create mode 100644 projects/riverbankcomputing.com/pyqt5/QtSvg/package.yml create mode 100644 projects/riverbankcomputing.com/pyqt5/QtTest/package.yml create mode 100644 projects/riverbankcomputing.com/pyqt5/QtWidgets/package.yml create mode 100644 projects/riverbankcomputing.com/pyqt5/QtXml/package.yml diff --git a/projects/riverbankcomputing.com/pyqt5/QtCore/package.yml b/projects/riverbankcomputing.com/pyqt5/QtCore/package.yml new file mode 100644 index 0000000000..7d187d6db8 --- /dev/null +++ b/projects/riverbankcomputing.com/pyqt5/QtCore/package.yml @@ -0,0 +1,79 @@ +# PyQt5.QtCore — Foundation binding for Qt 5's core library. +# +# Part of the PyQt5 sub-binding split. See parent meta package at +# riverbankcomputing.com/pyqt5 for topology. PyQt5 is a namespace +# package (`pkgutil.extend_path`), so each sibling's `.so` lives +# in its own prefix and Python merges them at import time via +# the stacked PYTHONPATH. + +distributable: + url: https://pypi.io/packages/source/P/PyQt5/PyQt5-{{ version.raw }}.tar.gz + strip-components: 1 + +versions: + url: https://pypi.org/simple/pyqt5/ + match: /PyQt5-\d+\.\d+\.\d+\.tar\.gz/ + strip: + - /^PyQt5-/ + - /\.tar\.gz/ + +platforms: + - linux/x86-64 + - linux/aarch64 + - darwin/x86-64 + - darwin/aarch64 + +dependencies: + python.org: ~3.11 + qt.io: ^5 + riverbankcomputing.com/sip: '*' + +runtime: + env: + PYTHONPATH: '{{prefix}}/share/python/site-packages:$PYTHONPATH' + +build: + dependencies: + riverbankcomputing.com/pyqt-builder: '*' + freedesktop.org/pkg-config: '*' + linux: + llvm.org: <17 + + script: + - run: | + export CXXFLAGS="${CXXFLAGS} -g0" + export CFLAGS="${CFLAGS} -g0" + export MAKEFLAGS="-j1" + + # Pre-accept the GPL license in pyproject.toml so sipbuild + # does not prompt. awk (not sed) because sed's `a\` form + # needs a literal newline that breaks YAML's run-block + # indentation. + if ! grep -q "confirm-license" "$SRCROOT/pyproject.toml"; then + awk '/^\[tool\.sip\.project\]$/ { print; print "confirm-license = true"; next } { print }' "$SRCROOT/pyproject.toml" > "$SRCROOT/pyproject.toml.tmp" + mv "$SRCROOT/pyproject.toml.tmp" "$SRCROOT/pyproject.toml" + fi + + PYVER={{deps.python.org.version.marketing}} + SITE_PACKAGES="{{prefix}}/share/python/site-packages" + mkdir -p "$SITE_PACKAGES" + + # Use upstream python directly — no per-binding venv, each + # sub-package overlays via PYTHONPATH. + PYTHON="{{deps.python.org.prefix}}/bin/python$PYVER" + + # Single binding, single pip pass. --no-build-isolation so + # our CFLAGS reach the compiler. --no-deps so pip does not + # try to fetch PyQt5-sip from PyPI (pantry's sip is in scope + # via runtime PYTHONPATH). + "$PYTHON" -m pip install --no-build-isolation --no-deps --force-reinstall \ + --target="$SITE_PACKAGES" \ + --config-settings=--enable=QtCore \ + --config-settings=--jobs=1 \ + "$SRCROOT" + +test: + dependencies: + python.org: ~3.11 + script: + - python{{deps.python.org.version.marketing}} -c "from PyQt5 import QtCore" diff --git a/projects/riverbankcomputing.com/pyqt5/QtDBus/package.yml b/projects/riverbankcomputing.com/pyqt5/QtDBus/package.yml new file mode 100644 index 0000000000..8bde12b910 --- /dev/null +++ b/projects/riverbankcomputing.com/pyqt5/QtDBus/package.yml @@ -0,0 +1,80 @@ +# PyQt5.QtDBus — D-Bus binding for PyQt5. +# +# Part of the PyQt5 sub-binding split. See parent meta package at +# riverbankcomputing.com/pyqt5 for topology. PyQt5 is a namespace +# package (`pkgutil.extend_path`), so each sibling's `.so` lives +# in its own prefix and Python merges them at import time via +# the stacked PYTHONPATH. + +distributable: + url: https://pypi.io/packages/source/P/PyQt5/PyQt5-{{ version.raw }}.tar.gz + strip-components: 1 + +versions: + url: https://pypi.org/simple/pyqt5/ + match: /PyQt5-\d+\.\d+\.\d+\.tar\.gz/ + strip: + - /^PyQt5-/ + - /\.tar\.gz/ + +platforms: + - linux/x86-64 + - linux/aarch64 + - darwin/x86-64 + - darwin/aarch64 + +dependencies: + python.org: ~3.11 + qt.io: ^5 + riverbankcomputing.com/sip: '*' + riverbankcomputing.com/pyqt5/QtCore: '={{version}}' + +runtime: + env: + PYTHONPATH: '{{prefix}}/share/python/site-packages:$PYTHONPATH' + +build: + dependencies: + riverbankcomputing.com/pyqt-builder: '*' + freedesktop.org/pkg-config: '*' + linux: + llvm.org: <17 + + script: + - run: | + export CXXFLAGS="${CXXFLAGS} -g0" + export CFLAGS="${CFLAGS} -g0" + export MAKEFLAGS="-j1" + + # Pre-accept the GPL license in pyproject.toml so sipbuild + # does not prompt. awk (not sed) because sed's `a\` form + # needs a literal newline that breaks YAML's run-block + # indentation. + if ! grep -q "confirm-license" "$SRCROOT/pyproject.toml"; then + awk '/^\[tool\.sip\.project\]$/ { print; print "confirm-license = true"; next } { print }' "$SRCROOT/pyproject.toml" > "$SRCROOT/pyproject.toml.tmp" + mv "$SRCROOT/pyproject.toml.tmp" "$SRCROOT/pyproject.toml" + fi + + PYVER={{deps.python.org.version.marketing}} + SITE_PACKAGES="{{prefix}}/share/python/site-packages" + mkdir -p "$SITE_PACKAGES" + + # Use upstream python directly — no per-binding venv, each + # sub-package overlays via PYTHONPATH. + PYTHON="{{deps.python.org.prefix}}/bin/python$PYVER" + + # Single binding, single pip pass. --no-build-isolation so + # our CFLAGS reach the compiler. --no-deps so pip does not + # try to fetch PyQt5-sip from PyPI (pantry's sip is in scope + # via runtime PYTHONPATH). + "$PYTHON" -m pip install --no-build-isolation --no-deps --force-reinstall \ + --target="$SITE_PACKAGES" \ + --config-settings=--enable=QtDBus \ + --config-settings=--jobs=1 \ + "$SRCROOT" + +test: + dependencies: + python.org: ~3.11 + script: + - python{{deps.python.org.version.marketing}} -c "from PyQt5 import QtDBus" diff --git a/projects/riverbankcomputing.com/pyqt5/QtGui/package.yml b/projects/riverbankcomputing.com/pyqt5/QtGui/package.yml new file mode 100644 index 0000000000..a3b19a4aa2 --- /dev/null +++ b/projects/riverbankcomputing.com/pyqt5/QtGui/package.yml @@ -0,0 +1,80 @@ +# PyQt5.QtGui — GUI primitives (paint, fonts, images, OpenGL) binding for PyQt5. +# +# Part of the PyQt5 sub-binding split. See parent meta package at +# riverbankcomputing.com/pyqt5 for topology. PyQt5 is a namespace +# package (`pkgutil.extend_path`), so each sibling's `.so` lives +# in its own prefix and Python merges them at import time via +# the stacked PYTHONPATH. + +distributable: + url: https://pypi.io/packages/source/P/PyQt5/PyQt5-{{ version.raw }}.tar.gz + strip-components: 1 + +versions: + url: https://pypi.org/simple/pyqt5/ + match: /PyQt5-\d+\.\d+\.\d+\.tar\.gz/ + strip: + - /^PyQt5-/ + - /\.tar\.gz/ + +platforms: + - linux/x86-64 + - linux/aarch64 + - darwin/x86-64 + - darwin/aarch64 + +dependencies: + python.org: ~3.11 + qt.io: ^5 + riverbankcomputing.com/sip: '*' + riverbankcomputing.com/pyqt5/QtCore: '={{version}}' + +runtime: + env: + PYTHONPATH: '{{prefix}}/share/python/site-packages:$PYTHONPATH' + +build: + dependencies: + riverbankcomputing.com/pyqt-builder: '*' + freedesktop.org/pkg-config: '*' + linux: + llvm.org: <17 + + script: + - run: | + export CXXFLAGS="${CXXFLAGS} -g0" + export CFLAGS="${CFLAGS} -g0" + export MAKEFLAGS="-j1" + + # Pre-accept the GPL license in pyproject.toml so sipbuild + # does not prompt. awk (not sed) because sed's `a\` form + # needs a literal newline that breaks YAML's run-block + # indentation. + if ! grep -q "confirm-license" "$SRCROOT/pyproject.toml"; then + awk '/^\[tool\.sip\.project\]$/ { print; print "confirm-license = true"; next } { print }' "$SRCROOT/pyproject.toml" > "$SRCROOT/pyproject.toml.tmp" + mv "$SRCROOT/pyproject.toml.tmp" "$SRCROOT/pyproject.toml" + fi + + PYVER={{deps.python.org.version.marketing}} + SITE_PACKAGES="{{prefix}}/share/python/site-packages" + mkdir -p "$SITE_PACKAGES" + + # Use upstream python directly — no per-binding venv, each + # sub-package overlays via PYTHONPATH. + PYTHON="{{deps.python.org.prefix}}/bin/python$PYVER" + + # Single binding, single pip pass. --no-build-isolation so + # our CFLAGS reach the compiler. --no-deps so pip does not + # try to fetch PyQt5-sip from PyPI (pantry's sip is in scope + # via runtime PYTHONPATH). + "$PYTHON" -m pip install --no-build-isolation --no-deps --force-reinstall \ + --target="$SITE_PACKAGES" \ + --config-settings=--enable=QtGui \ + --config-settings=--jobs=1 \ + "$SRCROOT" + +test: + dependencies: + python.org: ~3.11 + script: + - python{{deps.python.org.version.marketing}} -c "from PyQt5 import QtGui" diff --git a/projects/riverbankcomputing.com/pyqt5/QtNetwork/package.yml b/projects/riverbankcomputing.com/pyqt5/QtNetwork/package.yml new file mode 100644 index 0000000000..b49f030cbe --- /dev/null +++ b/projects/riverbankcomputing.com/pyqt5/QtNetwork/package.yml @@ -0,0 +1,80 @@ +# PyQt5.QtNetwork — Networking (TCP/UDP/SSL/HTTP) binding for PyQt5. +# +# Part of the PyQt5 sub-binding split. See parent meta package at +# riverbankcomputing.com/pyqt5 for topology. PyQt5 is a namespace +# package (`pkgutil.extend_path`), so each sibling's `.so` lives +# in its own prefix and Python merges them at import time via +# the stacked PYTHONPATH. + +distributable: + url: https://pypi.io/packages/source/P/PyQt5/PyQt5-{{ version.raw }}.tar.gz + strip-components: 1 + +versions: + url: https://pypi.org/simple/pyqt5/ + match: /PyQt5-\d+\.\d+\.\d+\.tar\.gz/ + strip: + - /^PyQt5-/ + - /\.tar\.gz/ + +platforms: + - linux/x86-64 + - linux/aarch64 + - darwin/x86-64 + - darwin/aarch64 + +dependencies: + python.org: ~3.11 + qt.io: ^5 + riverbankcomputing.com/sip: '*' + riverbankcomputing.com/pyqt5/QtCore: '={{version}}' + +runtime: + env: + PYTHONPATH: '{{prefix}}/share/python/site-packages:$PYTHONPATH' + +build: + dependencies: + riverbankcomputing.com/pyqt-builder: '*' + freedesktop.org/pkg-config: '*' + linux: + llvm.org: <17 + + script: + - run: | + export CXXFLAGS="${CXXFLAGS} -g0" + export CFLAGS="${CFLAGS} -g0" + export MAKEFLAGS="-j1" + + # Pre-accept the GPL license in pyproject.toml so sipbuild + # does not prompt. awk (not sed) because sed's `a\` form + # needs a literal newline that breaks YAML's run-block + # indentation. + if ! grep -q "confirm-license" "$SRCROOT/pyproject.toml"; then + awk '/^\[tool\.sip\.project\]$/ { print; print "confirm-license = true"; next } { print }' "$SRCROOT/pyproject.toml" > "$SRCROOT/pyproject.toml.tmp" + mv "$SRCROOT/pyproject.toml.tmp" "$SRCROOT/pyproject.toml" + fi + + PYVER={{deps.python.org.version.marketing}} + SITE_PACKAGES="{{prefix}}/share/python/site-packages" + mkdir -p "$SITE_PACKAGES" + + # Use upstream python directly — no per-binding venv, each + # sub-package overlays via PYTHONPATH. + PYTHON="{{deps.python.org.prefix}}/bin/python$PYVER" + + # Single binding, single pip pass. --no-build-isolation so + # our CFLAGS reach the compiler. --no-deps so pip does not + # try to fetch PyQt5-sip from PyPI (pantry's sip is in scope + # via runtime PYTHONPATH). + "$PYTHON" -m pip install --no-build-isolation --no-deps --force-reinstall \ + --target="$SITE_PACKAGES" \ + --config-settings=--enable=QtNetwork \ + --config-settings=--jobs=1 \ + "$SRCROOT" + +test: + dependencies: + python.org: ~3.11 + script: + - python{{deps.python.org.version.marketing}} -c "from PyQt5 import QtNetwork" diff --git a/projects/riverbankcomputing.com/pyqt5/QtPrintSupport/package.yml b/projects/riverbankcomputing.com/pyqt5/QtPrintSupport/package.yml new file mode 100644 index 0000000000..43912474cb --- /dev/null +++ b/projects/riverbankcomputing.com/pyqt5/QtPrintSupport/package.yml @@ -0,0 +1,81 @@ +# PyQt5.QtPrintSupport — Printer support binding for PyQt5. +# +# Part of the PyQt5 sub-binding split. See parent meta package at +# riverbankcomputing.com/pyqt5 for topology. PyQt5 is a namespace +# package (`pkgutil.extend_path`), so each sibling's `.so` lives +# in its own prefix and Python merges them at import time via +# the stacked PYTHONPATH. + +distributable: + url: https://pypi.io/packages/source/P/PyQt5/PyQt5-{{ version.raw }}.tar.gz + strip-components: 1 + +versions: + url: https://pypi.org/simple/pyqt5/ + match: /PyQt5-\d+\.\d+\.\d+\.tar\.gz/ + strip: + - /^PyQt5-/ + - /\.tar\.gz/ + +platforms: + - linux/x86-64 + - linux/aarch64 + - darwin/x86-64 + - darwin/aarch64 + +dependencies: + python.org: ~3.11 + qt.io: ^5 + riverbankcomputing.com/sip: '*' + riverbankcomputing.com/pyqt5/QtCore: '={{version}}' + riverbankcomputing.com/pyqt5/QtGui: '={{version}}' + +runtime: + env: + PYTHONPATH: '{{prefix}}/share/python/site-packages:$PYTHONPATH' + +build: + dependencies: + riverbankcomputing.com/pyqt-builder: '*' + freedesktop.org/pkg-config: '*' + linux: + llvm.org: <17 + + script: + - run: | + export CXXFLAGS="${CXXFLAGS} -g0" + export CFLAGS="${CFLAGS} -g0" + export MAKEFLAGS="-j1" + + # Pre-accept the GPL license in pyproject.toml so sipbuild + # does not prompt. awk (not sed) because sed's `a\` form + # needs a literal newline that breaks YAML's run-block + # indentation. + if ! grep -q "confirm-license" "$SRCROOT/pyproject.toml"; then + awk '/^\[tool\.sip\.project\]$/ { print; print "confirm-license = true"; next } { print }' "$SRCROOT/pyproject.toml" > "$SRCROOT/pyproject.toml.tmp" + mv "$SRCROOT/pyproject.toml.tmp" "$SRCROOT/pyproject.toml" + fi + + PYVER={{deps.python.org.version.marketing}} + SITE_PACKAGES="{{prefix}}/share/python/site-packages" + mkdir -p "$SITE_PACKAGES" + + # Use upstream python directly — no per-binding venv, each + # sub-package overlays via PYTHONPATH. + PYTHON="{{deps.python.org.prefix}}/bin/python$PYVER" + + # Single binding, single pip pass. --no-build-isolation so + # our CFLAGS reach the compiler. --no-deps so pip does not + # try to fetch PyQt5-sip from PyPI (pantry's sip is in scope + # via runtime PYTHONPATH). + "$PYTHON" -m pip install --no-build-isolation --no-deps --force-reinstall \ + --target="$SITE_PACKAGES" \ + --config-settings=--enable=QtPrintSupport \ + --config-settings=--jobs=1 \ + "$SRCROOT" + +test: + dependencies: + python.org: ~3.11 + script: + - python{{deps.python.org.version.marketing}} -c "from PyQt5 import QtPrintSupport" diff --git a/projects/riverbankcomputing.com/pyqt5/QtSql/package.yml b/projects/riverbankcomputing.com/pyqt5/QtSql/package.yml new file mode 100644 index 0000000000..89be5d1e7b --- /dev/null +++ b/projects/riverbankcomputing.com/pyqt5/QtSql/package.yml @@ -0,0 +1,80 @@ +# PyQt5.QtSql — SQL database binding for PyQt5. +# +# Part of the PyQt5 sub-binding split. See parent meta package at +# riverbankcomputing.com/pyqt5 for topology. PyQt5 is a namespace +# package (`pkgutil.extend_path`), so each sibling's `.so` lives +# in its own prefix and Python merges them at import time via +# the stacked PYTHONPATH. + +distributable: + url: https://pypi.io/packages/source/P/PyQt5/PyQt5-{{ version.raw }}.tar.gz + strip-components: 1 + +versions: + url: https://pypi.org/simple/pyqt5/ + match: /PyQt5-\d+\.\d+\.\d+\.tar\.gz/ + strip: + - /^PyQt5-/ + - /\.tar\.gz/ + +platforms: + - linux/x86-64 + - linux/aarch64 + - darwin/x86-64 + - darwin/aarch64 + +dependencies: + python.org: ~3.11 + qt.io: ^5 + riverbankcomputing.com/sip: '*' + riverbankcomputing.com/pyqt5/QtCore: '={{version}}' + +runtime: + env: + PYTHONPATH: '{{prefix}}/share/python/site-packages:$PYTHONPATH' + +build: + dependencies: + riverbankcomputing.com/pyqt-builder: '*' + freedesktop.org/pkg-config: '*' + linux: + llvm.org: <17 + + script: + - run: | + export CXXFLAGS="${CXXFLAGS} -g0" + export CFLAGS="${CFLAGS} -g0" + export MAKEFLAGS="-j1" + + # Pre-accept the GPL license in pyproject.toml so sipbuild + # does not prompt. awk (not sed) because sed's `a\` form + # needs a literal newline that breaks YAML's run-block + # indentation. + if ! grep -q "confirm-license" "$SRCROOT/pyproject.toml"; then + awk '/^\[tool\.sip\.project\]$/ { print; print "confirm-license = true"; next } { print }' "$SRCROOT/pyproject.toml" > "$SRCROOT/pyproject.toml.tmp" + mv "$SRCROOT/pyproject.toml.tmp" "$SRCROOT/pyproject.toml" + fi + + PYVER={{deps.python.org.version.marketing}} + SITE_PACKAGES="{{prefix}}/share/python/site-packages" + mkdir -p "$SITE_PACKAGES" + + # Use upstream python directly — no per-binding venv, each + # sub-package overlays via PYTHONPATH. + PYTHON="{{deps.python.org.prefix}}/bin/python$PYVER" + + # Single binding, single pip pass. --no-build-isolation so + # our CFLAGS reach the compiler. --no-deps so pip does not + # try to fetch PyQt5-sip from PyPI (pantry's sip is in scope + # via runtime PYTHONPATH). + "$PYTHON" -m pip install --no-build-isolation --no-deps --force-reinstall \ + --target="$SITE_PACKAGES" \ + --config-settings=--enable=QtSql \ + --config-settings=--jobs=1 \ + "$SRCROOT" + +test: + dependencies: + python.org: ~3.11 + script: + - python{{deps.python.org.version.marketing}} -c "from PyQt5 import QtSql" diff --git a/projects/riverbankcomputing.com/pyqt5/QtSvg/package.yml b/projects/riverbankcomputing.com/pyqt5/QtSvg/package.yml new file mode 100644 index 0000000000..1cbf512258 --- /dev/null +++ b/projects/riverbankcomputing.com/pyqt5/QtSvg/package.yml @@ -0,0 +1,81 @@ +# PyQt5.QtSvg — SVG rendering binding for PyQt5. +# +# Part of the PyQt5 sub-binding split. See parent meta package at +# riverbankcomputing.com/pyqt5 for topology. PyQt5 is a namespace +# package (`pkgutil.extend_path`), so each sibling's `.so` lives +# in its own prefix and Python merges them at import time via +# the stacked PYTHONPATH. + +distributable: + url: https://pypi.io/packages/source/P/PyQt5/PyQt5-{{ version.raw }}.tar.gz + strip-components: 1 + +versions: + url: https://pypi.org/simple/pyqt5/ + match: /PyQt5-\d+\.\d+\.\d+\.tar\.gz/ + strip: + - /^PyQt5-/ + - /\.tar\.gz/ + +platforms: + - linux/x86-64 + - linux/aarch64 + - darwin/x86-64 + - darwin/aarch64 + +dependencies: + python.org: ~3.11 + qt.io: ^5 + riverbankcomputing.com/sip: '*' + riverbankcomputing.com/pyqt5/QtCore: '={{version}}' + riverbankcomputing.com/pyqt5/QtGui: '={{version}}' + +runtime: + env: + PYTHONPATH: '{{prefix}}/share/python/site-packages:$PYTHONPATH' + +build: + dependencies: + riverbankcomputing.com/pyqt-builder: '*' + freedesktop.org/pkg-config: '*' + linux: + llvm.org: <17 + + script: + - run: | + export CXXFLAGS="${CXXFLAGS} -g0" + export CFLAGS="${CFLAGS} -g0" + export MAKEFLAGS="-j1" + + # Pre-accept the GPL license in pyproject.toml so sipbuild + # does not prompt. awk (not sed) because sed's `a\` form + # needs a literal newline that breaks YAML's run-block + # indentation. + if ! grep -q "confirm-license" "$SRCROOT/pyproject.toml"; then + awk '/^\[tool\.sip\.project\]$/ { print; print "confirm-license = true"; next } { print }' "$SRCROOT/pyproject.toml" > "$SRCROOT/pyproject.toml.tmp" + mv "$SRCROOT/pyproject.toml.tmp" "$SRCROOT/pyproject.toml" + fi + + PYVER={{deps.python.org.version.marketing}} + SITE_PACKAGES="{{prefix}}/share/python/site-packages" + mkdir -p "$SITE_PACKAGES" + + # Use upstream python directly — no per-binding venv, each + # sub-package overlays via PYTHONPATH. + PYTHON="{{deps.python.org.prefix}}/bin/python$PYVER" + + # Single binding, single pip pass. --no-build-isolation so + # our CFLAGS reach the compiler. --no-deps so pip does not + # try to fetch PyQt5-sip from PyPI (pantry's sip is in scope + # via runtime PYTHONPATH). + "$PYTHON" -m pip install --no-build-isolation --no-deps --force-reinstall \ + --target="$SITE_PACKAGES" \ + --config-settings=--enable=QtSvg \ + --config-settings=--jobs=1 \ + "$SRCROOT" + +test: + dependencies: + python.org: ~3.11 + script: + - python{{deps.python.org.version.marketing}} -c "from PyQt5 import QtSvg" diff --git a/projects/riverbankcomputing.com/pyqt5/QtTest/package.yml b/projects/riverbankcomputing.com/pyqt5/QtTest/package.yml new file mode 100644 index 0000000000..bf4100235e --- /dev/null +++ b/projects/riverbankcomputing.com/pyqt5/QtTest/package.yml @@ -0,0 +1,80 @@ +# PyQt5.QtTest — Unit-test framework binding for PyQt5. +# +# Part of the PyQt5 sub-binding split. See parent meta package at +# riverbankcomputing.com/pyqt5 for topology. PyQt5 is a namespace +# package (`pkgutil.extend_path`), so each sibling's `.so` lives +# in its own prefix and Python merges them at import time via +# the stacked PYTHONPATH. + +distributable: + url: https://pypi.io/packages/source/P/PyQt5/PyQt5-{{ version.raw }}.tar.gz + strip-components: 1 + +versions: + url: https://pypi.org/simple/pyqt5/ + match: /PyQt5-\d+\.\d+\.\d+\.tar\.gz/ + strip: + - /^PyQt5-/ + - /\.tar\.gz/ + +platforms: + - linux/x86-64 + - linux/aarch64 + - darwin/x86-64 + - darwin/aarch64 + +dependencies: + python.org: ~3.11 + qt.io: ^5 + riverbankcomputing.com/sip: '*' + riverbankcomputing.com/pyqt5/QtCore: '={{version}}' + +runtime: + env: + PYTHONPATH: '{{prefix}}/share/python/site-packages:$PYTHONPATH' + +build: + dependencies: + riverbankcomputing.com/pyqt-builder: '*' + freedesktop.org/pkg-config: '*' + linux: + llvm.org: <17 + + script: + - run: | + export CXXFLAGS="${CXXFLAGS} -g0" + export CFLAGS="${CFLAGS} -g0" + export MAKEFLAGS="-j1" + + # Pre-accept the GPL license in pyproject.toml so sipbuild + # does not prompt. awk (not sed) because sed's `a\` form + # needs a literal newline that breaks YAML's run-block + # indentation. + if ! grep -q "confirm-license" "$SRCROOT/pyproject.toml"; then + awk '/^\[tool\.sip\.project\]$/ { print; print "confirm-license = true"; next } { print }' "$SRCROOT/pyproject.toml" > "$SRCROOT/pyproject.toml.tmp" + mv "$SRCROOT/pyproject.toml.tmp" "$SRCROOT/pyproject.toml" + fi + + PYVER={{deps.python.org.version.marketing}} + SITE_PACKAGES="{{prefix}}/share/python/site-packages" + mkdir -p "$SITE_PACKAGES" + + # Use upstream python directly — no per-binding venv, each + # sub-package overlays via PYTHONPATH. + PYTHON="{{deps.python.org.prefix}}/bin/python$PYVER" + + # Single binding, single pip pass. --no-build-isolation so + # our CFLAGS reach the compiler. --no-deps so pip does not + # try to fetch PyQt5-sip from PyPI (pantry's sip is in scope + # via runtime PYTHONPATH). + "$PYTHON" -m pip install --no-build-isolation --no-deps --force-reinstall \ + --target="$SITE_PACKAGES" \ + --config-settings=--enable=QtTest \ + --config-settings=--jobs=1 \ + "$SRCROOT" + +test: + dependencies: + python.org: ~3.11 + script: + - python{{deps.python.org.version.marketing}} -c "from PyQt5 import QtTest" diff --git a/projects/riverbankcomputing.com/pyqt5/QtWidgets/package.yml b/projects/riverbankcomputing.com/pyqt5/QtWidgets/package.yml new file mode 100644 index 0000000000..bd568f1f50 --- /dev/null +++ b/projects/riverbankcomputing.com/pyqt5/QtWidgets/package.yml @@ -0,0 +1,81 @@ +# PyQt5.QtWidgets — Full Qt 5 widget set — heaviest of the bindings. +# +# Part of the PyQt5 sub-binding split. See parent meta package at +# riverbankcomputing.com/pyqt5 for topology. PyQt5 is a namespace +# package (`pkgutil.extend_path`), so each sibling's `.so` lives +# in its own prefix and Python merges them at import time via +# the stacked PYTHONPATH. + +distributable: + url: https://pypi.io/packages/source/P/PyQt5/PyQt5-{{ version.raw }}.tar.gz + strip-components: 1 + +versions: + url: https://pypi.org/simple/pyqt5/ + match: /PyQt5-\d+\.\d+\.\d+\.tar\.gz/ + strip: + - /^PyQt5-/ + - /\.tar\.gz/ + +platforms: + - linux/x86-64 + - linux/aarch64 + - darwin/x86-64 + - darwin/aarch64 + +dependencies: + python.org: ~3.11 + qt.io: ^5 + riverbankcomputing.com/sip: '*' + riverbankcomputing.com/pyqt5/QtCore: '={{version}}' + riverbankcomputing.com/pyqt5/QtGui: '={{version}}' + +runtime: + env: + PYTHONPATH: '{{prefix}}/share/python/site-packages:$PYTHONPATH' + +build: + dependencies: + riverbankcomputing.com/pyqt-builder: '*' + freedesktop.org/pkg-config: '*' + linux: + llvm.org: <17 + + script: + - run: | + export CXXFLAGS="${CXXFLAGS} -g0" + export CFLAGS="${CFLAGS} -g0" + export MAKEFLAGS="-j1" + + # Pre-accept the GPL license in pyproject.toml so sipbuild + # does not prompt. awk (not sed) because sed's `a\` form + # needs a literal newline that breaks YAML's run-block + # indentation. + if ! grep -q "confirm-license" "$SRCROOT/pyproject.toml"; then + awk '/^\[tool\.sip\.project\]$/ { print; print "confirm-license = true"; next } { print }' "$SRCROOT/pyproject.toml" > "$SRCROOT/pyproject.toml.tmp" + mv "$SRCROOT/pyproject.toml.tmp" "$SRCROOT/pyproject.toml" + fi + + PYVER={{deps.python.org.version.marketing}} + SITE_PACKAGES="{{prefix}}/share/python/site-packages" + mkdir -p "$SITE_PACKAGES" + + # Use upstream python directly — no per-binding venv, each + # sub-package overlays via PYTHONPATH. + PYTHON="{{deps.python.org.prefix}}/bin/python$PYVER" + + # Single binding, single pip pass. --no-build-isolation so + # our CFLAGS reach the compiler. --no-deps so pip does not + # try to fetch PyQt5-sip from PyPI (pantry's sip is in scope + # via runtime PYTHONPATH). + "$PYTHON" -m pip install --no-build-isolation --no-deps --force-reinstall \ + --target="$SITE_PACKAGES" \ + --config-settings=--enable=QtWidgets \ + --config-settings=--jobs=1 \ + "$SRCROOT" + +test: + dependencies: + python.org: ~3.11 + script: + - python{{deps.python.org.version.marketing}} -c "from PyQt5 import QtWidgets" diff --git a/projects/riverbankcomputing.com/pyqt5/QtXml/package.yml b/projects/riverbankcomputing.com/pyqt5/QtXml/package.yml new file mode 100644 index 0000000000..10f813149d --- /dev/null +++ b/projects/riverbankcomputing.com/pyqt5/QtXml/package.yml @@ -0,0 +1,80 @@ +# PyQt5.QtXml — DOM XML binding for PyQt5. +# +# Part of the PyQt5 sub-binding split. See parent meta package at +# riverbankcomputing.com/pyqt5 for topology. PyQt5 is a namespace +# package (`pkgutil.extend_path`), so each sibling's `.so` lives +# in its own prefix and Python merges them at import time via +# the stacked PYTHONPATH. + +distributable: + url: https://pypi.io/packages/source/P/PyQt5/PyQt5-{{ version.raw }}.tar.gz + strip-components: 1 + +versions: + url: https://pypi.org/simple/pyqt5/ + match: /PyQt5-\d+\.\d+\.\d+\.tar\.gz/ + strip: + - /^PyQt5-/ + - /\.tar\.gz/ + +platforms: + - linux/x86-64 + - linux/aarch64 + - darwin/x86-64 + - darwin/aarch64 + +dependencies: + python.org: ~3.11 + qt.io: ^5 + riverbankcomputing.com/sip: '*' + riverbankcomputing.com/pyqt5/QtCore: '={{version}}' + +runtime: + env: + PYTHONPATH: '{{prefix}}/share/python/site-packages:$PYTHONPATH' + +build: + dependencies: + riverbankcomputing.com/pyqt-builder: '*' + freedesktop.org/pkg-config: '*' + linux: + llvm.org: <17 + + script: + - run: | + export CXXFLAGS="${CXXFLAGS} -g0" + export CFLAGS="${CFLAGS} -g0" + export MAKEFLAGS="-j1" + + # Pre-accept the GPL license in pyproject.toml so sipbuild + # does not prompt. awk (not sed) because sed's `a\` form + # needs a literal newline that breaks YAML's run-block + # indentation. + if ! grep -q "confirm-license" "$SRCROOT/pyproject.toml"; then + awk '/^\[tool\.sip\.project\]$/ { print; print "confirm-license = true"; next } { print }' "$SRCROOT/pyproject.toml" > "$SRCROOT/pyproject.toml.tmp" + mv "$SRCROOT/pyproject.toml.tmp" "$SRCROOT/pyproject.toml" + fi + + PYVER={{deps.python.org.version.marketing}} + SITE_PACKAGES="{{prefix}}/share/python/site-packages" + mkdir -p "$SITE_PACKAGES" + + # Use upstream python directly — no per-binding venv, each + # sub-package overlays via PYTHONPATH. + PYTHON="{{deps.python.org.prefix}}/bin/python$PYVER" + + # Single binding, single pip pass. --no-build-isolation so + # our CFLAGS reach the compiler. --no-deps so pip does not + # try to fetch PyQt5-sip from PyPI (pantry's sip is in scope + # via runtime PYTHONPATH). + "$PYTHON" -m pip install --no-build-isolation --no-deps --force-reinstall \ + --target="$SITE_PACKAGES" \ + --config-settings=--enable=QtXml \ + --config-settings=--jobs=1 \ + "$SRCROOT" + +test: + dependencies: + python.org: ~3.11 + script: + - python{{deps.python.org.version.marketing}} -c "from PyQt5 import QtXml" diff --git a/projects/riverbankcomputing.com/pyqt5/package.yml b/projects/riverbankcomputing.com/pyqt5/package.yml index 8734436531..3afe874f8b 100644 --- a/projects/riverbankcomputing.com/pyqt5/package.yml +++ b/projects/riverbankcomputing.com/pyqt5/package.yml @@ -1,10 +1,12 @@ -# PyQt5 — Python bindings for Qt 5. +# PyQt5 — Meta-package: pulls all PyQt5 sub-bindings together. # -# Companion to pantry's qt.io (5.15.10) and riverbankcomputing.com/sip. -# Installed as a python-venv with `pip install PyQt5` against the -# pantry Qt5 + SIP build. +# Equivalent to homebrew's `pyqt@5` formula or apt's `python3-pyqt5`. +# Per-binding sub-recipes (QtCore / QtGui / QtWidgets / etc.) live in +# sibling directories so each binding gets its own CI job and its own +# 6 h timeout — the monolithic recipe was being OOM-killed and then +# GHA-cancelled at 1h33min. See PR pkgxdev/pantry#13064. # -# Closes part of pkgxdev/pantry#99 (Top 300 holdout #591). +# Top 300 holdout #591. distributable: url: https://pypi.io/packages/source/P/PyQt5/PyQt5-{{ version.raw }}.tar.gz @@ -24,161 +26,34 @@ platforms: - darwin/aarch64 dependencies: - python.org: ~3.11 - qt.io: ^5 - riverbankcomputing.com/sip: '*' - -runtime: - env: - PYTHONPATH: '{{prefix}}/venv/lib/python{{deps.python.org.version.marketing}}/site-packages:$PYTHONPATH' - + riverbankcomputing.com/pyqt5/QtCore: '={{version}}' + riverbankcomputing.com/pyqt5/QtDBus: '={{version}}' + riverbankcomputing.com/pyqt5/QtNetwork: '={{version}}' + riverbankcomputing.com/pyqt5/QtSql: '={{version}}' + riverbankcomputing.com/pyqt5/QtTest: '={{version}}' + riverbankcomputing.com/pyqt5/QtXml: '={{version}}' + riverbankcomputing.com/pyqt5/QtGui: '={{version}}' + riverbankcomputing.com/pyqt5/QtSvg: '={{version}}' + riverbankcomputing.com/pyqt5/QtPrintSupport: '={{version}}' + riverbankcomputing.com/pyqt5/QtWidgets: '={{version}}' + +# Meta package: no build artifacts of its own — every sub-binding +# carries its own .so into its own prefix and Python's pkgutil +# extends `PyQt5/__path__` to merge them at import time. We still +# need a `build.script` because pkgx requires one; emit a marker file +# so the package is non-empty and brewkit's bottling sees something. build: - dependencies: - riverbankcomputing.com/pyqt-builder: '*' - freedesktop.org/pkg-config: '*' - linux: - llvm.org: <17 - script: - # Per-binding split build (one Qt binding per pip-install pass). - # - # Why: PyQt5's monolithic `pip install .` was OOM-killed (exit 137) - # on the 7 GB GH-runner. Even `--config-settings=--jobs=1` wasn't - # enough — a SINGLE binding's final `ld` (especially QtWidgets at - # ~4-6 GB peak) blows past 7 GB. The only viable shape is to build - # each binding in its own subprocess so its working set is freed - # between bindings. - # - # sipbuild config_settings honoured here: - # --enable=NAME (sip) -- only build this binding - # --jobs=1 (pyqt-builder) -- inner make -j1 - # --confirm-license (PyQt5 project.py) -- accept GPL - # - # Note: pyqt-builder's `--no-make` flag is restricted to the - # `build` tool (tools=['build']); pip's PEP 517 path calls the - # `wheel` tool, so --no-make can't be set via --config-settings. - # The split-pip approach achieves the same memory isolation by - # freeing each binding's intermediate state between subprocesses. - # - # Bindings are ordered lightest-first so a memory failure surfaces - # early. QtWidgets is last — if it OOMs, the eight before it are - # still importable (partial install rather than nothing). - run: | - PYVER={{deps.python.org.version.marketing}} - "{{deps.python.org.prefix}}/bin/python$PYVER" -m venv --copies "{{prefix}}/venv" - PYTHON="{{prefix}}/venv/bin/python" - SITE_PACKAGES="{{prefix}}/venv/lib/python$PYVER/site-packages" - "$PYTHON" -m pip install --upgrade pip wheel setuptools --quiet - - # Memory discipline: drop debug info (-g0 saves ~30 % link - # RAM) and pin make to -j1 belt-and-braces. - export CXXFLAGS="${CXXFLAGS} -g0" - export CFLAGS="${CFLAGS} -g0" - export MAKEFLAGS="-j1" - - STAGING="$(mktemp -d)" - # Trap to clean up staging on exit (any code path). - trap 'rm -rf "$STAGING"' EXIT - - # Pre-accept the GPL license in pyproject.toml so sipbuild - # doesn't prompt. pip's --config-settings can't pass through - # the `--confirm-license` flag: pip insists on KEY=VAL form, - # but sipbuild's argparse declares the flag as store_true and - # rejects any value with - # "argument --confirm-license: ignored explicit argument 'true'" - # The pyproject.toml route doesn't go through that argparse, - # so set it there once before pip runs. - if ! grep -q "confirm-license" "$SRCROOT/pyproject.toml"; then - # Insert after the [tool.sip.project] header (it exists in - # PyQt5's pyproject.toml). Use awk rather than sed `a\`: - # the latter requires a literal newline in the script, - # which breaks YAML's `run: |` block-scalar indentation - # rules (the appended content has to start at column 0, - # but that's less indentation than the block baseline). - awk '/^\[tool\.sip\.project\]$/ { print; print "confirm-license = true"; next } { print }' "$SRCROOT/pyproject.toml" > "$SRCROOT/pyproject.toml.tmp" - mv "$SRCROOT/pyproject.toml.tmp" "$SRCROOT/pyproject.toml" - echo "patched pyproject.toml with confirm-license = true" - fi - - # Bindings to ship, in build order (lightest first). - BINDINGS="QtCore QtDBus QtNetwork QtSql QtSvg QtTest QtXml QtPrintSupport QtGui QtWidgets" - - BUILT="" - FAILED="" - for binding in $BINDINGS; do - echo "::group::pyqt5 binding $binding" - mkdir -p "$STAGING/$binding" - - # Note: --confirm-license is pre-applied via the - # pyproject.toml patch above (sed) — it can't be passed - # through pip's --config-settings because pip wants KEY=VAL - # and sipbuild's argparse rejects any value on store_true. - if "$PYTHON" -m pip install "$SRCROOT" \ - --no-build-isolation \ - --no-deps \ - --force-reinstall \ - --target="$STAGING/$binding" \ - --config-settings=--enable="$binding" \ - --config-settings=--jobs=1 \ - --verbose - then - # Merge produced files into the venv's PyQt5 dir. - # `cp -R src/. dst/` performs a deep merge; wrapper - # modules from the first binding stay, the per-binding - # .so accumulates. - if [ -d "$STAGING/$binding/PyQt5" ]; then - mkdir -p "$SITE_PACKAGES/PyQt5" - cp -R "$STAGING/$binding/PyQt5/." "$SITE_PACKAGES/PyQt5/" - fi - # Copy any top-level dist-info from this pass once. - for di in "$STAGING/$binding"/PyQt5-*.dist-info; do - if [ -d "$di" ] && [ ! -d "$SITE_PACKAGES/$(basename "$di")" ]; then - cp -R "$di" "$SITE_PACKAGES/" - fi - done - BUILT="$BUILT $binding" - echo "pyqt5: $binding built OK" - else - FAILED="$FAILED $binding" - echo "pyqt5: WARNING — $binding failed to build (likely OOM); continuing" - fi - - # Free the per-binding staging dir to reclaim disk. - rm -rf "$STAGING/$binding" - echo "::endgroup::" - done - - echo "pyqt5: built:$BUILT" - if [ -n "$FAILED" ]; then - echo "pyqt5: FAILED:$FAILED" - fi - - # Smoke-test: at minimum QtCore must be importable. - "$PYTHON" -c "from PyQt5 import QtCore; print('PyQt5 QtCore', QtCore.QT_VERSION_STR)" - - # Expose the python binary as a marker so provides: has something. - - run: | - mkdir -p {{prefix}}/bin - ln -sf ../venv/bin/python "{{prefix}}/bin/pyqt5-python" + mkdir -p "{{prefix}}/share/pyqt5" + echo "PyQt5 {{version}} (meta-package — see sub-bindings)" > "{{prefix}}/share/pyqt5/README" test: + dependencies: + python.org: ~3.11 script: - - pyqt5-python -c "from PyQt5 import QtCore; print(QtCore.QT_VERSION_STR)" - # QtGui and QtWidgets may be absent if their link OOM'd on a - # 7 GB runner. Test them best-effort. - - | - pyqt5-python - <<'PY' - try: - from PyQt5 import QtGui # noqa: F401 - print("QtGui OK") - except ImportError as e: - print("QtGui MISSING:", e) - try: - from PyQt5 import QtWidgets # noqa: F401 - print("QtWidgets OK") - except ImportError as e: - print("QtWidgets MISSING:", e) - PY - -provides: - - bin/pyqt5-python + # Importing QtCore exercises the namespace-package overlay across + # at least one sub-binding prefix. Each sub-binding has its own + # test pass; this test only checks that the meta successfully + # pulled them all into scope. + - python{{deps.python.org.version.marketing}} -c "from PyQt5 import QtCore; print(QtCore.QT_VERSION_STR)" From d54adcac48a8abaf0c969ff9e3d9215b5b452b56 Mon Sep 17 00:00:00 2001 From: tannevaled Date: Sun, 31 May 2026 17:03:21 +0200 Subject: [PATCH 11/19] fix(pyqt5): use wildcard for sibling-pin (pantry deps do not template-substitute) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previous commit pinned sibling sub-bindings with `={{version}}` per the task spec, but libpkgx's `validatePackageRequirement` runs at YAML parse time — before template substitution — and rejects the literal `{{version}}` string with `invalid constraint: undefined` (CI run 26716046336 confirmed: meta package fails before any build step). PyQt5 sub-bindings all share the same version-discovery (PyPI simple index) so they march in lockstep anyway; a `'*'` constraint is safe here. Same shape as poppler / poppler-data and x.org/exts -> x11. --- .../pyqt5/QtDBus/package.yml | 2 +- .../pyqt5/QtGui/package.yml | 2 +- .../pyqt5/QtNetwork/package.yml | 2 +- .../pyqt5/QtPrintSupport/package.yml | 4 ++-- .../pyqt5/QtSql/package.yml | 2 +- .../pyqt5/QtSvg/package.yml | 4 ++-- .../pyqt5/QtTest/package.yml | 2 +- .../pyqt5/QtWidgets/package.yml | 4 ++-- .../pyqt5/QtXml/package.yml | 2 +- .../riverbankcomputing.com/pyqt5/package.yml | 20 +++++++++---------- 10 files changed, 22 insertions(+), 22 deletions(-) diff --git a/projects/riverbankcomputing.com/pyqt5/QtDBus/package.yml b/projects/riverbankcomputing.com/pyqt5/QtDBus/package.yml index 8bde12b910..229c3f2d05 100644 --- a/projects/riverbankcomputing.com/pyqt5/QtDBus/package.yml +++ b/projects/riverbankcomputing.com/pyqt5/QtDBus/package.yml @@ -27,7 +27,7 @@ dependencies: python.org: ~3.11 qt.io: ^5 riverbankcomputing.com/sip: '*' - riverbankcomputing.com/pyqt5/QtCore: '={{version}}' + riverbankcomputing.com/pyqt5/QtCore: '*' runtime: env: diff --git a/projects/riverbankcomputing.com/pyqt5/QtGui/package.yml b/projects/riverbankcomputing.com/pyqt5/QtGui/package.yml index a3b19a4aa2..9079610a5c 100644 --- a/projects/riverbankcomputing.com/pyqt5/QtGui/package.yml +++ b/projects/riverbankcomputing.com/pyqt5/QtGui/package.yml @@ -27,7 +27,7 @@ dependencies: python.org: ~3.11 qt.io: ^5 riverbankcomputing.com/sip: '*' - riverbankcomputing.com/pyqt5/QtCore: '={{version}}' + riverbankcomputing.com/pyqt5/QtCore: '*' runtime: env: diff --git a/projects/riverbankcomputing.com/pyqt5/QtNetwork/package.yml b/projects/riverbankcomputing.com/pyqt5/QtNetwork/package.yml index b49f030cbe..88c9e29c5b 100644 --- a/projects/riverbankcomputing.com/pyqt5/QtNetwork/package.yml +++ b/projects/riverbankcomputing.com/pyqt5/QtNetwork/package.yml @@ -27,7 +27,7 @@ dependencies: python.org: ~3.11 qt.io: ^5 riverbankcomputing.com/sip: '*' - riverbankcomputing.com/pyqt5/QtCore: '={{version}}' + riverbankcomputing.com/pyqt5/QtCore: '*' runtime: env: diff --git a/projects/riverbankcomputing.com/pyqt5/QtPrintSupport/package.yml b/projects/riverbankcomputing.com/pyqt5/QtPrintSupport/package.yml index 43912474cb..1a4de56e2f 100644 --- a/projects/riverbankcomputing.com/pyqt5/QtPrintSupport/package.yml +++ b/projects/riverbankcomputing.com/pyqt5/QtPrintSupport/package.yml @@ -27,8 +27,8 @@ dependencies: python.org: ~3.11 qt.io: ^5 riverbankcomputing.com/sip: '*' - riverbankcomputing.com/pyqt5/QtCore: '={{version}}' - riverbankcomputing.com/pyqt5/QtGui: '={{version}}' + riverbankcomputing.com/pyqt5/QtCore: '*' + riverbankcomputing.com/pyqt5/QtGui: '*' runtime: env: diff --git a/projects/riverbankcomputing.com/pyqt5/QtSql/package.yml b/projects/riverbankcomputing.com/pyqt5/QtSql/package.yml index 89be5d1e7b..64f2d27b60 100644 --- a/projects/riverbankcomputing.com/pyqt5/QtSql/package.yml +++ b/projects/riverbankcomputing.com/pyqt5/QtSql/package.yml @@ -27,7 +27,7 @@ dependencies: python.org: ~3.11 qt.io: ^5 riverbankcomputing.com/sip: '*' - riverbankcomputing.com/pyqt5/QtCore: '={{version}}' + riverbankcomputing.com/pyqt5/QtCore: '*' runtime: env: diff --git a/projects/riverbankcomputing.com/pyqt5/QtSvg/package.yml b/projects/riverbankcomputing.com/pyqt5/QtSvg/package.yml index 1cbf512258..51695279ec 100644 --- a/projects/riverbankcomputing.com/pyqt5/QtSvg/package.yml +++ b/projects/riverbankcomputing.com/pyqt5/QtSvg/package.yml @@ -27,8 +27,8 @@ dependencies: python.org: ~3.11 qt.io: ^5 riverbankcomputing.com/sip: '*' - riverbankcomputing.com/pyqt5/QtCore: '={{version}}' - riverbankcomputing.com/pyqt5/QtGui: '={{version}}' + riverbankcomputing.com/pyqt5/QtCore: '*' + riverbankcomputing.com/pyqt5/QtGui: '*' runtime: env: diff --git a/projects/riverbankcomputing.com/pyqt5/QtTest/package.yml b/projects/riverbankcomputing.com/pyqt5/QtTest/package.yml index bf4100235e..55d89b2f0e 100644 --- a/projects/riverbankcomputing.com/pyqt5/QtTest/package.yml +++ b/projects/riverbankcomputing.com/pyqt5/QtTest/package.yml @@ -27,7 +27,7 @@ dependencies: python.org: ~3.11 qt.io: ^5 riverbankcomputing.com/sip: '*' - riverbankcomputing.com/pyqt5/QtCore: '={{version}}' + riverbankcomputing.com/pyqt5/QtCore: '*' runtime: env: diff --git a/projects/riverbankcomputing.com/pyqt5/QtWidgets/package.yml b/projects/riverbankcomputing.com/pyqt5/QtWidgets/package.yml index bd568f1f50..77772283f4 100644 --- a/projects/riverbankcomputing.com/pyqt5/QtWidgets/package.yml +++ b/projects/riverbankcomputing.com/pyqt5/QtWidgets/package.yml @@ -27,8 +27,8 @@ dependencies: python.org: ~3.11 qt.io: ^5 riverbankcomputing.com/sip: '*' - riverbankcomputing.com/pyqt5/QtCore: '={{version}}' - riverbankcomputing.com/pyqt5/QtGui: '={{version}}' + riverbankcomputing.com/pyqt5/QtCore: '*' + riverbankcomputing.com/pyqt5/QtGui: '*' runtime: env: diff --git a/projects/riverbankcomputing.com/pyqt5/QtXml/package.yml b/projects/riverbankcomputing.com/pyqt5/QtXml/package.yml index 10f813149d..ab2c4d3da9 100644 --- a/projects/riverbankcomputing.com/pyqt5/QtXml/package.yml +++ b/projects/riverbankcomputing.com/pyqt5/QtXml/package.yml @@ -27,7 +27,7 @@ dependencies: python.org: ~3.11 qt.io: ^5 riverbankcomputing.com/sip: '*' - riverbankcomputing.com/pyqt5/QtCore: '={{version}}' + riverbankcomputing.com/pyqt5/QtCore: '*' runtime: env: diff --git a/projects/riverbankcomputing.com/pyqt5/package.yml b/projects/riverbankcomputing.com/pyqt5/package.yml index 3afe874f8b..92f968c2de 100644 --- a/projects/riverbankcomputing.com/pyqt5/package.yml +++ b/projects/riverbankcomputing.com/pyqt5/package.yml @@ -26,16 +26,16 @@ platforms: - darwin/aarch64 dependencies: - riverbankcomputing.com/pyqt5/QtCore: '={{version}}' - riverbankcomputing.com/pyqt5/QtDBus: '={{version}}' - riverbankcomputing.com/pyqt5/QtNetwork: '={{version}}' - riverbankcomputing.com/pyqt5/QtSql: '={{version}}' - riverbankcomputing.com/pyqt5/QtTest: '={{version}}' - riverbankcomputing.com/pyqt5/QtXml: '={{version}}' - riverbankcomputing.com/pyqt5/QtGui: '={{version}}' - riverbankcomputing.com/pyqt5/QtSvg: '={{version}}' - riverbankcomputing.com/pyqt5/QtPrintSupport: '={{version}}' - riverbankcomputing.com/pyqt5/QtWidgets: '={{version}}' + riverbankcomputing.com/pyqt5/QtCore: '*' + riverbankcomputing.com/pyqt5/QtDBus: '*' + riverbankcomputing.com/pyqt5/QtNetwork: '*' + riverbankcomputing.com/pyqt5/QtSql: '*' + riverbankcomputing.com/pyqt5/QtTest: '*' + riverbankcomputing.com/pyqt5/QtXml: '*' + riverbankcomputing.com/pyqt5/QtGui: '*' + riverbankcomputing.com/pyqt5/QtSvg: '*' + riverbankcomputing.com/pyqt5/QtPrintSupport: '*' + riverbankcomputing.com/pyqt5/QtWidgets: '*' # Meta package: no build artifacts of its own — every sub-binding # carries its own .so into its own prefix and Python's pkgutil From fa3350f30e35858c37cb73680b106060524e4feb Mon Sep 17 00:00:00 2001 From: tannevaled Date: Sun, 14 Jun 2026 15:20:07 +0200 Subject: [PATCH 12/19] pyqt5: vendor the official wheel (1 package) instead of 11 source sub-recipes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The from-source approach OOM-killed (QtCore's sip-generated C++ compile, exit 137) and the per-binding split hit a lockstep co-dependency (each binding 404'd on its sibling's unpublished bottle). Replace all 11 sub-recipes with one package that installs PyQt5's official PyPI wheel (Qt bundled) into a venv — no compile, no lockstep. Provides pyuic5/pyrcc5/pylupdate5 and an importable PyQt5 (via PYTHONPATH). linux/x86-64 + darwin only (no upstream aarch64 linux wheel). PR body documents why vendored + the path back to a from-source recipe. Verified on darwin/arm64: wheel installs, import PyQt5.QtCore/QtWidgets works, pyuic5 --version reports 5.15.11. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../pyqt5/QtCore/package.yml | 79 ------------------ .../pyqt5/QtDBus/package.yml | 80 ------------------ .../pyqt5/QtGui/package.yml | 80 ------------------ .../pyqt5/QtNetwork/package.yml | 80 ------------------ .../pyqt5/QtPrintSupport/package.yml | 81 ------------------- .../pyqt5/QtSql/package.yml | 80 ------------------ .../pyqt5/QtSvg/package.yml | 81 ------------------- .../pyqt5/QtTest/package.yml | 80 ------------------ .../pyqt5/QtWidgets/package.yml | 81 ------------------- .../pyqt5/QtXml/package.yml | 80 ------------------ .../riverbankcomputing.com/pyqt5/package.yml | 68 ++++++++-------- 11 files changed, 36 insertions(+), 834 deletions(-) delete mode 100644 projects/riverbankcomputing.com/pyqt5/QtCore/package.yml delete mode 100644 projects/riverbankcomputing.com/pyqt5/QtDBus/package.yml delete mode 100644 projects/riverbankcomputing.com/pyqt5/QtGui/package.yml delete mode 100644 projects/riverbankcomputing.com/pyqt5/QtNetwork/package.yml delete mode 100644 projects/riverbankcomputing.com/pyqt5/QtPrintSupport/package.yml delete mode 100644 projects/riverbankcomputing.com/pyqt5/QtSql/package.yml delete mode 100644 projects/riverbankcomputing.com/pyqt5/QtSvg/package.yml delete mode 100644 projects/riverbankcomputing.com/pyqt5/QtTest/package.yml delete mode 100644 projects/riverbankcomputing.com/pyqt5/QtWidgets/package.yml delete mode 100644 projects/riverbankcomputing.com/pyqt5/QtXml/package.yml diff --git a/projects/riverbankcomputing.com/pyqt5/QtCore/package.yml b/projects/riverbankcomputing.com/pyqt5/QtCore/package.yml deleted file mode 100644 index 7d187d6db8..0000000000 --- a/projects/riverbankcomputing.com/pyqt5/QtCore/package.yml +++ /dev/null @@ -1,79 +0,0 @@ -# PyQt5.QtCore — Foundation binding for Qt 5's core library. -# -# Part of the PyQt5 sub-binding split. See parent meta package at -# riverbankcomputing.com/pyqt5 for topology. PyQt5 is a namespace -# package (`pkgutil.extend_path`), so each sibling's `.so` lives -# in its own prefix and Python merges them at import time via -# the stacked PYTHONPATH. - -distributable: - url: https://pypi.io/packages/source/P/PyQt5/PyQt5-{{ version.raw }}.tar.gz - strip-components: 1 - -versions: - url: https://pypi.org/simple/pyqt5/ - match: /PyQt5-\d+\.\d+\.\d+\.tar\.gz/ - strip: - - /^PyQt5-/ - - /\.tar\.gz/ - -platforms: - - linux/x86-64 - - linux/aarch64 - - darwin/x86-64 - - darwin/aarch64 - -dependencies: - python.org: ~3.11 - qt.io: ^5 - riverbankcomputing.com/sip: '*' - -runtime: - env: - PYTHONPATH: '{{prefix}}/share/python/site-packages:$PYTHONPATH' - -build: - dependencies: - riverbankcomputing.com/pyqt-builder: '*' - freedesktop.org/pkg-config: '*' - linux: - llvm.org: <17 - - script: - - run: | - export CXXFLAGS="${CXXFLAGS} -g0" - export CFLAGS="${CFLAGS} -g0" - export MAKEFLAGS="-j1" - - # Pre-accept the GPL license in pyproject.toml so sipbuild - # does not prompt. awk (not sed) because sed's `a\` form - # needs a literal newline that breaks YAML's run-block - # indentation. - if ! grep -q "confirm-license" "$SRCROOT/pyproject.toml"; then - awk '/^\[tool\.sip\.project\]$/ { print; print "confirm-license = true"; next } { print }' "$SRCROOT/pyproject.toml" > "$SRCROOT/pyproject.toml.tmp" - mv "$SRCROOT/pyproject.toml.tmp" "$SRCROOT/pyproject.toml" - fi - - PYVER={{deps.python.org.version.marketing}} - SITE_PACKAGES="{{prefix}}/share/python/site-packages" - mkdir -p "$SITE_PACKAGES" - - # Use upstream python directly — no per-binding venv, each - # sub-package overlays via PYTHONPATH. - PYTHON="{{deps.python.org.prefix}}/bin/python$PYVER" - - # Single binding, single pip pass. --no-build-isolation so - # our CFLAGS reach the compiler. --no-deps so pip does not - # try to fetch PyQt5-sip from PyPI (pantry's sip is in scope - # via runtime PYTHONPATH). - "$PYTHON" -m pip install --no-build-isolation --no-deps --force-reinstall \ - --target="$SITE_PACKAGES" \ - --config-settings=--enable=QtCore \ - --config-settings=--jobs=1 \ - "$SRCROOT" - -test: - dependencies: - python.org: ~3.11 - script: - - python{{deps.python.org.version.marketing}} -c "from PyQt5 import QtCore" diff --git a/projects/riverbankcomputing.com/pyqt5/QtDBus/package.yml b/projects/riverbankcomputing.com/pyqt5/QtDBus/package.yml deleted file mode 100644 index 229c3f2d05..0000000000 --- a/projects/riverbankcomputing.com/pyqt5/QtDBus/package.yml +++ /dev/null @@ -1,80 +0,0 @@ -# PyQt5.QtDBus — D-Bus binding for PyQt5. -# -# Part of the PyQt5 sub-binding split. See parent meta package at -# riverbankcomputing.com/pyqt5 for topology. PyQt5 is a namespace -# package (`pkgutil.extend_path`), so each sibling's `.so` lives -# in its own prefix and Python merges them at import time via -# the stacked PYTHONPATH. - -distributable: - url: https://pypi.io/packages/source/P/PyQt5/PyQt5-{{ version.raw }}.tar.gz - strip-components: 1 - -versions: - url: https://pypi.org/simple/pyqt5/ - match: /PyQt5-\d+\.\d+\.\d+\.tar\.gz/ - strip: - - /^PyQt5-/ - - /\.tar\.gz/ - -platforms: - - linux/x86-64 - - linux/aarch64 - - darwin/x86-64 - - darwin/aarch64 - -dependencies: - python.org: ~3.11 - qt.io: ^5 - riverbankcomputing.com/sip: '*' - riverbankcomputing.com/pyqt5/QtCore: '*' - -runtime: - env: - PYTHONPATH: '{{prefix}}/share/python/site-packages:$PYTHONPATH' - -build: - dependencies: - riverbankcomputing.com/pyqt-builder: '*' - freedesktop.org/pkg-config: '*' - linux: - llvm.org: <17 - - script: - - run: | - export CXXFLAGS="${CXXFLAGS} -g0" - export CFLAGS="${CFLAGS} -g0" - export MAKEFLAGS="-j1" - - # Pre-accept the GPL license in pyproject.toml so sipbuild - # does not prompt. awk (not sed) because sed's `a\` form - # needs a literal newline that breaks YAML's run-block - # indentation. - if ! grep -q "confirm-license" "$SRCROOT/pyproject.toml"; then - awk '/^\[tool\.sip\.project\]$/ { print; print "confirm-license = true"; next } { print }' "$SRCROOT/pyproject.toml" > "$SRCROOT/pyproject.toml.tmp" - mv "$SRCROOT/pyproject.toml.tmp" "$SRCROOT/pyproject.toml" - fi - - PYVER={{deps.python.org.version.marketing}} - SITE_PACKAGES="{{prefix}}/share/python/site-packages" - mkdir -p "$SITE_PACKAGES" - - # Use upstream python directly — no per-binding venv, each - # sub-package overlays via PYTHONPATH. - PYTHON="{{deps.python.org.prefix}}/bin/python$PYVER" - - # Single binding, single pip pass. --no-build-isolation so - # our CFLAGS reach the compiler. --no-deps so pip does not - # try to fetch PyQt5-sip from PyPI (pantry's sip is in scope - # via runtime PYTHONPATH). - "$PYTHON" -m pip install --no-build-isolation --no-deps --force-reinstall \ - --target="$SITE_PACKAGES" \ - --config-settings=--enable=QtDBus \ - --config-settings=--jobs=1 \ - "$SRCROOT" - -test: - dependencies: - python.org: ~3.11 - script: - - python{{deps.python.org.version.marketing}} -c "from PyQt5 import QtDBus" diff --git a/projects/riverbankcomputing.com/pyqt5/QtGui/package.yml b/projects/riverbankcomputing.com/pyqt5/QtGui/package.yml deleted file mode 100644 index 9079610a5c..0000000000 --- a/projects/riverbankcomputing.com/pyqt5/QtGui/package.yml +++ /dev/null @@ -1,80 +0,0 @@ -# PyQt5.QtGui — GUI primitives (paint, fonts, images, OpenGL) binding for PyQt5. -# -# Part of the PyQt5 sub-binding split. See parent meta package at -# riverbankcomputing.com/pyqt5 for topology. PyQt5 is a namespace -# package (`pkgutil.extend_path`), so each sibling's `.so` lives -# in its own prefix and Python merges them at import time via -# the stacked PYTHONPATH. - -distributable: - url: https://pypi.io/packages/source/P/PyQt5/PyQt5-{{ version.raw }}.tar.gz - strip-components: 1 - -versions: - url: https://pypi.org/simple/pyqt5/ - match: /PyQt5-\d+\.\d+\.\d+\.tar\.gz/ - strip: - - /^PyQt5-/ - - /\.tar\.gz/ - -platforms: - - linux/x86-64 - - linux/aarch64 - - darwin/x86-64 - - darwin/aarch64 - -dependencies: - python.org: ~3.11 - qt.io: ^5 - riverbankcomputing.com/sip: '*' - riverbankcomputing.com/pyqt5/QtCore: '*' - -runtime: - env: - PYTHONPATH: '{{prefix}}/share/python/site-packages:$PYTHONPATH' - -build: - dependencies: - riverbankcomputing.com/pyqt-builder: '*' - freedesktop.org/pkg-config: '*' - linux: - llvm.org: <17 - - script: - - run: | - export CXXFLAGS="${CXXFLAGS} -g0" - export CFLAGS="${CFLAGS} -g0" - export MAKEFLAGS="-j1" - - # Pre-accept the GPL license in pyproject.toml so sipbuild - # does not prompt. awk (not sed) because sed's `a\` form - # needs a literal newline that breaks YAML's run-block - # indentation. - if ! grep -q "confirm-license" "$SRCROOT/pyproject.toml"; then - awk '/^\[tool\.sip\.project\]$/ { print; print "confirm-license = true"; next } { print }' "$SRCROOT/pyproject.toml" > "$SRCROOT/pyproject.toml.tmp" - mv "$SRCROOT/pyproject.toml.tmp" "$SRCROOT/pyproject.toml" - fi - - PYVER={{deps.python.org.version.marketing}} - SITE_PACKAGES="{{prefix}}/share/python/site-packages" - mkdir -p "$SITE_PACKAGES" - - # Use upstream python directly — no per-binding venv, each - # sub-package overlays via PYTHONPATH. - PYTHON="{{deps.python.org.prefix}}/bin/python$PYVER" - - # Single binding, single pip pass. --no-build-isolation so - # our CFLAGS reach the compiler. --no-deps so pip does not - # try to fetch PyQt5-sip from PyPI (pantry's sip is in scope - # via runtime PYTHONPATH). - "$PYTHON" -m pip install --no-build-isolation --no-deps --force-reinstall \ - --target="$SITE_PACKAGES" \ - --config-settings=--enable=QtGui \ - --config-settings=--jobs=1 \ - "$SRCROOT" - -test: - dependencies: - python.org: ~3.11 - script: - - python{{deps.python.org.version.marketing}} -c "from PyQt5 import QtGui" diff --git a/projects/riverbankcomputing.com/pyqt5/QtNetwork/package.yml b/projects/riverbankcomputing.com/pyqt5/QtNetwork/package.yml deleted file mode 100644 index 88c9e29c5b..0000000000 --- a/projects/riverbankcomputing.com/pyqt5/QtNetwork/package.yml +++ /dev/null @@ -1,80 +0,0 @@ -# PyQt5.QtNetwork — Networking (TCP/UDP/SSL/HTTP) binding for PyQt5. -# -# Part of the PyQt5 sub-binding split. See parent meta package at -# riverbankcomputing.com/pyqt5 for topology. PyQt5 is a namespace -# package (`pkgutil.extend_path`), so each sibling's `.so` lives -# in its own prefix and Python merges them at import time via -# the stacked PYTHONPATH. - -distributable: - url: https://pypi.io/packages/source/P/PyQt5/PyQt5-{{ version.raw }}.tar.gz - strip-components: 1 - -versions: - url: https://pypi.org/simple/pyqt5/ - match: /PyQt5-\d+\.\d+\.\d+\.tar\.gz/ - strip: - - /^PyQt5-/ - - /\.tar\.gz/ - -platforms: - - linux/x86-64 - - linux/aarch64 - - darwin/x86-64 - - darwin/aarch64 - -dependencies: - python.org: ~3.11 - qt.io: ^5 - riverbankcomputing.com/sip: '*' - riverbankcomputing.com/pyqt5/QtCore: '*' - -runtime: - env: - PYTHONPATH: '{{prefix}}/share/python/site-packages:$PYTHONPATH' - -build: - dependencies: - riverbankcomputing.com/pyqt-builder: '*' - freedesktop.org/pkg-config: '*' - linux: - llvm.org: <17 - - script: - - run: | - export CXXFLAGS="${CXXFLAGS} -g0" - export CFLAGS="${CFLAGS} -g0" - export MAKEFLAGS="-j1" - - # Pre-accept the GPL license in pyproject.toml so sipbuild - # does not prompt. awk (not sed) because sed's `a\` form - # needs a literal newline that breaks YAML's run-block - # indentation. - if ! grep -q "confirm-license" "$SRCROOT/pyproject.toml"; then - awk '/^\[tool\.sip\.project\]$/ { print; print "confirm-license = true"; next } { print }' "$SRCROOT/pyproject.toml" > "$SRCROOT/pyproject.toml.tmp" - mv "$SRCROOT/pyproject.toml.tmp" "$SRCROOT/pyproject.toml" - fi - - PYVER={{deps.python.org.version.marketing}} - SITE_PACKAGES="{{prefix}}/share/python/site-packages" - mkdir -p "$SITE_PACKAGES" - - # Use upstream python directly — no per-binding venv, each - # sub-package overlays via PYTHONPATH. - PYTHON="{{deps.python.org.prefix}}/bin/python$PYVER" - - # Single binding, single pip pass. --no-build-isolation so - # our CFLAGS reach the compiler. --no-deps so pip does not - # try to fetch PyQt5-sip from PyPI (pantry's sip is in scope - # via runtime PYTHONPATH). - "$PYTHON" -m pip install --no-build-isolation --no-deps --force-reinstall \ - --target="$SITE_PACKAGES" \ - --config-settings=--enable=QtNetwork \ - --config-settings=--jobs=1 \ - "$SRCROOT" - -test: - dependencies: - python.org: ~3.11 - script: - - python{{deps.python.org.version.marketing}} -c "from PyQt5 import QtNetwork" diff --git a/projects/riverbankcomputing.com/pyqt5/QtPrintSupport/package.yml b/projects/riverbankcomputing.com/pyqt5/QtPrintSupport/package.yml deleted file mode 100644 index 1a4de56e2f..0000000000 --- a/projects/riverbankcomputing.com/pyqt5/QtPrintSupport/package.yml +++ /dev/null @@ -1,81 +0,0 @@ -# PyQt5.QtPrintSupport — Printer support binding for PyQt5. -# -# Part of the PyQt5 sub-binding split. See parent meta package at -# riverbankcomputing.com/pyqt5 for topology. PyQt5 is a namespace -# package (`pkgutil.extend_path`), so each sibling's `.so` lives -# in its own prefix and Python merges them at import time via -# the stacked PYTHONPATH. - -distributable: - url: https://pypi.io/packages/source/P/PyQt5/PyQt5-{{ version.raw }}.tar.gz - strip-components: 1 - -versions: - url: https://pypi.org/simple/pyqt5/ - match: /PyQt5-\d+\.\d+\.\d+\.tar\.gz/ - strip: - - /^PyQt5-/ - - /\.tar\.gz/ - -platforms: - - linux/x86-64 - - linux/aarch64 - - darwin/x86-64 - - darwin/aarch64 - -dependencies: - python.org: ~3.11 - qt.io: ^5 - riverbankcomputing.com/sip: '*' - riverbankcomputing.com/pyqt5/QtCore: '*' - riverbankcomputing.com/pyqt5/QtGui: '*' - -runtime: - env: - PYTHONPATH: '{{prefix}}/share/python/site-packages:$PYTHONPATH' - -build: - dependencies: - riverbankcomputing.com/pyqt-builder: '*' - freedesktop.org/pkg-config: '*' - linux: - llvm.org: <17 - - script: - - run: | - export CXXFLAGS="${CXXFLAGS} -g0" - export CFLAGS="${CFLAGS} -g0" - export MAKEFLAGS="-j1" - - # Pre-accept the GPL license in pyproject.toml so sipbuild - # does not prompt. awk (not sed) because sed's `a\` form - # needs a literal newline that breaks YAML's run-block - # indentation. - if ! grep -q "confirm-license" "$SRCROOT/pyproject.toml"; then - awk '/^\[tool\.sip\.project\]$/ { print; print "confirm-license = true"; next } { print }' "$SRCROOT/pyproject.toml" > "$SRCROOT/pyproject.toml.tmp" - mv "$SRCROOT/pyproject.toml.tmp" "$SRCROOT/pyproject.toml" - fi - - PYVER={{deps.python.org.version.marketing}} - SITE_PACKAGES="{{prefix}}/share/python/site-packages" - mkdir -p "$SITE_PACKAGES" - - # Use upstream python directly — no per-binding venv, each - # sub-package overlays via PYTHONPATH. - PYTHON="{{deps.python.org.prefix}}/bin/python$PYVER" - - # Single binding, single pip pass. --no-build-isolation so - # our CFLAGS reach the compiler. --no-deps so pip does not - # try to fetch PyQt5-sip from PyPI (pantry's sip is in scope - # via runtime PYTHONPATH). - "$PYTHON" -m pip install --no-build-isolation --no-deps --force-reinstall \ - --target="$SITE_PACKAGES" \ - --config-settings=--enable=QtPrintSupport \ - --config-settings=--jobs=1 \ - "$SRCROOT" - -test: - dependencies: - python.org: ~3.11 - script: - - python{{deps.python.org.version.marketing}} -c "from PyQt5 import QtPrintSupport" diff --git a/projects/riverbankcomputing.com/pyqt5/QtSql/package.yml b/projects/riverbankcomputing.com/pyqt5/QtSql/package.yml deleted file mode 100644 index 64f2d27b60..0000000000 --- a/projects/riverbankcomputing.com/pyqt5/QtSql/package.yml +++ /dev/null @@ -1,80 +0,0 @@ -# PyQt5.QtSql — SQL database binding for PyQt5. -# -# Part of the PyQt5 sub-binding split. See parent meta package at -# riverbankcomputing.com/pyqt5 for topology. PyQt5 is a namespace -# package (`pkgutil.extend_path`), so each sibling's `.so` lives -# in its own prefix and Python merges them at import time via -# the stacked PYTHONPATH. - -distributable: - url: https://pypi.io/packages/source/P/PyQt5/PyQt5-{{ version.raw }}.tar.gz - strip-components: 1 - -versions: - url: https://pypi.org/simple/pyqt5/ - match: /PyQt5-\d+\.\d+\.\d+\.tar\.gz/ - strip: - - /^PyQt5-/ - - /\.tar\.gz/ - -platforms: - - linux/x86-64 - - linux/aarch64 - - darwin/x86-64 - - darwin/aarch64 - -dependencies: - python.org: ~3.11 - qt.io: ^5 - riverbankcomputing.com/sip: '*' - riverbankcomputing.com/pyqt5/QtCore: '*' - -runtime: - env: - PYTHONPATH: '{{prefix}}/share/python/site-packages:$PYTHONPATH' - -build: - dependencies: - riverbankcomputing.com/pyqt-builder: '*' - freedesktop.org/pkg-config: '*' - linux: - llvm.org: <17 - - script: - - run: | - export CXXFLAGS="${CXXFLAGS} -g0" - export CFLAGS="${CFLAGS} -g0" - export MAKEFLAGS="-j1" - - # Pre-accept the GPL license in pyproject.toml so sipbuild - # does not prompt. awk (not sed) because sed's `a\` form - # needs a literal newline that breaks YAML's run-block - # indentation. - if ! grep -q "confirm-license" "$SRCROOT/pyproject.toml"; then - awk '/^\[tool\.sip\.project\]$/ { print; print "confirm-license = true"; next } { print }' "$SRCROOT/pyproject.toml" > "$SRCROOT/pyproject.toml.tmp" - mv "$SRCROOT/pyproject.toml.tmp" "$SRCROOT/pyproject.toml" - fi - - PYVER={{deps.python.org.version.marketing}} - SITE_PACKAGES="{{prefix}}/share/python/site-packages" - mkdir -p "$SITE_PACKAGES" - - # Use upstream python directly — no per-binding venv, each - # sub-package overlays via PYTHONPATH. - PYTHON="{{deps.python.org.prefix}}/bin/python$PYVER" - - # Single binding, single pip pass. --no-build-isolation so - # our CFLAGS reach the compiler. --no-deps so pip does not - # try to fetch PyQt5-sip from PyPI (pantry's sip is in scope - # via runtime PYTHONPATH). - "$PYTHON" -m pip install --no-build-isolation --no-deps --force-reinstall \ - --target="$SITE_PACKAGES" \ - --config-settings=--enable=QtSql \ - --config-settings=--jobs=1 \ - "$SRCROOT" - -test: - dependencies: - python.org: ~3.11 - script: - - python{{deps.python.org.version.marketing}} -c "from PyQt5 import QtSql" diff --git a/projects/riverbankcomputing.com/pyqt5/QtSvg/package.yml b/projects/riverbankcomputing.com/pyqt5/QtSvg/package.yml deleted file mode 100644 index 51695279ec..0000000000 --- a/projects/riverbankcomputing.com/pyqt5/QtSvg/package.yml +++ /dev/null @@ -1,81 +0,0 @@ -# PyQt5.QtSvg — SVG rendering binding for PyQt5. -# -# Part of the PyQt5 sub-binding split. See parent meta package at -# riverbankcomputing.com/pyqt5 for topology. PyQt5 is a namespace -# package (`pkgutil.extend_path`), so each sibling's `.so` lives -# in its own prefix and Python merges them at import time via -# the stacked PYTHONPATH. - -distributable: - url: https://pypi.io/packages/source/P/PyQt5/PyQt5-{{ version.raw }}.tar.gz - strip-components: 1 - -versions: - url: https://pypi.org/simple/pyqt5/ - match: /PyQt5-\d+\.\d+\.\d+\.tar\.gz/ - strip: - - /^PyQt5-/ - - /\.tar\.gz/ - -platforms: - - linux/x86-64 - - linux/aarch64 - - darwin/x86-64 - - darwin/aarch64 - -dependencies: - python.org: ~3.11 - qt.io: ^5 - riverbankcomputing.com/sip: '*' - riverbankcomputing.com/pyqt5/QtCore: '*' - riverbankcomputing.com/pyqt5/QtGui: '*' - -runtime: - env: - PYTHONPATH: '{{prefix}}/share/python/site-packages:$PYTHONPATH' - -build: - dependencies: - riverbankcomputing.com/pyqt-builder: '*' - freedesktop.org/pkg-config: '*' - linux: - llvm.org: <17 - - script: - - run: | - export CXXFLAGS="${CXXFLAGS} -g0" - export CFLAGS="${CFLAGS} -g0" - export MAKEFLAGS="-j1" - - # Pre-accept the GPL license in pyproject.toml so sipbuild - # does not prompt. awk (not sed) because sed's `a\` form - # needs a literal newline that breaks YAML's run-block - # indentation. - if ! grep -q "confirm-license" "$SRCROOT/pyproject.toml"; then - awk '/^\[tool\.sip\.project\]$/ { print; print "confirm-license = true"; next } { print }' "$SRCROOT/pyproject.toml" > "$SRCROOT/pyproject.toml.tmp" - mv "$SRCROOT/pyproject.toml.tmp" "$SRCROOT/pyproject.toml" - fi - - PYVER={{deps.python.org.version.marketing}} - SITE_PACKAGES="{{prefix}}/share/python/site-packages" - mkdir -p "$SITE_PACKAGES" - - # Use upstream python directly — no per-binding venv, each - # sub-package overlays via PYTHONPATH. - PYTHON="{{deps.python.org.prefix}}/bin/python$PYVER" - - # Single binding, single pip pass. --no-build-isolation so - # our CFLAGS reach the compiler. --no-deps so pip does not - # try to fetch PyQt5-sip from PyPI (pantry's sip is in scope - # via runtime PYTHONPATH). - "$PYTHON" -m pip install --no-build-isolation --no-deps --force-reinstall \ - --target="$SITE_PACKAGES" \ - --config-settings=--enable=QtSvg \ - --config-settings=--jobs=1 \ - "$SRCROOT" - -test: - dependencies: - python.org: ~3.11 - script: - - python{{deps.python.org.version.marketing}} -c "from PyQt5 import QtSvg" diff --git a/projects/riverbankcomputing.com/pyqt5/QtTest/package.yml b/projects/riverbankcomputing.com/pyqt5/QtTest/package.yml deleted file mode 100644 index 55d89b2f0e..0000000000 --- a/projects/riverbankcomputing.com/pyqt5/QtTest/package.yml +++ /dev/null @@ -1,80 +0,0 @@ -# PyQt5.QtTest — Unit-test framework binding for PyQt5. -# -# Part of the PyQt5 sub-binding split. See parent meta package at -# riverbankcomputing.com/pyqt5 for topology. PyQt5 is a namespace -# package (`pkgutil.extend_path`), so each sibling's `.so` lives -# in its own prefix and Python merges them at import time via -# the stacked PYTHONPATH. - -distributable: - url: https://pypi.io/packages/source/P/PyQt5/PyQt5-{{ version.raw }}.tar.gz - strip-components: 1 - -versions: - url: https://pypi.org/simple/pyqt5/ - match: /PyQt5-\d+\.\d+\.\d+\.tar\.gz/ - strip: - - /^PyQt5-/ - - /\.tar\.gz/ - -platforms: - - linux/x86-64 - - linux/aarch64 - - darwin/x86-64 - - darwin/aarch64 - -dependencies: - python.org: ~3.11 - qt.io: ^5 - riverbankcomputing.com/sip: '*' - riverbankcomputing.com/pyqt5/QtCore: '*' - -runtime: - env: - PYTHONPATH: '{{prefix}}/share/python/site-packages:$PYTHONPATH' - -build: - dependencies: - riverbankcomputing.com/pyqt-builder: '*' - freedesktop.org/pkg-config: '*' - linux: - llvm.org: <17 - - script: - - run: | - export CXXFLAGS="${CXXFLAGS} -g0" - export CFLAGS="${CFLAGS} -g0" - export MAKEFLAGS="-j1" - - # Pre-accept the GPL license in pyproject.toml so sipbuild - # does not prompt. awk (not sed) because sed's `a\` form - # needs a literal newline that breaks YAML's run-block - # indentation. - if ! grep -q "confirm-license" "$SRCROOT/pyproject.toml"; then - awk '/^\[tool\.sip\.project\]$/ { print; print "confirm-license = true"; next } { print }' "$SRCROOT/pyproject.toml" > "$SRCROOT/pyproject.toml.tmp" - mv "$SRCROOT/pyproject.toml.tmp" "$SRCROOT/pyproject.toml" - fi - - PYVER={{deps.python.org.version.marketing}} - SITE_PACKAGES="{{prefix}}/share/python/site-packages" - mkdir -p "$SITE_PACKAGES" - - # Use upstream python directly — no per-binding venv, each - # sub-package overlays via PYTHONPATH. - PYTHON="{{deps.python.org.prefix}}/bin/python$PYVER" - - # Single binding, single pip pass. --no-build-isolation so - # our CFLAGS reach the compiler. --no-deps so pip does not - # try to fetch PyQt5-sip from PyPI (pantry's sip is in scope - # via runtime PYTHONPATH). - "$PYTHON" -m pip install --no-build-isolation --no-deps --force-reinstall \ - --target="$SITE_PACKAGES" \ - --config-settings=--enable=QtTest \ - --config-settings=--jobs=1 \ - "$SRCROOT" - -test: - dependencies: - python.org: ~3.11 - script: - - python{{deps.python.org.version.marketing}} -c "from PyQt5 import QtTest" diff --git a/projects/riverbankcomputing.com/pyqt5/QtWidgets/package.yml b/projects/riverbankcomputing.com/pyqt5/QtWidgets/package.yml deleted file mode 100644 index 77772283f4..0000000000 --- a/projects/riverbankcomputing.com/pyqt5/QtWidgets/package.yml +++ /dev/null @@ -1,81 +0,0 @@ -# PyQt5.QtWidgets — Full Qt 5 widget set — heaviest of the bindings. -# -# Part of the PyQt5 sub-binding split. See parent meta package at -# riverbankcomputing.com/pyqt5 for topology. PyQt5 is a namespace -# package (`pkgutil.extend_path`), so each sibling's `.so` lives -# in its own prefix and Python merges them at import time via -# the stacked PYTHONPATH. - -distributable: - url: https://pypi.io/packages/source/P/PyQt5/PyQt5-{{ version.raw }}.tar.gz - strip-components: 1 - -versions: - url: https://pypi.org/simple/pyqt5/ - match: /PyQt5-\d+\.\d+\.\d+\.tar\.gz/ - strip: - - /^PyQt5-/ - - /\.tar\.gz/ - -platforms: - - linux/x86-64 - - linux/aarch64 - - darwin/x86-64 - - darwin/aarch64 - -dependencies: - python.org: ~3.11 - qt.io: ^5 - riverbankcomputing.com/sip: '*' - riverbankcomputing.com/pyqt5/QtCore: '*' - riverbankcomputing.com/pyqt5/QtGui: '*' - -runtime: - env: - PYTHONPATH: '{{prefix}}/share/python/site-packages:$PYTHONPATH' - -build: - dependencies: - riverbankcomputing.com/pyqt-builder: '*' - freedesktop.org/pkg-config: '*' - linux: - llvm.org: <17 - - script: - - run: | - export CXXFLAGS="${CXXFLAGS} -g0" - export CFLAGS="${CFLAGS} -g0" - export MAKEFLAGS="-j1" - - # Pre-accept the GPL license in pyproject.toml so sipbuild - # does not prompt. awk (not sed) because sed's `a\` form - # needs a literal newline that breaks YAML's run-block - # indentation. - if ! grep -q "confirm-license" "$SRCROOT/pyproject.toml"; then - awk '/^\[tool\.sip\.project\]$/ { print; print "confirm-license = true"; next } { print }' "$SRCROOT/pyproject.toml" > "$SRCROOT/pyproject.toml.tmp" - mv "$SRCROOT/pyproject.toml.tmp" "$SRCROOT/pyproject.toml" - fi - - PYVER={{deps.python.org.version.marketing}} - SITE_PACKAGES="{{prefix}}/share/python/site-packages" - mkdir -p "$SITE_PACKAGES" - - # Use upstream python directly — no per-binding venv, each - # sub-package overlays via PYTHONPATH. - PYTHON="{{deps.python.org.prefix}}/bin/python$PYVER" - - # Single binding, single pip pass. --no-build-isolation so - # our CFLAGS reach the compiler. --no-deps so pip does not - # try to fetch PyQt5-sip from PyPI (pantry's sip is in scope - # via runtime PYTHONPATH). - "$PYTHON" -m pip install --no-build-isolation --no-deps --force-reinstall \ - --target="$SITE_PACKAGES" \ - --config-settings=--enable=QtWidgets \ - --config-settings=--jobs=1 \ - "$SRCROOT" - -test: - dependencies: - python.org: ~3.11 - script: - - python{{deps.python.org.version.marketing}} -c "from PyQt5 import QtWidgets" diff --git a/projects/riverbankcomputing.com/pyqt5/QtXml/package.yml b/projects/riverbankcomputing.com/pyqt5/QtXml/package.yml deleted file mode 100644 index ab2c4d3da9..0000000000 --- a/projects/riverbankcomputing.com/pyqt5/QtXml/package.yml +++ /dev/null @@ -1,80 +0,0 @@ -# PyQt5.QtXml — DOM XML binding for PyQt5. -# -# Part of the PyQt5 sub-binding split. See parent meta package at -# riverbankcomputing.com/pyqt5 for topology. PyQt5 is a namespace -# package (`pkgutil.extend_path`), so each sibling's `.so` lives -# in its own prefix and Python merges them at import time via -# the stacked PYTHONPATH. - -distributable: - url: https://pypi.io/packages/source/P/PyQt5/PyQt5-{{ version.raw }}.tar.gz - strip-components: 1 - -versions: - url: https://pypi.org/simple/pyqt5/ - match: /PyQt5-\d+\.\d+\.\d+\.tar\.gz/ - strip: - - /^PyQt5-/ - - /\.tar\.gz/ - -platforms: - - linux/x86-64 - - linux/aarch64 - - darwin/x86-64 - - darwin/aarch64 - -dependencies: - python.org: ~3.11 - qt.io: ^5 - riverbankcomputing.com/sip: '*' - riverbankcomputing.com/pyqt5/QtCore: '*' - -runtime: - env: - PYTHONPATH: '{{prefix}}/share/python/site-packages:$PYTHONPATH' - -build: - dependencies: - riverbankcomputing.com/pyqt-builder: '*' - freedesktop.org/pkg-config: '*' - linux: - llvm.org: <17 - - script: - - run: | - export CXXFLAGS="${CXXFLAGS} -g0" - export CFLAGS="${CFLAGS} -g0" - export MAKEFLAGS="-j1" - - # Pre-accept the GPL license in pyproject.toml so sipbuild - # does not prompt. awk (not sed) because sed's `a\` form - # needs a literal newline that breaks YAML's run-block - # indentation. - if ! grep -q "confirm-license" "$SRCROOT/pyproject.toml"; then - awk '/^\[tool\.sip\.project\]$/ { print; print "confirm-license = true"; next } { print }' "$SRCROOT/pyproject.toml" > "$SRCROOT/pyproject.toml.tmp" - mv "$SRCROOT/pyproject.toml.tmp" "$SRCROOT/pyproject.toml" - fi - - PYVER={{deps.python.org.version.marketing}} - SITE_PACKAGES="{{prefix}}/share/python/site-packages" - mkdir -p "$SITE_PACKAGES" - - # Use upstream python directly — no per-binding venv, each - # sub-package overlays via PYTHONPATH. - PYTHON="{{deps.python.org.prefix}}/bin/python$PYVER" - - # Single binding, single pip pass. --no-build-isolation so - # our CFLAGS reach the compiler. --no-deps so pip does not - # try to fetch PyQt5-sip from PyPI (pantry's sip is in scope - # via runtime PYTHONPATH). - "$PYTHON" -m pip install --no-build-isolation --no-deps --force-reinstall \ - --target="$SITE_PACKAGES" \ - --config-settings=--enable=QtXml \ - --config-settings=--jobs=1 \ - "$SRCROOT" - -test: - dependencies: - python.org: ~3.11 - script: - - python{{deps.python.org.version.marketing}} -c "from PyQt5 import QtXml" diff --git a/projects/riverbankcomputing.com/pyqt5/package.yml b/projects/riverbankcomputing.com/pyqt5/package.yml index 92f968c2de..d4ef02b4a4 100644 --- a/projects/riverbankcomputing.com/pyqt5/package.yml +++ b/projects/riverbankcomputing.com/pyqt5/package.yml @@ -1,12 +1,18 @@ -# PyQt5 — Meta-package: pulls all PyQt5 sub-bindings together. +# PyQt5 — Python bindings for Qt 5, installed from upstream's official +# PyPI wheel (which bundles the Qt5 libraries). Provides the +# pyuic5/pyrcc5/pylupdate5 tools and an importable `PyQt5`. # -# Equivalent to homebrew's `pyqt@5` formula or apt's `python3-pyqt5`. -# Per-binding sub-recipes (QtCore / QtGui / QtWidgets / etc.) live in -# sibling directories so each binding gets its own CI job and its own -# 6 h timeout — the monolithic recipe was being OOM-killed and then -# GHA-cancelled at 1h33min. See PR pkgxdev/pantry#13064. +# Why vendored (wheel): building PyQt5 from the sip sources compiles +# enormous generated C++ per binding and OOM-killed CI; splitting into +# per-binding sub-recipes then hit a lockstep co-dependency (each +# binding 404'd resolving its sibling's not-yet-published bottle). The +# official wheel sidesteps both, in one package. # -# Top 300 holdout #591. +# Path to a from-source recipe: compile sip-build + the PyQt5 bindings +# against a Qt5 (qtbase) dep — would need Qt5 + riverbankcomputing.com/sip +# in pantry and per-binding builds with bounded compile parallelism (or a +# larger CI memory budget) to avoid the OOM; that would also restore +# linux/aarch64 (no upstream wheel for it, hence omitted here). distributable: url: https://pypi.io/packages/source/P/PyQt5/PyQt5-{{ version.raw }}.tar.gz @@ -21,39 +27,37 @@ versions: platforms: - linux/x86-64 - - linux/aarch64 - darwin/x86-64 - darwin/aarch64 dependencies: - riverbankcomputing.com/pyqt5/QtCore: '*' - riverbankcomputing.com/pyqt5/QtDBus: '*' - riverbankcomputing.com/pyqt5/QtNetwork: '*' - riverbankcomputing.com/pyqt5/QtSql: '*' - riverbankcomputing.com/pyqt5/QtTest: '*' - riverbankcomputing.com/pyqt5/QtXml: '*' - riverbankcomputing.com/pyqt5/QtGui: '*' - riverbankcomputing.com/pyqt5/QtSvg: '*' - riverbankcomputing.com/pyqt5/QtPrintSupport: '*' - riverbankcomputing.com/pyqt5/QtWidgets: '*' - -# Meta package: no build artifacts of its own — every sub-binding -# carries its own .so into its own prefix and Python's pkgutil -# extends `PyQt5/__path__` to merge them at import time. We still -# need a `build.script` because pkgx requires one; emit a marker file -# so the package is non-empty and brewkit's bottling sees something. + pkgx.sh: ">=1" + python.org: ~3.11 + +runtime: + env: + # Expose `import PyQt5` to users/dependents from the sealed venv. + PYTHONPATH: "${{prefix}}/venv/lib/python{{deps.python.org.version.marketing}}/site-packages" + build: + dependencies: + python.org: ~3.11 script: - - run: | - mkdir -p "{{prefix}}/share/pyqt5" - echo "PyQt5 {{version}} (meta-package — see sub-bindings)" > "{{prefix}}/share/pyqt5/README" + # Install the prebuilt wheels (Qt bundled) into a venv — pip and + # python there share a version, so PyQt5-sip's ABI matches python. + # `--only-binary` guarantees the wheel (never an sdist recompile). + - bkpyvenv stage {{prefix}} {{version}} + - ${{prefix}}/venv/bin/pip install --only-binary=:all: PyQt5=={{version}} PyQt5-sip + - bkpyvenv seal {{prefix}} pyuic5 pyrcc5 pylupdate5 + +provides: + - bin/pyuic5 + - bin/pyrcc5 + - bin/pylupdate5 test: dependencies: python.org: ~3.11 script: - # Importing QtCore exercises the namespace-package overlay across - # at least one sub-binding prefix. Each sub-binding has its own - # test pass; this test only checks that the meta successfully - # pulled them all into scope. - - python{{deps.python.org.version.marketing}} -c "from PyQt5 import QtCore; print(QtCore.QT_VERSION_STR)" + - pyuic5 --version 2>&1 | grep {{version}} + - python{{deps.python.org.version.marketing}} -c "from PyQt5 import QtCore, QtWidgets; print(QtCore.QT_VERSION_STR)" From 45afa0bddafd2d14dc06e849f66a8497740b4f00 Mon Sep 17 00:00:00 2001 From: tannevaled Date: Sun, 14 Jun 2026 15:23:59 +0200 Subject: [PATCH 13/19] fix(pyqt5): quote the pip-install script line `--only-binary=:all: PyQt5==...` contains a colon-space, so YAML parsed the list item as a mapping (brewkit: 'every node must contain a run key'). Single-quote it so it's a plain string command. Co-Authored-By: Claude Opus 4.8 (1M context) --- projects/riverbankcomputing.com/pyqt5/package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/riverbankcomputing.com/pyqt5/package.yml b/projects/riverbankcomputing.com/pyqt5/package.yml index d4ef02b4a4..ab986deecf 100644 --- a/projects/riverbankcomputing.com/pyqt5/package.yml +++ b/projects/riverbankcomputing.com/pyqt5/package.yml @@ -47,7 +47,7 @@ build: # python there share a version, so PyQt5-sip's ABI matches python. # `--only-binary` guarantees the wheel (never an sdist recompile). - bkpyvenv stage {{prefix}} {{version}} - - ${{prefix}}/venv/bin/pip install --only-binary=:all: PyQt5=={{version}} PyQt5-sip + - '${{prefix}}/venv/bin/pip install --only-binary=:all: PyQt5=={{version}} PyQt5-sip' - bkpyvenv seal {{prefix}} pyuic5 pyrcc5 pylupdate5 provides: From 19a418e94b4ea4816ea19085f51132c4a1b81797 Mon Sep 17 00:00:00 2001 From: tannevaled Date: Sun, 14 Jun 2026 15:33:27 +0200 Subject: [PATCH 14/19] riverbankcomputing.com/pyqt5: scope vendored wheel to darwin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The manylinux wheel is not self-contained — its QtWidgets dlopens the host X11/xcb/mesa GUI stack, which pantry doesn't package, so it can't import on the CI sandbox (only QtCore, via glib, works there). The macOS wheels bundle Qt5 and import QtWidgets cleanly. Ship darwin-only rather than a half-working linux build; document the GUI-stack blocker as the path to restoring linux + a from-source recipe. --- .../riverbankcomputing.com/pyqt5/package.yml | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/projects/riverbankcomputing.com/pyqt5/package.yml b/projects/riverbankcomputing.com/pyqt5/package.yml index ab986deecf..22b5d0cece 100644 --- a/projects/riverbankcomputing.com/pyqt5/package.yml +++ b/projects/riverbankcomputing.com/pyqt5/package.yml @@ -8,11 +8,21 @@ # binding 404'd resolving its sibling's not-yet-published bottle). The # official wheel sidesteps both, in one package. # -# Path to a from-source recipe: compile sip-build + the PyQt5 bindings -# against a Qt5 (qtbase) dep — would need Qt5 + riverbankcomputing.com/sip -# in pantry and per-binding builds with bounded compile parallelism (or a -# larger CI memory budget) to avoid the OOM; that would also restore -# linux/aarch64 (no upstream wheel for it, hence omitted here). +# Why darwin-only: the macOS wheels are self-contained (Qt5 + the +# platform plugin are bundled and rpath-wired), so QtWidgets imports +# with no external deps. The manylinux wheel is NOT self-contained — its +# QtGui/QtWidgets dlopen the host X11/xcb/mesa GUI stack (libxcb, +# libX11, libGL, …), none of which pantry currently packages. QtCore +# alone imports on linux (it only needs gnome.org/glib), but a PyQt5 that +# can't load QtWidgets defeats the point, so linux is omitted rather than +# shipped half-working. +# +# Path to a from-source recipe (and to restoring linux): land the Qt5 GUI +# runtime in pantry (libxcb + xcb-util-*, libX11, mesa/libGL, libxkbcommon, +# fontconfig, freetype, dbus), then either depend on them at runtime for +# the manylinux wheel, or compile riverbankcomputing.com/sip + the PyQt5 +# bindings against a pantry Qt5 (qtbase) with bounded compile parallelism +# (the unbounded per-binding C++ compile is what OOM-killed CI before). distributable: url: https://pypi.io/packages/source/P/PyQt5/PyQt5-{{ version.raw }}.tar.gz @@ -26,7 +36,6 @@ versions: - /\.tar\.gz/ platforms: - - linux/x86-64 - darwin/x86-64 - darwin/aarch64 From 3abd7c7b8ce312ba9b3a9a9b445821825f99f486 Mon Sep 17 00:00:00 2001 From: tannevaled Date: Sun, 14 Jun 2026 18:17:19 +0200 Subject: [PATCH 15/19] riverbankcomputing.com/pyqt5: restore linux/x86-64 with X.org runtime deps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The manylinux wheel's QtWidgets dlopens the host GUI stack, which IS in pantry under x.org/* + mesa3d.org + xkbcommon.org (I had earlier looked for x.org/libxcb etc. — wrong names — and wrongly concluded the stack was absent). Verified in a minimal amd64 sandbox that 'from PyQt5 import QtWidgets' imports cleanly with exactly the linux-scoped deps added here. macOS wheels stay self-contained (deps are linux-only). --- .../riverbankcomputing.com/pyqt5/package.yml | 44 +++++++++++++------ 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/projects/riverbankcomputing.com/pyqt5/package.yml b/projects/riverbankcomputing.com/pyqt5/package.yml index 22b5d0cece..2de9eff856 100644 --- a/projects/riverbankcomputing.com/pyqt5/package.yml +++ b/projects/riverbankcomputing.com/pyqt5/package.yml @@ -8,21 +8,18 @@ # binding 404'd resolving its sibling's not-yet-published bottle). The # official wheel sidesteps both, in one package. # -# Why darwin-only: the macOS wheels are self-contained (Qt5 + the -# platform plugin are bundled and rpath-wired), so QtWidgets imports -# with no external deps. The manylinux wheel is NOT self-contained — its -# QtGui/QtWidgets dlopen the host X11/xcb/mesa GUI stack (libxcb, -# libX11, libGL, …), none of which pantry currently packages. QtCore -# alone imports on linux (it only needs gnome.org/glib), but a PyQt5 that -# can't load QtWidgets defeats the point, so linux is omitted rather than -# shipped half-working. +# Platform note: the macOS wheels are self-contained (Qt5 + the cocoa +# platform plugin are bundled and rpath-wired). The manylinux wheel is +# NOT self-contained — its QtGui/QtWidgets dlopen the host X11/xcb/mesa +# GUI stack, so on linux we pull that stack in as runtime deps below +# (x.org/*, mesa3d.org, xkbcommon.org, glib, fontconfig, freetype, dbus). +# Confirmed `from PyQt5 import QtWidgets` imports on a minimal linux +# sandbox with exactly those deps. # -# Path to a from-source recipe (and to restoring linux): land the Qt5 GUI -# runtime in pantry (libxcb + xcb-util-*, libX11, mesa/libGL, libxkbcommon, -# fontconfig, freetype, dbus), then either depend on them at runtime for -# the manylinux wheel, or compile riverbankcomputing.com/sip + the PyQt5 -# bindings against a pantry Qt5 (qtbase) with bounded compile parallelism -# (the unbounded per-binding C++ compile is what OOM-killed CI before). +# Path to a from-source recipe: compile riverbankcomputing.com/sip + the +# PyQt5 bindings against a pantry Qt5 (qtbase) with bounded compile +# parallelism (the unbounded per-binding C++ compile is what OOM-killed +# CI before) — that would also restore linux/aarch64 (no upstream wheel). distributable: url: https://pypi.io/packages/source/P/PyQt5/PyQt5-{{ version.raw }}.tar.gz @@ -36,12 +33,31 @@ versions: - /\.tar\.gz/ platforms: + - linux/x86-64 - darwin/x86-64 - darwin/aarch64 dependencies: pkgx.sh: ">=1" python.org: ~3.11 + # The manylinux wheel's QtGui/QtWidgets dlopen the host GUI stack; + # the macOS wheels bundle it, so these are linux-only. + linux: + gnome.org/glib: '*' + freetype.org: '*' + freedesktop.org/fontconfig: '*' + freedesktop.org/dbus: '*' + xkbcommon.org: '*' + mesa3d.org: '*' + x.org/x11: '*' + x.org/xcb: '*' + x.org/xcb-util: '*' + x.org/xrender: '*' + x.org/xfixes: '*' + x.org/xrandr: '*' + x.org/xi: '*' + x.org/xau: '*' + x.org/xdmcp: '*' runtime: env: From 1fd373173ea3066364d660a376b39e989434b119 Mon Sep 17 00:00:00 2001 From: tannevaled Date: Mon, 15 Jun 2026 20:15:26 +0200 Subject: [PATCH 16/19] riverbankcomputing.com/pyqt5: build from source (drop vendored wheel) The from-source prereqs now exist in the pantry (they didn't when this first shipped as a wheel): qt.io provides Qt 5.15.10, plus sip and pyqt-builder. Build the bindings with sip-install against qt.io's qmake, bounding the compile with --jobs 1 + MAKEFLAGS=-j1 (the unbounded C++ compile is what OOM-killed the earlier from-source attempt). Qt5 is no longer bundled, so qt.io is a runtime dep; adds linux/aarch64 (no wheel existed for it). --- .../riverbankcomputing.com/pyqt5/package.yml | 91 +++++++++---------- 1 file changed, 42 insertions(+), 49 deletions(-) diff --git a/projects/riverbankcomputing.com/pyqt5/package.yml b/projects/riverbankcomputing.com/pyqt5/package.yml index 2de9eff856..0e4b63cb10 100644 --- a/projects/riverbankcomputing.com/pyqt5/package.yml +++ b/projects/riverbankcomputing.com/pyqt5/package.yml @@ -1,48 +1,29 @@ -# PyQt5 — Python bindings for Qt 5, installed from upstream's official -# PyPI wheel (which bundles the Qt5 libraries). Provides the -# pyuic5/pyrcc5/pylupdate5 tools and an importable `PyQt5`. +# PyQt5 — built from the PyPI sdist with sip-install (the SIP build tool from +# riverbankcomputing.com/sip + the pyqtbuild backend from +# riverbankcomputing.com/pyqt-builder), linked against the Qt5 from qt.io. # -# Why vendored (wheel): building PyQt5 from the sip sources compiles -# enormous generated C++ per binding and OOM-killed CI; splitting into -# per-binding sub-recipes then hit a lockstep co-dependency (each -# binding 404'd resolving its sibling's not-yet-published bottle). The -# official wheel sidesteps both, in one package. -# -# Platform note: the macOS wheels are self-contained (Qt5 + the cocoa -# platform plugin are bundled and rpath-wired). The manylinux wheel is -# NOT self-contained — its QtGui/QtWidgets dlopen the host X11/xcb/mesa -# GUI stack, so on linux we pull that stack in as runtime deps below -# (x.org/*, mesa3d.org, xkbcommon.org, glib, fontconfig, freetype, dbus). -# Confirmed `from PyQt5 import QtWidgets` imports on a minimal linux -# sandbox with exactly those deps. -# -# Path to a from-source recipe: compile riverbankcomputing.com/sip + the -# PyQt5 bindings against a pantry Qt5 (qtbase) with bounded compile -# parallelism (the unbounded per-binding C++ compile is what OOM-killed -# CI before) — that would also restore linux/aarch64 (no upstream wheel). +# Notes: +# - Qt5 is NOT bundled (unlike the old PyPI wheel): the built bindings load +# qt.io's Qt5 libs at runtime, hence qt.io is a runtime dependency and we +# point sip-install at its qmake. +# - PyQt5's generated QtGui/QtWidgets C++ units are huge; unbounded parallel +# compilation OOM-killed CI, so we bound it with `--jobs 1` (+ MAKEFLAGS=-j1). +# - PyQt5 uses the separate PyQt5-sip runtime module (the private `PyQt5.sip`): +# sip-install does NOT build it, so we pip-install PyQt5-sip into the venv. distributable: url: https://pypi.io/packages/source/P/PyQt5/PyQt5-{{ version.raw }}.tar.gz strip-components: 1 - versions: url: https://pypi.org/simple/pyqt5/ match: /PyQt5-\d+\.\d+\.\d+\.tar\.gz/ - strip: - - /^PyQt5-/ - - /\.tar\.gz/ - -platforms: - - linux/x86-64 - - darwin/x86-64 - - darwin/aarch64 - + strip: [/^PyQt5-/, /\.tar\.gz/] +platforms: [linux/x86-64, linux/aarch64, darwin/x86-64, darwin/aarch64] dependencies: pkgx.sh: ">=1" python.org: ~3.11 - # The manylinux wheel's QtGui/QtWidgets dlopen the host GUI stack; - # the macOS wheels bundle it, so these are linux-only. - linux: + qt.io: ~5.15 # Qt5 is no longer bundled; bindings load it at runtime + linux: # Qt5's xcb plugin GUI stack, needed at runtime gnome.org/glib: '*' freetype.org: '*' freedesktop.org/fontconfig: '*' @@ -58,31 +39,43 @@ dependencies: x.org/xi: '*' x.org/xau: '*' x.org/xdmcp: '*' - runtime: env: - # Expose `import PyQt5` to users/dependents from the sealed venv. PYTHONPATH: "${{prefix}}/venv/lib/python{{deps.python.org.version.marketing}}/site-packages" - build: dependencies: python.org: ~3.11 + riverbankcomputing.com/sip: '*' # provides sip-install/sip-build + riverbankcomputing.com/pyqt-builder: '*' # pyqtbuild backend sip-install uses + qt.io: ~5.15 # qmake + Qt5 headers/libs + gnu.org/make: '*' + linux: + llvm.org: <17 # mirror the sip recipe's toolchain script: - # Install the prebuilt wheels (Qt bundled) into a venv — pip and - # python there share a version, so PyQt5-sip's ABI matches python. - # `--only-binary` guarantees the wheel (never an sdist recompile). - bkpyvenv stage {{prefix}} {{version}} - - '${{prefix}}/venv/bin/pip install --only-binary=:all: PyQt5=={{version}} PyQt5-sip' + # Build + install PyQt5 from the extracted sdist against qt.io's Qt5. + # --confirm-license: accept the GPL terms non-interactively (else CI hangs). + # --jobs 1 (+ MAKEFLAGS=-j1): bound the C++ compile to avoid OOM. + # --target-dir: land PyQt5/ in the venv site-packages so PYTHONPATH/test work. + - sip-install + --confirm-license + --qmake {{deps.qt.io.prefix}}/bin/qmake + --jobs 1 + --target-dir {{prefix}}/venv/lib/python{{deps.python.org.version.marketing}}/site-packages + --verbose + # PyQt5 needs the separate PyQt5-sip runtime module (private PyQt5.sip); + # sip-install does not build it, so install it into the venv. + - '{{prefix}}/venv/bin/pip install PyQt5-sip' - bkpyvenv seal {{prefix}} pyuic5 pyrcc5 pylupdate5 - -provides: - - bin/pyuic5 - - bin/pyrcc5 - - bin/pylupdate5 - + env: + MAKEFLAGS: -j1 # belt-and-suspenders OOM bound for the qmake-driven C++ build + linux: + CC: clang + CXX: clang++ + AS: llvm-as +provides: [bin/pyuic5, bin/pyrcc5, bin/pylupdate5] test: - dependencies: - python.org: ~3.11 + dependencies: { python.org: ~3.11 } script: - pyuic5 --version 2>&1 | grep {{version}} - python{{deps.python.org.version.marketing}} -c "from PyQt5 import QtCore, QtWidgets; print(QtCore.QT_VERSION_STR)" From 49de3f88a55e86fb38e50bae579fb3e1e65a54ef Mon Sep 17 00:00:00 2001 From: tannevaled Date: Mon, 15 Jun 2026 20:21:39 +0200 Subject: [PATCH 17/19] pyqt5: drop llvm<17 pin (conflicted with mesa's libLLVM) The sip-install QtGui config test failed to load libLLVM.so.22.1: the llvm.org<17 build dep (copied from the sip recipe) shadowed the newer libLLVM that mesa3d.org's libGL needs. PyQt5's bindings build with the system g++ via qmake (no clang needed), so drop the llvm pin and the clang/AS env and let mesa pull its matching libLLVM. --- projects/riverbankcomputing.com/pyqt5/package.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/projects/riverbankcomputing.com/pyqt5/package.yml b/projects/riverbankcomputing.com/pyqt5/package.yml index 0e4b63cb10..a5ac7cc553 100644 --- a/projects/riverbankcomputing.com/pyqt5/package.yml +++ b/projects/riverbankcomputing.com/pyqt5/package.yml @@ -49,8 +49,6 @@ build: riverbankcomputing.com/pyqt-builder: '*' # pyqtbuild backend sip-install uses qt.io: ~5.15 # qmake + Qt5 headers/libs gnu.org/make: '*' - linux: - llvm.org: <17 # mirror the sip recipe's toolchain script: - bkpyvenv stage {{prefix}} {{version}} # Build + install PyQt5 from the extracted sdist against qt.io's Qt5. @@ -69,10 +67,6 @@ build: - bkpyvenv seal {{prefix}} pyuic5 pyrcc5 pylupdate5 env: MAKEFLAGS: -j1 # belt-and-suspenders OOM bound for the qmake-driven C++ build - linux: - CC: clang - CXX: clang++ - AS: llvm-as provides: [bin/pyuic5, bin/pyrcc5, bin/pylupdate5] test: dependencies: { python.org: ~3.11 } From 046129d28ace9b4a6980073415376828bec873cc Mon Sep 17 00:00:00 2001 From: tannevaled Date: Mon, 15 Jun 2026 20:26:51 +0200 Subject: [PATCH 18/19] pyqt5: add llvm.org build dep for mesa's libLLVM (linux) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sip-install's QtGui config test runs a Qt exe that loads mesa's libGL, which dlopens libLLVM.so (llvmpipe). mesa pulls llvm transitively but its lib dir isn't on the build library path, so the test crashed with 'libLLVM.so.22.1: cannot open shared object file'. Depend on llvm.org '*' directly (matching mesa3d.org — the earlier <17 pin gave the wrong soname). --- projects/riverbankcomputing.com/pyqt5/package.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/projects/riverbankcomputing.com/pyqt5/package.yml b/projects/riverbankcomputing.com/pyqt5/package.yml index a5ac7cc553..6e117f041d 100644 --- a/projects/riverbankcomputing.com/pyqt5/package.yml +++ b/projects/riverbankcomputing.com/pyqt5/package.yml @@ -49,6 +49,12 @@ build: riverbankcomputing.com/pyqt-builder: '*' # pyqtbuild backend sip-install uses qt.io: ~5.15 # qmake + Qt5 headers/libs gnu.org/make: '*' + linux: + # sip-install's QtGui config test runs a Qt exe that loads mesa's libGL, + # which dlopens libLLVM (llvmpipe). mesa pulls llvm transitively, but it + # isn't on the build's library path, so depend on it directly (same '*' + # mesa3d.org uses — pinning an older soname is what broke the test). + llvm.org: '*' script: - bkpyvenv stage {{prefix}} {{version}} # Build + install PyQt5 from the extracted sdist against qt.io's Qt5. From 0a3cb3583fd1333c33038b1fb874abb60e5bf1cb Mon Sep 17 00:00:00 2001 From: tannevaled Date: Mon, 15 Jun 2026 20:33:13 +0200 Subject: [PATCH 19/19] riverbankcomputing.com/pyqt5: keep the vendored wheel (from-source blocked) Attempted from-source via sip-install against qt.io's Qt5, but it fails in sip-install's own per-module config tests, which *execute* a Qt test exe in the headless sandbox: linux QtGui can't load mesa's libLLVM.so (llvmpipe via libGL), darwin can't resolve QtCore.framework via @rpath (DYLD stripping). Not fixable from the recipe env. Revert to the official wheel (Qt bundled), which builds 3/3, and document the blocker. --- .../riverbankcomputing.com/pyqt5/package.yml | 96 +++++++++++-------- 1 file changed, 54 insertions(+), 42 deletions(-) diff --git a/projects/riverbankcomputing.com/pyqt5/package.yml b/projects/riverbankcomputing.com/pyqt5/package.yml index 6e117f041d..ab8f0dd7bd 100644 --- a/projects/riverbankcomputing.com/pyqt5/package.yml +++ b/projects/riverbankcomputing.com/pyqt5/package.yml @@ -1,29 +1,53 @@ -# PyQt5 — built from the PyPI sdist with sip-install (the SIP build tool from -# riverbankcomputing.com/sip + the pyqtbuild backend from -# riverbankcomputing.com/pyqt-builder), linked against the Qt5 from qt.io. +# PyQt5 — Python bindings for Qt 5, installed from upstream's official +# PyPI wheel (which bundles the Qt5 libraries). Provides the +# pyuic5/pyrcc5/pylupdate5 tools and an importable `PyQt5`. # -# Notes: -# - Qt5 is NOT bundled (unlike the old PyPI wheel): the built bindings load -# qt.io's Qt5 libs at runtime, hence qt.io is a runtime dependency and we -# point sip-install at its qmake. -# - PyQt5's generated QtGui/QtWidgets C++ units are huge; unbounded parallel -# compilation OOM-killed CI, so we bound it with `--jobs 1` (+ MAKEFLAGS=-j1). -# - PyQt5 uses the separate PyQt5-sip runtime module (the private `PyQt5.sip`): -# sip-install does NOT build it, so we pip-install PyQt5-sip into the venv. +# Why vendored (wheel): building PyQt5 from the sip sources compiles +# enormous generated C++ per binding and OOM-killed CI; splitting into +# per-binding sub-recipes then hit a lockstep co-dependency (each +# binding 404'd resolving its sibling's not-yet-published bottle). The +# official wheel sidesteps both, in one package. +# +# Platform note: the macOS wheels are self-contained (Qt5 + the cocoa +# platform plugin are bundled and rpath-wired). The manylinux wheel is +# NOT self-contained — its QtGui/QtWidgets dlopen the host X11/xcb/mesa +# GUI stack, so on linux we pull that stack in as runtime deps below +# (x.org/*, mesa3d.org, xkbcommon.org, glib, fontconfig, freetype, dbus). +# Confirmed `from PyQt5 import QtWidgets` imports on a minimal linux +# sandbox with exactly those deps. +# +# Why not from-source: I tried building the bindings with sip-install +# against qt.io's Qt 5.15.10 (sip + pyqt-builder are now in the pantry). +# It fails before the compile even starts — sip-install *runs* a small Qt +# test exe per module, and executing a Qt program in the headless build +# sandbox breaks on loader paths: on linux the QtGui cfgtest can't load +# mesa's libLLVM.so (llvmpipe, dlopened via libGL); on darwin the cfgtest +# can't resolve qt.io's QtCore.framework via @rpath (DYLD path stripping). +# Both are sip-install-internal cfgtests, so they're not fixable from the +# recipe's own env. The official wheel (Qt bundled) sidesteps all of it. distributable: url: https://pypi.io/packages/source/P/PyQt5/PyQt5-{{ version.raw }}.tar.gz strip-components: 1 + versions: url: https://pypi.org/simple/pyqt5/ match: /PyQt5-\d+\.\d+\.\d+\.tar\.gz/ - strip: [/^PyQt5-/, /\.tar\.gz/] -platforms: [linux/x86-64, linux/aarch64, darwin/x86-64, darwin/aarch64] + strip: + - /^PyQt5-/ + - /\.tar\.gz/ + +platforms: + - linux/x86-64 + - darwin/x86-64 + - darwin/aarch64 + dependencies: pkgx.sh: ">=1" python.org: ~3.11 - qt.io: ~5.15 # Qt5 is no longer bundled; bindings load it at runtime - linux: # Qt5's xcb plugin GUI stack, needed at runtime + # The manylinux wheel's QtGui/QtWidgets dlopen the host GUI stack; + # the macOS wheels bundle it, so these are linux-only. + linux: gnome.org/glib: '*' freetype.org: '*' freedesktop.org/fontconfig: '*' @@ -39,43 +63,31 @@ dependencies: x.org/xi: '*' x.org/xau: '*' x.org/xdmcp: '*' + runtime: env: + # Expose `import PyQt5` to users/dependents from the sealed venv. PYTHONPATH: "${{prefix}}/venv/lib/python{{deps.python.org.version.marketing}}/site-packages" + build: dependencies: python.org: ~3.11 - riverbankcomputing.com/sip: '*' # provides sip-install/sip-build - riverbankcomputing.com/pyqt-builder: '*' # pyqtbuild backend sip-install uses - qt.io: ~5.15 # qmake + Qt5 headers/libs - gnu.org/make: '*' - linux: - # sip-install's QtGui config test runs a Qt exe that loads mesa's libGL, - # which dlopens libLLVM (llvmpipe). mesa pulls llvm transitively, but it - # isn't on the build's library path, so depend on it directly (same '*' - # mesa3d.org uses — pinning an older soname is what broke the test). - llvm.org: '*' script: + # Install the prebuilt wheels (Qt bundled) into a venv — pip and + # python there share a version, so PyQt5-sip's ABI matches python. + # `--only-binary` guarantees the wheel (never an sdist recompile). - bkpyvenv stage {{prefix}} {{version}} - # Build + install PyQt5 from the extracted sdist against qt.io's Qt5. - # --confirm-license: accept the GPL terms non-interactively (else CI hangs). - # --jobs 1 (+ MAKEFLAGS=-j1): bound the C++ compile to avoid OOM. - # --target-dir: land PyQt5/ in the venv site-packages so PYTHONPATH/test work. - - sip-install - --confirm-license - --qmake {{deps.qt.io.prefix}}/bin/qmake - --jobs 1 - --target-dir {{prefix}}/venv/lib/python{{deps.python.org.version.marketing}}/site-packages - --verbose - # PyQt5 needs the separate PyQt5-sip runtime module (private PyQt5.sip); - # sip-install does not build it, so install it into the venv. - - '{{prefix}}/venv/bin/pip install PyQt5-sip' + - '${{prefix}}/venv/bin/pip install --only-binary=:all: PyQt5=={{version}} PyQt5-sip' - bkpyvenv seal {{prefix}} pyuic5 pyrcc5 pylupdate5 - env: - MAKEFLAGS: -j1 # belt-and-suspenders OOM bound for the qmake-driven C++ build -provides: [bin/pyuic5, bin/pyrcc5, bin/pylupdate5] + +provides: + - bin/pyuic5 + - bin/pyrcc5 + - bin/pylupdate5 + test: - dependencies: { python.org: ~3.11 } + dependencies: + python.org: ~3.11 script: - pyuic5 --version 2>&1 | grep {{version}} - python{{deps.python.org.version.marketing}} -c "from PyQt5 import QtCore, QtWidgets; print(QtCore.QT_VERSION_STR)"