15
15
PY3 = bytes != str
16
16
17
17
18
+ def JoinPath (* args ):
19
+ return os .path .normpath (os .path .join (* args ))
20
+
21
+
18
22
class VisualStudioVersion (object ):
19
23
"""Information regarding a version of Visual Studio."""
20
24
21
25
def __init__ (self , short_name , description ,
22
26
solution_version , project_version , flat_sln , uses_vcxproj ,
23
- path , sdk_based , default_toolset = None ):
27
+ path , sdk_based , default_toolset = None , compatible_sdks = None ):
24
28
self .short_name = short_name
25
29
self .description = description
26
30
self .solution_version = solution_version
@@ -30,6 +34,9 @@ def __init__(self, short_name, description,
30
34
self .path = path
31
35
self .sdk_based = sdk_based
32
36
self .default_toolset = default_toolset
37
+ compatible_sdks = compatible_sdks or []
38
+ compatible_sdks .sort (key = lambda v : float (v .replace ('v' , '' )), reverse = True )
39
+ self .compatible_sdks = compatible_sdks
33
40
34
41
def ShortName (self ):
35
42
return self .short_name
@@ -70,43 +77,67 @@ def DefaultToolset(self):
70
77
of a user override."""
71
78
return self .default_toolset
72
79
73
- def SetupScript (self , target_arch ):
80
+
81
+ def _SetupScriptInternal (self , target_arch ):
74
82
"""Returns a command (with arguments) to be used to set up the
75
83
environment."""
76
- # Check if we are running in the SDK command line environment and use
77
- # the setup script from the SDK if so. |target_arch| should be either
78
- # 'x86' or 'x64'.
79
- assert target_arch in ('x86' , 'x64' )
80
- sdk_dir = os .environ .get ('WindowsSDKDir' )
81
- if self .sdk_based and sdk_dir :
82
- return [os .path .normpath (os .path .join (sdk_dir , 'Bin/SetEnv.Cmd' )),
83
- '/' + target_arch ]
84
- else :
85
- # We don't use VC/vcvarsall.bat for x86 because vcvarsall calls
86
- # vcvars32, which it can only find if VS??COMNTOOLS is set, which it
87
- # isn't always.
88
- if target_arch == 'x86' :
89
- if self .short_name >= '2013' and self .short_name [- 1 ] != 'e' and (
90
- os .environ .get ('PROCESSOR_ARCHITECTURE' ) == 'AMD64' or
91
- os .environ .get ('PROCESSOR_ARCHITEW6432' ) == 'AMD64' ):
92
- # VS2013 and later, non-Express have a x64-x86 cross that we want
93
- # to prefer.
94
- return [os .path .normpath (
95
- os .path .join (self .path , 'VC/vcvarsall.bat' )), 'amd64_x86' ]
96
- # Otherwise, the standard x86 compiler.
97
- return [os .path .normpath (
98
- os .path .join (self .path , 'Common7/Tools/vsvars32.bat' ))]
84
+ assert target_arch in ('x86' , 'x64' ), "target_arch not supported"
85
+ # If WindowsSDKDir is set and SetEnv.Cmd exists then we are using the
86
+ # depot_tools build tools and should run SetEnv.Cmd to set up the
87
+ # environment. The check for WindowsSDKDir alone is not sufficient because
88
+ # this is set by running vcvarsall.bat.
89
+ sdk_dir = os .environ .get ('WindowsSDKDir' , '' )
90
+ setup_path = JoinPath (sdk_dir , 'Bin' , 'SetEnv.Cmd' )
91
+ if self .sdk_based and sdk_dir and os .path .exists (setup_path ):
92
+ return [setup_path , '/' + target_arch ]
93
+
94
+ is_host_arch_x64 = (
95
+ os .environ .get ('PROCESSOR_ARCHITECTURE' ) == 'AMD64' or
96
+ os .environ .get ('PROCESSOR_ARCHITEW6432' ) == 'AMD64'
97
+ )
98
+
99
+ # For VS2017 (and newer) it's fairly easy
100
+ if self .short_name >= '2017' :
101
+ script_path = JoinPath (self .path ,
102
+ 'VC' , 'Auxiliary' , 'Build' , 'vcvarsall.bat' )
103
+
104
+ # Always use a native executable, cross-compiling if necessary.
105
+ host_arch = 'amd64' if is_host_arch_x64 else 'x86'
106
+ msvc_target_arch = 'amd64' if target_arch == 'x64' else 'x86'
107
+ arg = host_arch
108
+ if host_arch != msvc_target_arch :
109
+ arg += '_' + msvc_target_arch
110
+
111
+ return [script_path , arg ]
112
+
113
+ # We try to find the best version of the env setup batch.
114
+ vcvarsall = JoinPath (self .path , 'VC' , 'vcvarsall.bat' )
115
+ if target_arch == 'x86' :
116
+ if self .short_name >= '2013' and self .short_name [- 1 ] != 'e' and \
117
+ is_host_arch_x64 :
118
+ # VS2013 and later, non-Express have a x64-x86 cross that we want
119
+ # to prefer.
120
+ return [vcvarsall , 'amd64_x86' ]
99
121
else :
100
- assert target_arch == 'x64'
101
- arg = 'x86_amd64'
102
- # Use the 64-on-64 compiler if we're not using an express
103
- # edition and we're running on a 64bit OS.
104
- if self .short_name [- 1 ] != 'e' and (
105
- os .environ .get ('PROCESSOR_ARCHITECTURE' ) == 'AMD64' or
106
- os .environ .get ('PROCESSOR_ARCHITEW6432' ) == 'AMD64' ):
107
- arg = 'amd64'
108
- return [os .path .normpath (
109
- os .path .join (self .path , 'VC/vcvarsall.bat' )), arg ]
122
+ # Otherwise, the standard x86 compiler. We don't use VC/vcvarsall.bat
123
+ # for x86 because vcvarsall calls vcvars32, which it can only find if
124
+ # VS??COMNTOOLS is set, which isn't guaranteed.
125
+ return [JoinPath (self .path , 'Common7' , 'Tools' , 'vsvars32.bat' )]
126
+ elif target_arch == 'x64' :
127
+ arg = 'x86_amd64'
128
+ # Use the 64-on-64 compiler if we're not using an express edition and
129
+ # we're running on a 64bit OS.
130
+ if self .short_name [- 1 ] != 'e' and is_host_arch_x64 :
131
+ arg = 'amd64'
132
+ return [vcvarsall , arg ]
133
+
134
+ def SetupScript (self , target_arch ):
135
+ script_data = self ._SetupScriptInternal (target_arch )
136
+ script_path = script_data [0 ]
137
+ if not os .path .exists (script_path ):
138
+ raise Exception ('%s is missing - make sure VC++ tools are installed.' %
139
+ script_path )
140
+ return script_data
110
141
111
142
112
143
def _RegistryQueryBase (sysdir , key , value ):
@@ -181,11 +212,11 @@ def _RegistryGetValueUsingWinReg(key, value):
181
212
ImportError if _winreg is unavailable.
182
213
"""
183
214
try :
184
- # Python 2
185
- from _winreg import HKEY_LOCAL_MACHINE , OpenKey , QueryValueEx
215
+ # Python 2
216
+ from _winreg import HKEY_LOCAL_MACHINE , OpenKey , QueryValueEx
186
217
except ImportError :
187
- # Python 3
188
- from winreg import HKEY_LOCAL_MACHINE , OpenKey , QueryValueEx
218
+ # Python 3
219
+ from winreg import HKEY_LOCAL_MACHINE , OpenKey , QueryValueEx
189
220
190
221
try :
191
222
root , subkey = key .split ('\\ ' , 1 )
@@ -236,6 +267,26 @@ def _CreateVersion(name, path, sdk_based=False):
236
267
if path :
237
268
path = os .path .normpath (path )
238
269
versions = {
270
+ '2019' : VisualStudioVersion ('2019' ,
271
+ 'Visual Studio 2019' ,
272
+ solution_version = '12.00' ,
273
+ project_version = '16.0' ,
274
+ flat_sln = False ,
275
+ uses_vcxproj = True ,
276
+ path = path ,
277
+ sdk_based = sdk_based ,
278
+ default_toolset = 'v142' ,
279
+ compatible_sdks = ['v8.1' , 'v10.0' ]),
280
+ '2017' : VisualStudioVersion ('2017' ,
281
+ 'Visual Studio 2017' ,
282
+ solution_version = '12.00' ,
283
+ project_version = '15.0' ,
284
+ flat_sln = False ,
285
+ uses_vcxproj = True ,
286
+ path = path ,
287
+ sdk_based = sdk_based ,
288
+ default_toolset = 'v141' ,
289
+ compatible_sdks = ['v8.1' , 'v10.0' ]),
239
290
'2015' : VisualStudioVersion ('2015' ,
240
291
'Visual Studio 2015' ,
241
292
solution_version = '12.00' ,
@@ -350,14 +401,15 @@ def _DetectVisualStudioVersions(versions_to_check, force_express):
350
401
A list of visual studio versions installed in descending order of
351
402
usage preference.
352
403
Base this on the registry and a quick check if devenv.exe exists.
353
- Only versions 8-10 are considered.
354
404
Possibilities are:
355
405
2005(e) - Visual Studio 2005 (8)
356
406
2008(e) - Visual Studio 2008 (9)
357
407
2010(e) - Visual Studio 2010 (10)
358
408
2012(e) - Visual Studio 2012 (11)
359
409
2013(e) - Visual Studio 2013 (12)
360
410
2015 - Visual Studio 2015 (14)
411
+ 2017 - Visual Studio 2017 (15)
412
+ 2019 - Visual Studio 2019 (16)
361
413
Where (e) is e for express editions of MSVS and blank otherwise.
362
414
"""
363
415
version_to_year = {
@@ -367,6 +419,8 @@ def _DetectVisualStudioVersions(versions_to_check, force_express):
367
419
'11.0' : '2012' ,
368
420
'12.0' : '2013' ,
369
421
'14.0' : '2015' ,
422
+ '15.0' : '2017' ,
423
+ '16.0' : '2019' ,
370
424
}
371
425
versions = []
372
426
for version in versions_to_check :
@@ -397,13 +451,18 @@ def _DetectVisualStudioVersions(versions_to_check, force_express):
397
451
398
452
# The old method above does not work when only SDK is installed.
399
453
keys = [r'HKLM\Software\Microsoft\VisualStudio\SxS\VC7' ,
400
- r'HKLM\Software\Wow6432Node\Microsoft\VisualStudio\SxS\VC7' ]
454
+ r'HKLM\Software\Wow6432Node\Microsoft\VisualStudio\SxS\VC7' ,
455
+ r'HKLM\Software\Microsoft\VisualStudio\SxS\VS7' ,
456
+ r'HKLM\Software\Wow6432Node\Microsoft\VisualStudio\SxS\VS7' ]
401
457
for index in range (len (keys )):
402
458
path = _RegistryGetValue (keys [index ], version )
403
459
if not path :
404
460
continue
405
461
path = _ConvertToCygpath (path )
406
- if version != '14.0' : # There is no Express edition for 2015.
462
+ if version == '15.0' :
463
+ if os .path .exists (path ):
464
+ versions .append (_CreateVersion ('2017' , path ))
465
+ elif version != '14.0' : # There is no Express edition for 2015.
407
466
versions .append (_CreateVersion (version_to_year [version ] + 'e' ,
408
467
os .path .join (path , '..' ), sdk_based = True ))
409
468
@@ -422,7 +481,7 @@ def SelectVisualStudioVersion(version='auto', allow_fallback=True):
422
481
if version == 'auto' :
423
482
version = os .environ .get ('GYP_MSVS_VERSION' , 'auto' )
424
483
version_map = {
425
- 'auto' : ('14.0' , '12.0' , '10.0' , '9.0' , '8.0' , '11.0' ),
484
+ 'auto' : ('16.0' , '15.0' , ' 14.0' , '12.0' , '10.0' , '9.0' , '8.0' , '11.0' ),
426
485
'2005' : ('8.0' ,),
427
486
'2005e' : ('8.0' ,),
428
487
'2008' : ('9.0' ,),
@@ -434,6 +493,8 @@ def SelectVisualStudioVersion(version='auto', allow_fallback=True):
434
493
'2013' : ('12.0' ,),
435
494
'2013e' : ('12.0' ,),
436
495
'2015' : ('14.0' ,),
496
+ '2017' : ('15.0' ,),
497
+ '2019' : ('16.0' ,),
437
498
}
438
499
override_path = os .environ .get ('GYP_MSVS_OVERRIDE_PATH' )
439
500
if override_path :
0 commit comments