5151import importlib
5252import os
5353import re
54+ import shlex
5455import shutil
5556import subprocess
5657import sys
@@ -107,6 +108,7 @@ def build_wheels(pip):
107108 packages_to_build = set ()
108109 with open (join (dirname (__file__ ), "packages.txt" )) as f :
109110 for line in f .readlines ():
111+ line = line .strip ()
110112 name , version = line .split ("==" )
111113 if not packages_selected or name in packages_selected or line in packages_selected :
112114 packages_to_build .add (line )
@@ -131,7 +133,11 @@ def build_wheels(pip):
131133 env ["PATH" ] = abspath (dirname (pip )) + os .pathsep + env ["PATH" ]
132134 env ["VIRTUAL_ENV" ] = abspath (dirname (dirname (pip )))
133135 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 )
135141 if not len (glob ("*.whl" )) > whl_count :
136142 print ("Building wheel for" , name , version , "after" , script , "did not" , flush = True )
137143 subprocess .check_call ([pip , "wheel" , spec ])
@@ -140,152 +146,26 @@ def build_wheels(pip):
140146 subprocess .check_call ([pip , "wheel" , spec ])
141147
142148
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-
284149def repair_wheels ():
285150 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+ )
289169 elif sys .platform == "linux" :
290170 ensure_installed ("auditwheel" )
291171 subprocess .check_call (
0 commit comments