# calendar_gui.spec # -*- mode: python ; coding: utf-8 -*- import os import sys from pathlib import Path from PyInstaller.utils.hooks import collect_all # Collect reportlab barcode data (same as before) datas = [] binaries = [] hiddenimports = [] tmp_ret = collect_all('reportlab.graphics.barcode') datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2] # ---- Analysis ---- a = Analysis( ['calendar_gui.py'], pathex=[os.getcwd()], binaries=binaries, datas=datas, hiddenimports=hiddenimports, hookspath=[], hooksconfig={}, runtime_hooks=[], excludes=['scipy','numpy'], # keep your existing excludes noarchive=False, optimize=0, ) # Platform-aware essential names & drop patterns IS_WINDOWS = sys.platform.startswith('win') IS_MAC = sys.platform == 'darwin' IS_UNIX = not IS_WINDOWS and not IS_MAC # Lowercase names will be used for case-insensitive matching if IS_WINDOWS: ESSENTIAL_QT_NAMES = [ 'qt5core.dll', 'qt5gui.dll', 'qt5widgets.dll', # the platform plugin folder & plugin name on Windows os.path.join('platforms', 'qwindows.dll'), # Python runtime dlls that are critical f'python{sys.version_info.major}{sys.version_info.minor}.dll', # e.g. python312.dll ] DROP_PATTERNS = [ # Qt optional DLLs you listed (Windows names) 'Qt5Quick.dll', 'qt5qml.dll', 'qt5qmlmodels.dll', 'qt5svg.dll', 'qt5websockets.dll', 'qt5eglfsdeviceintegration.dll', # Pillow / image codec dll patterns (windows) 'libavif', 'libwebp', 'lcms2', 'sharpyuv', 'openjp2', 'webpdemux', 'webpmux', # qml/translations directories ] STRIP_ON_BUILD = False else: # Linux / other UNIX ESSENTIAL_QT_NAMES = [ 'libQt5Core.so', 'libQt5Gui.so', 'libQt5Widgets.so', 'libQt5XcbQpa.so', 'libpython{major}.{minor}.so'.format(major=sys.version_info.major, minor=sys.version_info.minor), 'libstdc++.so.6', 'libc.so.6' ] DROP_PATTERNS = [ # Pillow image codecs & windows variants too 'libavif-', 'libwebp-', 'liblcms2-', 'libsharpyuv', 'libopenjp2', # Qt optional subsystems you listed 'libQt5Quick.so', 'libQt5Qml.so', 'libQt5QmlModels.so', 'libQt5Svg.so', 'libQt5WebSockets.so', 'libQt5EglFSDeviceIntegration.so', ] STRIP_ON_BUILD = True # Normalize patterns to lowercase for case-insensitive comparisons ESSENTIAL_QT_NAMES = [p.lower() for p in ESSENTIAL_QT_NAMES] DROP_PATTERNS = [p.lower() for p in DROP_PATTERNS] def should_drop_path(path_obj): """ Return True when the path (string or Path) should be dropped from binaries/datas. Uses case-insensitive substring matching and avoids dropping essential runtime libs. """ s = str(path_obj) s_lower = s.lower().replace('\\', '/') # never drop critical essentials (match if any essential substring is contained) for ess in ESSENTIAL_QT_NAMES: if ess in s_lower: return False # drop if pattern matches for p in DROP_PATTERNS: if p in s_lower: return True # drop QML/translations directories if present if '/qml/' in s_lower or '/translations/' in s_lower: return True # Also drop "pillow.libs" link targets if they match the patterns above if 'pillow.libs' in s_lower and any(p in s_lower for p in DROP_PATTERNS): return True return False # ---------- robust filtering for a.binaries / a.datas ---------- def _entry_src(obj): """ Return the 'source' part of a TOC entry for binaries/datas. PyInstaller entries may be (src, dest) or (src, dest, type) etc. """ try: return obj[0] except Exception: return obj filtered_binaries = [] for entry in a.binaries: src = _entry_src(entry) if should_drop_path(src): # drop this binary entry # print("Dropping binary:", src) continue filtered_binaries.append(entry) a.binaries = filtered_binaries filtered_datas = [] for entry in a.datas: src = _entry_src(entry) if should_drop_path(src): # print("Dropping data:", src) continue filtered_datas.append(entry) a.datas = filtered_datas # ---------------------------------------------------------------- # ---- Build steps: PYZ, EXE, COLLECT ---- pyz = PYZ(a.pure, a.zipped_data, cipher=None) exe = EXE( pyz, a.scripts, [], exclude_binaries=True, name='azrechner', debug=False, bootloader_ignore_signals=False, strip=STRIP_ON_BUILD, # only strip on unix-like systems upx=True, console=False, ) coll = COLLECT( exe, a.binaries, a.zipfiles, a.datas, strip=STRIP_ON_BUILD, # only strip on unix-like systems upx=True, # if you know specific DLLs that break with UPX you can list them here upx_exclude=[], name='azrechner-trimmed', )