17
17
import shutil
18
18
import stat
19
19
import subprocess
20
+ import winreg
20
21
21
22
from distutils .errors import DistutilsExecError , DistutilsPlatformError , \
22
23
CompileError , LibError , LinkError
23
24
from distutils .ccompiler import CCompiler , gen_lib_options
24
25
from distutils import log
25
26
from distutils .util import get_platform
26
27
27
- import winreg
28
28
from itertools import count
29
29
30
- def _find_vcvarsall ( plat_spec ):
30
+ def _find_vc2015 ( ):
31
31
try :
32
32
key = winreg .OpenKeyEx (
33
33
winreg .HKEY_LOCAL_MACHINE ,
@@ -38,9 +38,9 @@ def _find_vcvarsall(plat_spec):
38
38
log .debug ("Visual C++ is not registered" )
39
39
return None , None
40
40
41
+ best_version = 0
42
+ best_dir = None
41
43
with key :
42
- best_version = 0
43
- best_dir = None
44
44
for i in count ():
45
45
try :
46
46
v , vc_dir , vt = winreg .EnumValue (key , i )
@@ -53,25 +53,74 @@ def _find_vcvarsall(plat_spec):
53
53
continue
54
54
if version >= 14 and version > best_version :
55
55
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
59
90
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
64
113
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 )
65
121
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
73
122
74
- return vcvarsall , vcruntime
123
+ return vcvarsall , vcruntime
75
124
76
125
def _get_vc_env (plat_spec ):
77
126
if os .getenv ("DISTUTILS_USE_SDK" ):
@@ -130,14 +179,6 @@ def _find_exe(exe, paths=None):
130
179
'win-amd64' : 'x86_amd64' ,
131
180
}
132
181
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
-
141
182
# A set containing the DLLs that are guaranteed to be available for
142
183
# all micro versions of this Python version. Known extension
143
184
# dependencies that are not in this set will be copied to the output
0 commit comments