forked from HaujetZhao/PyInstaller-Perfect-Build-Method
-
Notifications
You must be signed in to change notification settings - Fork 0
/
build-hello-goodbye.spec
221 lines (180 loc) · 7.77 KB
/
build-hello-goodbye.spec
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
# ===========================添加要额外复制的文件和文件夹==================================
from importlib.util import find_spec # 用于查找模块所在路径
from os.path import dirname
from os import path
from pprint import pprint
import os, re
# 空列表,用于准备要复制的数据
datas = []
# 这是要额外复制的模块
manual_modules = []
for m in manual_modules:
if not find_spec(m): continue
p1 = dirname(find_spec(m).origin)
p2 = m
datas.append((p1, p2))
# 这是要额外复制的文件夹
my_folders = ['assets']
for f in my_folders:
datas.append((f, f))
# 这是要额外复制的文件
my_files = ['hello_main.py', 'readme.md']
for f in my_files:
datas.append((f, '.')) # 复制到打包导出的根目录
# ==================新建两个 a 变量,分析两个脚本============================
a = Analysis(
['hello.py'], # 分析 hello.py
pathex=[],
binaries=[],
datas=datas, # 把我们准备好的 datas 列表传入
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=['hook.py'], # 一定要传入 hook.py 用于修改模块查找路径
excludes=['IPython'], # 有时 pyinstaller 会抽风,加入一些不需要的包,在这里排除掉
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
a2 = Analysis(
['goodbye.py'], # 分析 goodbye.py
pathex=[],
binaries=[],
datas=[], # 要传入的额外文件由第一个 a 处理就行了,这里留空
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=['hook.py'], # 一定要传入 hook.py 用于修改模块查找路径
excludes=['IPython'], # 有时 pyinstaller 会抽风,加入一些不需要的包,在这里排除掉
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
#===================分析完成后,重定向 a 的二进制、py文件到 libs 文件夹================================
# 把 a.datas 中不属于自定义的文件重定向到 libs 文件夹
temp = a.datas.copy(); a.datas.clear()
for dst, src, type in temp:
c1 = (dst == 'base_library.zip') # 判断文件是否为 base_library.zip
c2 = any([dst.startswith(f) for f in my_folders]) # 判断文件是否属于 my_folders
c3 = any([dst.startswith(f) for f in my_files]) # 判断文件是否属于 my_files
if any([c1, c2, c3]):
a.datas.append((dst, src, type))
else:
a.datas.append((path.join('libs', dst), src, type))
# 把 a.binaries 中的二进制文件放到 a.datas ,作为普通文件复制到 libs 目录
for dst, src, type in a.binaries:
c1 = (dst=='Python') # 不修改 Pyhton
c2 = re.fullmatch(r'python\d+\.dll', dst) # 不修改 python310.dll
if any([c1, c2]):
a.datas.append((dst, src, 'DATA'))
else:
a.datas.append((path.join('libs', dst), src, 'DATA'))
a.binaries.clear()
# 把所有的 py 文件依赖用 a.datas 复制到 libs 文件夹
# 可选地保留某些要打包的依赖
private_module = [] # hello.exe 不保留任何依赖
temp = a.pure.copy(); a.pure.clear()
for name, src, type in temp:
condition = [name.startswith(m) for m in private_module]
if condition and any(condition):
a.pure.append((name, src, type)) # 把需要保留打包的 py 文件重新添加回 a.pure
else:
name = name.replace('.', os.sep)
init = path.join(name, '__init__.py')
pos = src.find(init) if init in src else src.find(name)
dst = src[pos:]
dst = path.join('libs', dst)
a.datas.append((dst, src, 'DATA')) # 不需要打包的第三方依赖 py 文件引到 libs 文件夹
#============================重定向 a2 的二进制、py文件================================
# 把 a2.datas 中不属于自定义的文件重定向到 libs 文件夹
temp = a2.datas.copy(); a2.datas.clear()
for dst, src, type in temp:
c1 = (dst == 'base_library.zip') # 判断文件是否为 base_library.zip
c2 = any([dst.startswith(f) for f in my_folders]) # 判断文件是否属于 my_folders
c3 = any([dst.startswith(f) for f in my_files]) # 判断文件是否属于 my_files
if any([c1, c2, c3]):
a2.datas.append((dst, src, type))
else:
a2.datas.append((path.join('libs', dst), src, type))
# 把 a2.binaries 中的二进制文件放到 a2.datas ,作为普通文件复制到 libs 目录
for dst, src, type in a2.binaries:
c1 = (dst=='Python') # 不修改 Pyhton
c2 = re.fullmatch(r'python\d+\.dll', dst) # 不修改 python310.dll
if any([c1, c2]):
a2.datas.append((dst, src, 'DATA'))
else:
a2.datas.append((path.join('libs', dst), src, 'DATA'))
a2.binaries.clear()
# 把所有的 py 文件依赖用 a2.datas 复制到 libs 文件夹
# 可选地保留某些要打包的依赖
private_module = ['goodbye_main'] # 作为示例,hello.exe 把 goodbye_main.py 保留打包
temp = a2.pure.copy(); a2.pure.clear()
for name, src, type in temp:
condition = [name.startswith(m) for m in private_module]
if condition and any(condition):
a2.pure.append((name, src, type)) # 把需要保留打包的 py 文件重新添加回 a.pure
else:
name = name.replace('.', os.sep)
init = path.join(name, '__init__.py')
pos = src.find(init) if init in src else src.find(name)
dst = src[pos:]
dst = path.join('libs', dst)
a2.datas.append((dst, src, 'DATA')) # 不需要打包的第三方依赖 py 文件引到 libs 文件夹
# ========================为 a 和 a2 生成 exe =========================
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
pyz2 = PYZ(a2.pure, a2.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts, # 运行 hello 的 scripts
[],
exclude_binaries=True,
name='hello', # 程序的创口贴名字叫 hello
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=True, # 运行时弹出终端窗口
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon=[], # 这里可以给 exe 加图标,如果你有图标文件的话
)
exe2 = EXE(
pyz2,
a2.scripts, # 运行 goodbye 的 scripts
[],
exclude_binaries=True,
name='goodbye', # 程序的窗口名字叫 goodbye
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=True, # 运行时弹出终端窗口
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon=[], # 这里可以给 exe 加图标,如果你有图标文件的话
)
# =============用 coll 把两个 exe 和其所属的文件收集到目标文件夹=========================
coll = COLLECT(
exe, # hello.exe
exe2, # goodbye.exe
a.binaries, # hello.exe 的二进制文件(实际上已被清空了)
a2.binaries, # goodbye.exe 的二进制文件(实际上已被清空了)
a.zipfiles,
a2.zipfiles,
a.datas, # hello.exe 的依赖文件和自定义复制文件,都被我们导到了这里
a2.datas, # goodbye.exe 的依赖文件,都被我们导到了这里
strip=False,
upx=True,
upx_exclude=[],
name='hello-and-goodbye', # 输出路径在 dist 文件夹里的 hello-and-goodbye 文件夹
)