51
51
import importlib
52
52
import os
53
53
import re
54
+ import shlex
54
55
import shutil
55
56
import subprocess
56
57
import sys
@@ -107,6 +108,7 @@ def build_wheels(pip):
107
108
packages_to_build = set ()
108
109
with open (join (dirname (__file__ ), "packages.txt" )) as f :
109
110
for line in f .readlines ():
111
+ line = line .strip ()
110
112
name , version = line .split ("==" )
111
113
if not packages_selected or name in packages_selected or line in packages_selected :
112
114
packages_to_build .add (line )
@@ -131,7 +133,11 @@ def build_wheels(pip):
131
133
env ["PATH" ] = abspath (dirname (pip )) + os .pathsep + env ["PATH" ]
132
134
env ["VIRTUAL_ENV" ] = abspath (dirname (dirname (pip )))
133
135
print ("Building" , name , version , "with" , script , flush = True )
134
- subprocess .check_call ([script , version ], shell = True , env = env )
136
+ if sys .platform == "win32" :
137
+ cmd = [script , version ] # Python's subprocess.py does the quoting we need
138
+ else :
139
+ cmd = f"{ shlex .quote (script )} { version } "
140
+ subprocess .check_call (cmd , shell = True , env = env )
135
141
if not len (glob ("*.whl" )) > whl_count :
136
142
print ("Building wheel for" , name , version , "after" , script , "did not" , flush = True )
137
143
subprocess .check_call ([pip , "wheel" , spec ])
@@ -140,152 +146,26 @@ def build_wheels(pip):
140
146
subprocess .check_call ([pip , "wheel" , spec ])
141
147
142
148
143
- _warned_dlls = []
144
-
145
-
146
- def repair_wheels_windows (output_dir , wheels ):
147
- import pefile
148
- from machomachomangler .pe import redll
149
-
150
- def resolve_dll_src (dll ):
151
- # search for dependencies in system directories
152
- dll_search_paths = [
153
- os .environ ["WINDIR" ],
154
- join (os .environ ["WINDIR" ], "System32" ),
155
- * os .environ ["PATH" ].split (";" ),
156
- ]
157
- ignored_dlls = [
158
- # These DLLs are just provided by Windows.
159
- # This list is probably incomplete.
160
- r"advapi32\.dll" ,
161
- r"advapires32\.dll" ,
162
- r"atl.*\.dll" ,
163
- r"comctl32\.dll" ,
164
- r"comdlg32\.dll" ,
165
- r"crtdll\.dll" ,
166
- r"gdi32\.dll" ,
167
- r"hal.*\.dll" ,
168
- r"imm32\.dll" ,
169
- r"iphlpapi\.dll" ,
170
- r"kernel32\.dll" ,
171
- r"kernelbase\.dll" ,
172
- r"msvbvm60\.dll" ,
173
- r"msvcirt\.dll" ,
174
- r"msvcrt?.*\.dll" ,
175
- r"netapi32\.dll" ,
176
- r"ntdll\.dll" ,
177
- r"ole32\.dll" ,
178
- r"pdh\.dll" ,
179
- r"powrprof\.dll" ,
180
- r"psapi\.dll" ,
181
- r"rpcrt4\.dll" ,
182
- r"sechost\.dll" ,
183
- r"shell32\.dll" ,
184
- r"shlwapi\.dll" ,
185
- r"shscrap\.dll" ,
186
- r"ucrtbase\.dll" ,
187
- r"user32\.dll" ,
188
- r"version\.dll" ,
189
- r"winmm\.dll" ,
190
- r"ws2_32\.dll" ,
191
- # These match DLLs that provide API sets.
192
- # See https://learn.microsoft.com/en-us/windows/win32/apiindex/windows-apisets
193
- r"api-ms-win-.*\.dll" ,
194
- r"ext-ms-win-.*\.dll" ,
195
- # These match DLLs that we provide in GraalPy
196
- r"python.*\.dll" ,
197
- # These are the DLLs typically linked when building with MSVC. See
198
- # https://learn.microsoft.com/en-us/cpp/windows/determining-which-dlls-to-redistribute
199
- # When these are included, the user should install the latest
200
- # redist package from
201
- # https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist
202
- # However, https://aka.ms/vs/17/redist.txt lists the libraries
203
- # which can be included in application distributions.
204
- r"concrt.*\.dll" ,
205
- r"mfc.*\.dll" ,
206
- r"msvcp.*\.dll" ,
207
- r"vcamp.*\.dll" ,
208
- r"vccorlib.*\.dll" ,
209
- r"vcomp.*\.dll" ,
210
- r"vcruntime.*\.dll" ,
211
- ]
212
- if not dll :
213
- return
214
- if any (re .match (pat , basename (dll ), re .IGNORECASE ) for pat in ignored_dlls ):
215
- if dll not in _warned_dlls :
216
- print ("Not including" , dll , flush = True )
217
- _warned_dlls .append (dll )
218
- return
219
- if isabs (dll ):
220
- return dll
221
- for search_path in dll_search_paths :
222
- if exists (src := join (search_path , dll )):
223
- return src
224
-
225
- def resolve_dll_target (dll , dependent , checksum ):
226
- return join (dirname (dependent ), f"{ checksum } .{ basename (dll )} " )
227
-
228
- def filehash (files ):
229
- sha1 = hashlib .sha1 ()
230
- for file in files :
231
- with open (file , mode = "rb" ) as f :
232
- sha1 .update (f .read ())
233
- return sha1 .hexdigest ()[:8 ]
234
-
235
- for whl in wheels :
236
- with TemporaryDirectory () as name :
237
- with zipfile .ZipFile (whl ) as f :
238
- f .extractall (name )
239
-
240
- # find all pyd files and recursively copy dependencies
241
- dlls = glob (f"{ name } /**/*.pyd" , recursive = True )
242
- checksum = filehash (dlls )
243
- dependents_to_dependencies = {}
244
- while dlls :
245
- dll = dlls .pop ()
246
- with pefile .PE (dll ) as pe :
247
- pe_info = pe .dump_dict ()
248
- for syms in pe_info .get ("Imported symbols" , []):
249
- for sym in syms :
250
- if dep_src := resolve_dll_src (sym .get ("DLL" , b"" ).decode ("utf-8" )):
251
- if not exists (dep_tgt := resolve_dll_target (dep_src , dll , checksum )):
252
- print ("Including" , dep_src , "as" , dep_tgt , flush = True )
253
- shutil .copy (dep_src , dep_tgt )
254
- dlls .append (dep_tgt )
255
- dependents_to_dependencies .setdefault (dll , []).append (dep_src )
256
-
257
- for dll , dependencies in dependents_to_dependencies .items ():
258
- mapping = {}
259
- for dep_src in dependencies :
260
- mapping [basename (dep_src ).encode ("utf-8" )] = basename (
261
- resolve_dll_target (dep_src , dll , checksum )
262
- ).encode ("utf-8" )
263
- with open (dll , mode = "rb" ) as f :
264
- data = f .read ()
265
- print (
266
- "Rewriting\n \t " ,
267
- "\n \t " .join ([k .decode ("utf-8" ) for k in mapping .keys ()]),
268
- "\n \t ->\n \t " ,
269
- "\n \t " .join ([v .decode ("utf-8" ) for v in mapping .values ()]),
270
- "\n in" ,
271
- dll ,
272
- )
273
- data = redll (data , mapping )
274
- with open (dll , mode = "wb" ) as f :
275
- f .write (data )
276
-
277
- os .makedirs (output_dir , exist_ok = True )
278
- if exists (whl_tgt := join (output_dir , whl )):
279
- os .unlink (whl_tgt )
280
- shutil .make_archive (whl_tgt , "zip" , name )
281
- os .rename (f"{ whl_tgt } .zip" , whl_tgt )
282
-
283
-
284
149
def repair_wheels ():
285
150
if sys .platform == "win32" :
286
- ensure_installed ("machomachomangler" )
287
- ensure_installed ("pefile" )
288
- repair_wheels_windows ("wheelhouse" , glob ("*.whl" ))
151
+ ensure_installed ("delvewheel" )
152
+ env = os .environ .copy ()
153
+ env ["PYTHONUTF8" ] = "1"
154
+ subprocess .check_call (
155
+ [
156
+ sys .executable ,
157
+ "-m" ,
158
+ "delvewheel" ,
159
+ "repair" ,
160
+ "-v" ,
161
+ "--exclude" ,
162
+ "python-native.dll" ,
163
+ "-w" ,
164
+ "wheelhouse" ,
165
+ * glob ("*.whl" ),
166
+ ],
167
+ env = env ,
168
+ )
289
169
elif sys .platform == "linux" :
290
170
ensure_installed ("auditwheel" )
291
171
subprocess .check_call (
0 commit comments