1717import shutil
1818import stat
1919import subprocess
20+ import winreg
2021
2122from distutils .errors import DistutilsExecError , DistutilsPlatformError , \
2223 CompileError , LibError , LinkError
2324from distutils .ccompiler import CCompiler , gen_lib_options
2425from distutils import log
2526from distutils .util import get_platform
2627
27- import winreg
2828from itertools import count
2929
30- def _find_vcvarsall ( plat_spec ):
30+ def _find_vc2015 ( ):
3131 try :
3232 key = winreg .OpenKeyEx (
3333 winreg .HKEY_LOCAL_MACHINE ,
@@ -38,9 +38,9 @@ def _find_vcvarsall(plat_spec):
3838 log .debug ("Visual C++ is not registered" )
3939 return None , None
4040
41+ best_version = 0
42+ best_dir = None
4143 with key :
42- best_version = 0
43- best_dir = None
4444 for i in count ():
4545 try :
4646 v , vc_dir , vt = winreg .EnumValue (key , i )
@@ -53,25 +53,74 @@ def _find_vcvarsall(plat_spec):
5353 continue
5454 if version >= 14 and version > best_version :
5555 best_version , best_dir = version , vc_dir
56- if not best_version :
57- log .debug ("No suitable Visual C++ version found" )
58- return None , None
56+ return best_version , best_dir
57+
58+ def _find_vc2017 ():
59+ import _findvs
60+ import threading
61+
62+ best_version = 0 , # tuple for full version comparisons
63+ best_dir = None
64+
65+ # We need to call findall() on its own thread because it will
66+ # initialize COM.
67+ all_packages = []
68+ def _getall ():
69+ all_packages .extend (_findvs .findall ())
70+ t = threading .Thread (target = _getall )
71+ t .start ()
72+ t .join ()
73+
74+ for name , version_str , path , packages in all_packages :
75+ if 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64' in packages :
76+ vc_dir = os .path .join (path , 'VC' , 'Auxiliary' , 'Build' )
77+ if not os .path .isdir (vc_dir ):
78+ continue
79+ try :
80+ version = tuple (int (i ) for i in version_str .split ('.' ))
81+ except (ValueError , TypeError ):
82+ continue
83+ if version > best_version :
84+ best_version , best_dir = version , vc_dir
85+ try :
86+ best_version = best_version [0 ]
87+ except IndexError :
88+ best_version = None
89+ return best_version , best_dir
5990
60- vcvarsall = os .path .join (best_dir , "vcvarsall.bat" )
61- if not os .path .isfile (vcvarsall ):
62- log .debug ("%s cannot be found" , vcvarsall )
63- return None , None
91+ def _find_vcvarsall (plat_spec ):
92+ best_version , best_dir = _find_vc2017 ()
93+ vcruntime = None
94+ vcruntime_plat = 'x64' if 'amd64' in plat_spec else 'x86'
95+ if best_version :
96+ vcredist = os .path .join (best_dir , ".." , ".." , "redist" , "MSVC" , "**" ,
97+ "Microsoft.VC141.CRT" , "vcruntime140.dll" )
98+ try :
99+ import glob
100+ vcruntime = glob .glob (vcredist , recursive = True )[- 1 ]
101+ except (ImportError , OSError , LookupError ):
102+ vcruntime = None
103+
104+ if not best_version :
105+ best_version , best_dir = _find_vc2015 ()
106+ if best_version :
107+ vcruntime = os .path .join (best_dir , 'redist' , vcruntime_plat ,
108+ "Microsoft.VC140.CRT" , "vcruntime140.dll" )
109+
110+ if not best_version :
111+ log .debug ("No suitable Visual C++ version found" )
112+ return None , None
64113
114+ vcvarsall = os .path .join (best_dir , "vcvarsall.bat" )
115+ if not os .path .isfile (vcvarsall ):
116+ log .debug ("%s cannot be found" , vcvarsall )
117+ return None , None
118+
119+ if not vcruntime or not os .path .isfile (vcruntime ):
120+ log .debug ("%s cannot be found" , vcruntime )
65121 vcruntime = None
66- vcruntime_spec = _VCVARS_PLAT_TO_VCRUNTIME_REDIST .get (plat_spec )
67- if vcruntime_spec :
68- vcruntime = os .path .join (best_dir ,
69- vcruntime_spec .format (best_version ))
70- if not os .path .isfile (vcruntime ):
71- log .debug ("%s cannot be found" , vcruntime )
72- vcruntime = None
73122
74- return vcvarsall , vcruntime
123+ return vcvarsall , vcruntime
75124
76125def _get_vc_env (plat_spec ):
77126 if os .getenv ("DISTUTILS_USE_SDK" ):
@@ -130,14 +179,6 @@ def _find_exe(exe, paths=None):
130179 'win-amd64' : 'x86_amd64' ,
131180}
132181
133- # A map keyed by get_platform() return values to the file under
134- # the VC install directory containing the vcruntime redistributable.
135- _VCVARS_PLAT_TO_VCRUNTIME_REDIST = {
136- 'x86' : 'redist\\ x86\\ Microsoft.VC{0}0.CRT\\ vcruntime{0}0.dll' ,
137- 'amd64' : 'redist\\ x64\\ Microsoft.VC{0}0.CRT\\ vcruntime{0}0.dll' ,
138- 'x86_amd64' : 'redist\\ x64\\ Microsoft.VC{0}0.CRT\\ vcruntime{0}0.dll' ,
139- }
140-
141182# A set containing the DLLs that are guaranteed to be available for
142183# all micro versions of this Python version. Known extension
143184# dependencies that are not in this set will be copied to the output
0 commit comments