diff options
| author | SulfurNitride <SulfurNitride@users.noreply.github.com> | 2026-05-15 17:13:41 -0500 |
|---|---|---|
| committer | SulfurNitride <lukew19@proton.me> | 2026-05-16 12:57:25 -0500 |
| commit | fe424eef00692482b859c9b23e86b8fb814754fd (patch) | |
| tree | 35e7330e6fee6120baf8475226377fcefaddfea4 | |
| parent | f782b0ca53b2353011ebc517302f1509690040ee (diff) | |
package: prune unused PyQt6 modules and dedupe lib/
Shrinks the staging tree by ~27 MB (~250M -> ~223M) via two changes in
docker/build-inner.sh:
1. PyQt6 prune. Allowlist QtCore/QtGui/QtWidgets/QtOpenGL/QtOpenGLWidgets
(confirmed by full-repo grep of all shipped Python plugins). Drop the
remaining ~30 .abi3.so bindings plus bindings/, uic/, lupdate/, every
.pyi stub, every __pycache__. Pruning runs BEFORE the existing
ldd-scan loop, so libQt6Designer/Help/Sql/Test/SvgWidgets/Bluetooth/...
stop getting pulled into lib/ as a side effect.
plugins/libs/PyQt6: 31M -> 14M.
2. Dedupe lib/. cp -Lf on globs like libboost_program_options.so* stages
the unversioned soname and the versioned SO as identical real files.
Adds a post-bundling pass that, for each *.so / *.so.N file, finds a
byte-identical versioned twin via cmp -s and replaces it with a
symlink. Skips existing symlinks. Fixes the boost_program_options,
boost_thread, and xcb-cursor duplicates that have been here from the
start.
Also removes the now-orphan fluorine_vfs.dll / fluorine_vfs_hid.dll /
libfluorine_vfs_preload.so staging block left behind after the VFS shim
removal in 2ed0704f.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
| -rwxr-xr-x | docker/build-inner.sh | 92 |
1 files changed, 80 insertions, 12 deletions
diff --git a/docker/build-inner.sh b/docker/build-inner.sh index 865e0b4..888894a 100755 --- a/docker/build-inner.sh +++ b/docker/build-inner.sh @@ -149,18 +149,6 @@ cp -f build/libs/uibase/src/libuibase.so "${OUT_DIR}/lib/" cp -f build/libs/libbsarch/liblibbsarch.so "${OUT_DIR}/lib/" cp -f build/libs/archive/src/libarchive.so "${OUT_DIR}/lib/" cp -f build/libs/plugin_python/src/runner/librunner.so "${OUT_DIR}/lib/" -[ -f build/src/src/libfluorine_vfs_preload.so ] && \ - cp -f build/src/src/libfluorine_vfs_preload.so "${OUT_DIR}/lib/" -# PE-side VFS injector: cross-built with mingw, copied into wine/ where -# Fluorine picks it up at prefix init and stages into c:\\windows\\system32\\. -if [ -f build/src/src/fluorine_vfs.dll ]; then - mkdir -p "${OUT_DIR}/wine" - cp -f build/src/src/fluorine_vfs.dll "${OUT_DIR}/wine/" -fi -if [ -f build/src/src/fluorine_vfs_hid.dll ]; then - mkdir -p "${OUT_DIR}/wine" - cp -f build/src/src/fluorine_vfs_hid.dll "${OUT_DIR}/wine/" -fi if [ -f "libs/bsa_ffi/target/release/libbsa_ffi.so" ]; then cp -f libs/bsa_ffi/target/release/libbsa_ffi.so "${OUT_DIR}/lib/" fi @@ -323,6 +311,37 @@ mkdir -p "${PYQT6_OUT}" cp -a "${PYQT6_SRC}/." "${PYQT6_OUT}/" # Remove PyQt6's bundled Qt — we already have Qt in lib/ rm -rf "${PYQT6_OUT}/Qt6" + +# Prune unused PyQt6 modules. Full-repo grep of libs/ + src/ confirms shipped +# Python plugins only import the five modules below. Pruning happens BEFORE +# the deps-scan loop further down so libQt6Designer/Help/Sql/Test/SvgWidgets/ +# Bluetooth/... stop getting copied into lib/ as a side effect. +PYQT6_KEEP_MODULES="QtCore QtGui QtWidgets QtOpenGL QtOpenGLWidgets" +rm -rf "${PYQT6_OUT}/bindings" "${PYQT6_OUT}/uic" "${PYQT6_OUT}/lupdate" +find "${PYQT6_OUT}" -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true +find "${PYQT6_OUT}" -type f -name '*.pyi' -delete 2>/dev/null || true +for entry in "${PYQT6_OUT}"/*; do + [ -e "${entry}" ] || continue + base="$(basename "${entry}")" + case "${base}" in + __init__.py|py.typed) continue ;; + sip.cpython-*.so) continue ;; + Qt6) continue ;; # already removed; defensive + *.abi3.so) + mod="${base%.abi3.so}" + keep=0 + for k in ${PYQT6_KEEP_MODULES}; do + [ "${mod}" = "${k}" ] && keep=1 && break + done + [ ${keep} -eq 0 ] && rm -f "${entry}" + ;; + *) + rm -rf "${entry}" + ;; + esac +done +echo "PyQt6 pruned to: ${PYQT6_KEEP_MODULES}" + # Patchelf all PyQt6 binding .so files to reach our lib/ via RPATH # Path: plugins/libs/PyQt6/*.so → ../../.. = staging root → lib/ find "${PYQT6_OUT}" -name "*.so" -exec \ @@ -346,6 +365,55 @@ find "${PYQT6_OUT}" -name "*.so" | while read -r pyqt_so; do done done +# ── Dedupe identical files in lib/ via symlinks ── +# Source-side `cp -Lf` resolves symlinks, so unversioned (foo.so) and versioned +# (foo.so.X.Y.Z) get staged as identical real files. Replace the unversioned +# (or shorter-versioned) twin with a symlink to the longest real file. +# MUST run after both the main dep-collection loop and the PyQt6 ldd scan +# above; do not reorder. +echo "Deduping lib/ via symlinks..." +( + cd "${OUT_DIR}/lib" || exit 0 + # Pass A: foo.so → foo.so.X[.Y[.Z]] + for f in *.so; do + [ -L "${f}" ] && continue + [ -f "${f}" ] || continue + target="" + for v in $(ls -1 "${f}".* 2>/dev/null | sort -r); do + [ -L "${v}" ] && continue + [ -f "${v}" ] || continue + if cmp -s "${f}" "${v}"; then + target="${v}" + break + fi + done + if [ -n "${target}" ]; then + rm -f "${f}" + ln -s "${target}" "${f}" + echo " link ${f} -> ${target}" + fi + done + # Pass B: foo.so.N → foo.so.N.M[.P] (handles e.g. libxcb-cursor.so.0 → .so.0.0.0) + for f in *.so.[0-9]*; do + [ -L "${f}" ] && continue + [ -f "${f}" ] || continue + target="" + for v in $(ls -1 "${f}".* 2>/dev/null | sort -r); do + [ -L "${v}" ] && continue + [ -f "${v}" ] || continue + if cmp -s "${f}" "${v}"; then + target="${v}" + break + fi + done + if [ -n "${target}" ]; then + rm -f "${f}" + ln -s "${target}" "${f}" + echo " link ${f} -> ${target}" + fi + done +) + # ── Strip all MO2 binaries ── echo "Stripping MO2 binaries..." strip --strip-unneeded "${OUT_DIR}/ModOrganizer-core" 2>/dev/null || true |
