1
1
"""
2
- Improved support for Microsoft Visual C++ compilers.
3
-
4
- Known supported compilers:
5
- --------------------------
6
- Microsoft Visual C++ 14.X:
7
- Microsoft Visual C++ Build Tools 2015 (x86, x64, arm)
8
- Microsoft Visual Studio Build Tools 2017 (x86, x64, arm, arm64)
9
- Microsoft Visual Studio Build Tools 2019 (x86, x64, arm, arm64)
10
-
11
- This may also support compilers shipped with compatible Visual Studio versions.
2
+ Environment info about Microsoft Compilers.
12
3
"""
13
4
14
5
from __future__ import annotations
17
8
import itertools
18
9
import json
19
10
import platform
20
- import subprocess
21
11
from os import listdir , pathsep
22
12
from os .path import dirname , isdir , isfile , join
23
- from subprocess import CalledProcessError
24
13
from typing import TYPE_CHECKING
25
14
26
15
from more_itertools import unique_everseen
27
16
28
17
import distutils .errors
29
- from distutils .util import get_platform
30
18
31
19
# https://github.com/python/mypy/issues/8166
32
20
if not TYPE_CHECKING and platform .system () == 'Windows' :
@@ -44,240 +32,6 @@ class winreg:
44
32
environ : dict [str , str ] = dict ()
45
33
46
34
47
- def _msvc14_find_vc2015 ():
48
- """Python 3.8 "distutils/_msvccompiler.py" backport"""
49
- try :
50
- key = winreg .OpenKey (
51
- winreg .HKEY_LOCAL_MACHINE ,
52
- r"Software\Microsoft\VisualStudio\SxS\VC7" ,
53
- 0 ,
54
- winreg .KEY_READ | winreg .KEY_WOW64_32KEY ,
55
- )
56
- except OSError :
57
- return None , None
58
-
59
- best_version = 0
60
- best_dir = None
61
- with key :
62
- for i in itertools .count ():
63
- try :
64
- v , vc_dir , vt = winreg .EnumValue (key , i )
65
- except OSError :
66
- break
67
- if v and vt == winreg .REG_SZ and isdir (vc_dir ):
68
- try :
69
- version = int (float (v ))
70
- except (ValueError , TypeError ):
71
- continue
72
- if version >= 14 and version > best_version :
73
- best_version , best_dir = version , vc_dir
74
- return best_version , best_dir
75
-
76
-
77
- def _msvc14_find_vc2017 ():
78
- """Python 3.8 "distutils/_msvccompiler.py" backport
79
-
80
- Returns "15, path" based on the result of invoking vswhere.exe
81
- If no install is found, returns "None, None"
82
-
83
- The version is returned to avoid unnecessarily changing the function
84
- result. It may be ignored when the path is not None.
85
-
86
- If vswhere.exe is not available, by definition, VS 2017 is not
87
- installed.
88
- """
89
- root = environ .get ("ProgramFiles(x86)" ) or environ .get ("ProgramFiles" )
90
- if not root :
91
- return None , None
92
-
93
- variant = 'arm64' if get_platform () == 'win-arm64' else 'x86.x64'
94
- suitable_components = (
95
- f"Microsoft.VisualStudio.Component.VC.Tools.{ variant } " ,
96
- "Microsoft.VisualStudio.Workload.WDExpress" ,
97
- )
98
-
99
- for component in suitable_components :
100
- # Workaround for `-requiresAny` (only available on VS 2017 > 15.6)
101
- with contextlib .suppress (CalledProcessError , OSError , UnicodeDecodeError ):
102
- path = (
103
- subprocess .check_output ([
104
- join (root , "Microsoft Visual Studio" , "Installer" , "vswhere.exe" ),
105
- "-latest" ,
106
- "-prerelease" ,
107
- "-requires" ,
108
- component ,
109
- "-property" ,
110
- "installationPath" ,
111
- "-products" ,
112
- "*" ,
113
- ])
114
- .decode (encoding = "mbcs" , errors = "strict" )
115
- .strip ()
116
- )
117
-
118
- path = join (path , "VC" , "Auxiliary" , "Build" )
119
- if isdir (path ):
120
- return 15 , path
121
-
122
- return None , None # no suitable component found
123
-
124
-
125
- PLAT_SPEC_TO_RUNTIME = {
126
- 'x86' : 'x86' ,
127
- 'x86_amd64' : 'x64' ,
128
- 'x86_arm' : 'arm' ,
129
- 'x86_arm64' : 'arm64' ,
130
- }
131
-
132
-
133
- def _msvc14_find_vcvarsall (plat_spec ):
134
- """Python 3.8 "distutils/_msvccompiler.py" backport"""
135
- _ , best_dir = _msvc14_find_vc2017 ()
136
- vcruntime = None
137
-
138
- if plat_spec in PLAT_SPEC_TO_RUNTIME :
139
- vcruntime_plat = PLAT_SPEC_TO_RUNTIME [plat_spec ]
140
- else :
141
- vcruntime_plat = 'x64' if 'amd64' in plat_spec else 'x86'
142
-
143
- if best_dir :
144
- vcredist = join (
145
- best_dir ,
146
- ".." ,
147
- ".." ,
148
- "redist" ,
149
- "MSVC" ,
150
- "**" ,
151
- vcruntime_plat ,
152
- "Microsoft.VC14*.CRT" ,
153
- "vcruntime140.dll" ,
154
- )
155
- try :
156
- import glob
157
-
158
- vcruntime = glob .glob (vcredist , recursive = True )[- 1 ]
159
- except (ImportError , OSError , LookupError ):
160
- vcruntime = None
161
-
162
- if not best_dir :
163
- best_version , best_dir = _msvc14_find_vc2015 ()
164
- if best_version :
165
- vcruntime = join (
166
- best_dir ,
167
- 'redist' ,
168
- vcruntime_plat ,
169
- "Microsoft.VC140.CRT" ,
170
- "vcruntime140.dll" ,
171
- )
172
-
173
- if not best_dir :
174
- return None , None
175
-
176
- vcvarsall = join (best_dir , "vcvarsall.bat" )
177
- if not isfile (vcvarsall ):
178
- return None , None
179
-
180
- if not vcruntime or not isfile (vcruntime ):
181
- vcruntime = None
182
-
183
- return vcvarsall , vcruntime
184
-
185
-
186
- def _msvc14_get_vc_env (plat_spec ):
187
- """Python 3.8 "distutils/_msvccompiler.py" backport"""
188
- if "DISTUTILS_USE_SDK" in environ :
189
- return {key .lower (): value for key , value in environ .items ()}
190
-
191
- vcvarsall , vcruntime = _msvc14_find_vcvarsall (plat_spec )
192
- if not vcvarsall :
193
- raise distutils .errors .DistutilsPlatformError ("Unable to find vcvarsall.bat" )
194
-
195
- try :
196
- out = subprocess .check_output (
197
- 'cmd /u /c "{}" {} && set' .format (vcvarsall , plat_spec ),
198
- stderr = subprocess .STDOUT ,
199
- ).decode ('utf-16le' , errors = 'replace' )
200
- except subprocess .CalledProcessError as exc :
201
- raise distutils .errors .DistutilsPlatformError (
202
- "Error executing {}" .format (exc .cmd )
203
- ) from exc
204
-
205
- env = {
206
- key .lower (): value
207
- for key , _ , value in (line .partition ('=' ) for line in out .splitlines ())
208
- if key and value
209
- }
210
-
211
- if vcruntime :
212
- env ['py_vcruntime_redist' ] = vcruntime
213
- return env
214
-
215
-
216
- def msvc14_get_vc_env (plat_spec ):
217
- """
218
- Patched "distutils._msvccompiler._get_vc_env" for support extra
219
- Microsoft Visual C++ 14.X compilers.
220
-
221
- Set environment without use of "vcvarsall.bat".
222
-
223
- Parameters
224
- ----------
225
- plat_spec: str
226
- Target architecture.
227
-
228
- Return
229
- ------
230
- dict
231
- environment
232
- """
233
-
234
- # Always use backport from CPython 3.8
235
- try :
236
- return _msvc14_get_vc_env (plat_spec )
237
- except distutils .errors .DistutilsPlatformError as exc :
238
- _augment_exception (exc , 14.0 )
239
- raise
240
-
241
-
242
- def _augment_exception (exc , version , arch = '' ):
243
- """
244
- Add details to the exception message to help guide the user
245
- as to what action will resolve it.
246
- """
247
- # Error if MSVC++ directory not found or environment not set
248
- message = exc .args [0 ]
249
-
250
- if "vcvarsall" in message .lower () or "visual c" in message .lower ():
251
- # Special error message if MSVC++ not installed
252
- tmpl = 'Microsoft Visual C++ {version:0.1f} or greater is required.'
253
- message = tmpl .format (** locals ())
254
- msdownload = 'www.microsoft.com/download/details.aspx?id=%d'
255
- if version == 9.0 :
256
- if arch .lower ().find ('ia64' ) > - 1 :
257
- # For VC++ 9.0, if IA64 support is needed, redirect user
258
- # to Windows SDK 7.0.
259
- # Note: No download link available from Microsoft.
260
- message += ' Get it with "Microsoft Windows SDK 7.0"'
261
- else :
262
- # For VC++ 9.0 redirect user to Vc++ for Python 2.7 :
263
- # This redirection link is maintained by Microsoft.
264
- # Contact [email protected] if it needs updating.
265
- message += ' Get it from http://aka.ms/vcpython27'
266
- elif version == 10.0 :
267
- # For VC++ 10.0 Redirect user to Windows SDK 7.1
268
- message += ' Get it with "Microsoft Windows SDK 7.1": '
269
- message += msdownload % 8279
270
- elif version >= 14.0 :
271
- # For VC++ 14.X Redirect user to latest Visual C++ Build Tools
272
- message += (
273
- ' Get it with "Microsoft C++ Build Tools": '
274
- r'https://visualstudio.microsoft.com'
275
- r'/visual-cpp-build-tools/'
276
- )
277
-
278
- exc .args = (message ,)
279
-
280
-
281
35
class PlatformInfo :
282
36
"""
283
37
Current and Target Architectures information.
0 commit comments