summaryrefslogtreecommitdiff
path: root/azrechner-trimmed.spec
blob: d42a1b1a32fd60e11824e0073577b9412cf91862 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# 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',
)