3 # Copyright The SCons Foundation
5 # Permission is hereby granted, free of charge, to any person obtaining
6 # a copy of this software and associated documentation files (the
7 # "Software"), to deal in the Software without restriction, including
8 # without limitation the rights to use, copy, modify, merge, publish,
9 # distribute, sublicense, and/or sell copies of the Software, and to
10 # permit persons to whom the Software is furnished to do so, subject to
11 # the following conditions:
13 # The above copyright notice and this permission notice shall be included
14 # in all copies or substantial portions of the Software.
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
17 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
18 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 Batch file argument functions for Microsoft Visual C/C++.
32 from collections
import (
36 from ..common
import (
37 CONFIG_CACHE_FORCE_DEFAULT_ARGUMENTS
,
43 from . import Registry
47 from .Exceptions
import (
49 MSVCSDKVersionNotFound
,
50 MSVCToolsetVersionNotFound
,
51 MSVCSpectreLibsNotFound
,
55 from . import Dispatcher
56 Dispatcher
.register_modulename(__name__
)
59 # Script argument: boolean True
60 _ARGUMENT_BOOLEAN_TRUE_LEGACY
= (True, '1') # MSVC_UWP_APP
61 _ARGUMENT_BOOLEAN_TRUE
= (True,)
63 # TODO: verify SDK 10 version folder names 10.0.XXXXX.0 {1,3} last?
64 re_sdk_version_100
= re
.compile(r
'^10[.][0-9][.][0-9]{5}[.][0-9]{1}$')
65 re_sdk_version_81
= re
.compile(r
'^8[.]1$')
67 re_sdk_dispatch_map
= {
68 '10.0': re_sdk_version_100
,
69 '8.1': re_sdk_version_81
,
72 def _verify_re_sdk_dispatch_map():
74 for sdk_version
in Config
.MSVC_SDK_VERSIONS
:
75 if sdk_version
in re_sdk_dispatch_map
:
77 err_msg
= f
'sdk version {sdk_version} not in re_sdk_dispatch_map'
78 raise MSVCInternalError(err_msg
)
82 _msvc_sxs_bugfix_map
= {}
83 _msvc_sxs_bugfix_folder
= {}
84 _msvc_sxs_bugfix_version
= {}
86 for msvc_version
, sxs_version
, sxs_bugfix
in [
87 # VS2019\Common7\Tools\vsdevcmd\ext\vcvars.bat AzDO Bug#1293526
88 # special handling of the 16.8 SxS toolset, use VC\Auxiliary\Build\14.28 directory and SxS files
89 # if SxS version 14.28 not present/installed, fallback selection of toolset VC\Tools\MSVC\14.28.nnnnn.
90 ('14.2', '14.28.16.8', '14.28')
92 _msvc_sxs_bugfix_map
.setdefault(msvc_version
, []).append((sxs_version
, sxs_bugfix
))
93 _msvc_sxs_bugfix_folder
[(msvc_version
, sxs_bugfix
)] = sxs_version
94 _msvc_sxs_bugfix_version
[(msvc_version
, sxs_version
)] = sxs_bugfix
97 re_vcvars_uwp
= re
.compile(r
'(?:(?<!\S)|^)(?P<uwp>(?:uwp|store))(?:(?!\S)|$)',re
.IGNORECASE
)
98 re_vcvars_sdk
= re
.compile(r
'(?:(?<!\S)|^)(?P<sdk>(?:[1-9][0-9]*[.]\S*))(?:(?!\S)|$)',re
.IGNORECASE
)
99 re_vcvars_toolset
= re
.compile(r
'(?:(?<!\S)|^)(?P<toolset_arg>(?:[-]{1,2}|[/])vcvars_ver[=](?P<toolset>\S*))(?:(?!\S)|$)', re
.IGNORECASE
)
100 re_vcvars_spectre
= re
.compile(r
'(?:(?<!\S)|^)(?P<spectre_arg>(?:[-]{1,2}|[/])vcvars_spectre_libs[=](?P<spectre>\S*))(?:(?!\S)|$)',re
.IGNORECASE
)
102 # Force default sdk argument
103 _MSVC_FORCE_DEFAULT_SDK
= False
105 # Force default toolset argument
106 _MSVC_FORCE_DEFAULT_TOOLSET
= False
108 # Force default arguments
109 _MSVC_FORCE_DEFAULT_ARGUMENTS
= False
111 def _msvc_force_default_sdk(force
: bool=True) -> None:
112 global _MSVC_FORCE_DEFAULT_SDK
113 _MSVC_FORCE_DEFAULT_SDK
= force
114 debug('_MSVC_FORCE_DEFAULT_SDK=%s', repr(force
))
116 def _msvc_force_default_toolset(force
: bool=True) -> None:
117 global _MSVC_FORCE_DEFAULT_TOOLSET
118 _MSVC_FORCE_DEFAULT_TOOLSET
= force
119 debug('_MSVC_FORCE_DEFAULT_TOOLSET=%s', repr(force
))
121 def msvc_force_default_arguments(force
=None):
122 global _MSVC_FORCE_DEFAULT_ARGUMENTS
123 prev_policy
= _MSVC_FORCE_DEFAULT_ARGUMENTS
124 if force
is not None:
125 _MSVC_FORCE_DEFAULT_ARGUMENTS
= force
126 _msvc_force_default_sdk(force
)
127 _msvc_force_default_toolset(force
)
130 if CONFIG_CACHE_FORCE_DEFAULT_ARGUMENTS
:
131 msvc_force_default_arguments(force
=True)
133 # UWP SDK 8.1 and SDK 10:
135 # https://stackoverflow.com/questions/46659238/build-windows-app-compatible-for-8-1-and-10
136 # VS2019 - UWP (Except for Win10Mobile)
138 # VS2015 - UWP, Win8.1 StoreApp, WP8/8.1 StoreApp
139 # VS2013 - Win8/8.1 StoreApp, WP8/8.1 StoreApp
141 # SPECTRE LIBS (msvc documentation):
142 # "There are no versions of Spectre-mitigated libraries for Universal Windows (UWP) apps or
143 # components. App-local deployment of such libraries isn't possible."
145 # MSVC batch file arguments:
147 # VS2022: UWP, SDK, TOOLSET, SPECTRE
148 # VS2019: UWP, SDK, TOOLSET, SPECTRE
149 # VS2017: UWP, SDK, TOOLSET, SPECTRE
152 # MSVC_SCRIPT_ARGS: VS2015+
154 # MSVC_UWP_APP: VS2015+
155 # MSVC_SDK_VERSION: VS2015+
156 # MSVC_TOOLSET_VERSION: VS2017+
157 # MSVC_SPECTRE_LIBS: VS2017+
160 class SortOrder(enum
.IntEnum
):
161 UWP
= 1 # MSVC_UWP_APP
162 SDK
= 2 # MSVC_SDK_VERSION
163 TOOLSET
= 3 # MSVC_TOOLSET_VERSION
164 SPECTRE
= 4 # MSVC_SPECTRE_LIBS
165 USER
= 5 # MSVC_SCRIPT_ARGS
167 VS2019
= Config
.MSVS_VERSION_INTERNAL
['2019']
168 VS2017
= Config
.MSVS_VERSION_INTERNAL
['2017']
169 VS2015
= Config
.MSVS_VERSION_INTERNAL
['2015']
171 MSVC_VERSION_ARGS_DEFINITION
= namedtuple('MSVCVersionArgsDefinition', [
172 'version', # full version (e.g., '14.1Exp', '14.32.31326')
176 TOOLSET_VERSION_ARGS_DEFINITION
= namedtuple('ToolsetVersionArgsDefinition', [
177 'version', # full version (e.g., '14.1Exp', '14.32.31326')
182 def _msvc_version(version
):
184 verstr
= Util
.get_msvc_version_prefix(version
)
185 vs_def
= Config
.MSVC_VERSION_INTERNAL
[verstr
]
187 version_args
= MSVC_VERSION_ARGS_DEFINITION(
194 def _toolset_version(version
, is_user
=False):
196 vc_series
= Util
.get_msvc_version_prefix(version
)
198 vc_buildseries_def
= Config
.MSVC_BUILDSERIES_EXTERNAL
[vc_series
]
199 vc_buildtools_def
= Config
.VC_BUILDTOOLS_MAP
[vc_buildseries_def
.vc_buildseries
]
201 version_args
= TOOLSET_VERSION_ARGS_DEFINITION(
203 vc_buildtools_def
= vc_buildtools_def
,
209 def _msvc_script_argument_uwp(env
, msvc
, arglist
, target_arch
):
211 uwp_app
= env
['MSVC_UWP_APP']
212 debug('MSVC_VERSION=%s, MSVC_UWP_APP=%s', repr(msvc
.version
), repr(uwp_app
))
217 if uwp_app
not in _ARGUMENT_BOOLEAN_TRUE_LEGACY
:
220 if msvc
.vs_def
.vc_buildtools_def
.msvc_version_numeric
< VS2015
.vc_buildtools_def
.msvc_version_numeric
:
222 'invalid: msvc version constraint: %s < %s VS2015',
223 repr(msvc
.vs_def
.vc_buildtools_def
.msvc_version_numeric
),
224 repr(VS2015
.vc_buildtools_def
.msvc_version_numeric
)
226 err_msg
= "MSVC_UWP_APP ({}) constraint violation: MSVC_VERSION {} < {} VS2015".format(
227 repr(uwp_app
), repr(msvc
.version
), repr(VS2015
.vc_buildtools_def
.msvc_version
)
229 raise MSVCArgumentError(err_msg
)
231 is_supported
, is_target
= Kind
.msvc_version_uwp_is_supported(msvc
.version
, target_arch
, env
)
233 _
, kind_str
= Kind
.get_msvc_version_kind(msvc
.version
)
235 'invalid: msvc_version constraint: %s %s %s',
236 repr(msvc
.version
), repr(kind_str
), repr(target_arch
)
238 if is_target
and target_arch
:
239 err_msg
= "MSVC_UWP_APP ({}) TARGET_ARCH ({}) is not supported for MSVC_VERSION {} ({})".format(
240 repr(uwp_app
), repr(target_arch
), repr(msvc
.version
), repr(kind_str
)
243 err_msg
= "MSVC_UWP_APP ({}) is not supported for MSVC_VERSION {} ({})".format(
244 repr(uwp_app
), repr(msvc
.version
), repr(kind_str
)
246 raise MSVCArgumentError(err_msg
)
248 # VS2017+ rewrites uwp => store for 14.0 toolset
249 uwp_arg
= msvc
.vs_def
.vc_uwp
251 # store/uwp may not be fully installed
252 argpair
= (SortOrder
.UWP
, uwp_arg
)
253 arglist
.append(argpair
)
257 def _user_script_argument_uwp(env
, uwp
, user_argstr
) -> bool:
259 matches
= [m
for m
in re_vcvars_uwp
.finditer(user_argstr
)]
264 debug('multiple uwp declarations: MSVC_SCRIPT_ARGS=%s', repr(user_argstr
))
265 err_msg
= f
"multiple uwp declarations: MSVC_SCRIPT_ARGS={user_argstr!r}"
266 raise MSVCArgumentError(err_msg
)
271 env_argstr
= env
.get('MSVC_UWP_APP','')
272 debug('multiple uwp declarations: MSVC_UWP_APP=%s, MSVC_SCRIPT_ARGS=%s', repr(env_argstr
), repr(user_argstr
))
274 err_msg
= "multiple uwp declarations: MSVC_UWP_APP={} and MSVC_SCRIPT_ARGS={}".format(
275 repr(env_argstr
), repr(user_argstr
)
278 raise MSVCArgumentError(err_msg
)
280 def _msvc_script_argument_sdk_constraints(msvc
, sdk_version
, env
):
282 if msvc
.vs_def
.vc_buildtools_def
.msvc_version_numeric
< VS2015
.vc_buildtools_def
.msvc_version_numeric
:
284 'invalid: msvc_version constraint: %s < %s VS2015',
285 repr(msvc
.vs_def
.vc_buildtools_def
.msvc_version_numeric
),
286 repr(VS2015
.vc_buildtools_def
.msvc_version_numeric
)
288 err_msg
= "MSVC_SDK_VERSION ({}) constraint violation: MSVC_VERSION {} < {} VS2015".format(
289 repr(sdk_version
), repr(msvc
.version
), repr(VS2015
.vc_buildtools_def
.msvc_version
)
293 if not Kind
.msvc_version_sdk_version_is_supported(msvc
.version
, env
):
294 _
, kind_str
= Kind
.get_msvc_version_kind(msvc
.version
)
295 debug('invalid: msvc_version constraint: %s %s', repr(msvc
.version
), repr(kind_str
))
296 err_msg
= "MSVC_SDK_VERSION ({}) is not supported for MSVC_VERSION {} ({})".format(
297 repr(sdk_version
), repr(msvc
.version
), repr(kind_str
)
301 for msvc_sdk_version
in msvc
.vs_def
.vc_sdk_versions
:
302 re_sdk_version
= re_sdk_dispatch_map
[msvc_sdk_version
]
303 if re_sdk_version
.match(sdk_version
):
304 debug('valid: sdk_version=%s', repr(sdk_version
))
307 debug('invalid: method exit: sdk_version=%s', repr(sdk_version
))
308 err_msg
= f
"MSVC_SDK_VERSION ({sdk_version!r}) is not supported"
311 def _msvc_script_argument_sdk_platform_constraints(msvc
, toolset
, sdk_version
, platform_def
):
313 if sdk_version
== '8.1' and platform_def
.is_uwp
:
315 vc_buildtools_def
= toolset
.vc_buildtools_def
if toolset
else msvc
.vs_def
.vc_buildtools_def
317 if vc_buildtools_def
.msvc_version_numeric
> VS2015
.vc_buildtools_def
.msvc_version_numeric
:
319 'invalid: uwp/store SDK 8.1 msvc_version constraint: %s > %s VS2015',
320 repr(vc_buildtools_def
.msvc_version_numeric
),
321 repr(VS2015
.vc_buildtools_def
.msvc_version_numeric
)
323 if toolset
and toolset
.is_user
:
324 err_msg
= "MSVC_SDK_VERSION ({}) and platform type ({}) constraint violation: toolset {} MSVC_VERSION {} > {} VS2015".format(
325 repr(sdk_version
), repr(platform_def
.vc_platform
),
326 repr(toolset
.version
), repr(msvc
.version
), repr(VS2015
.vc_buildtools_def
.msvc_version
)
329 err_msg
= "MSVC_SDK_VERSION ({}) and platform type ({}) constraint violation: MSVC_VERSION {} > {} VS2015".format(
330 repr(sdk_version
), repr(platform_def
.vc_platform
),
331 repr(msvc
.version
), repr(VS2015
.vc_buildtools_def
.msvc_version
)
337 def _msvc_script_argument_sdk(env
, msvc
, toolset
, platform_def
, arglist
):
339 sdk_version
= env
['MSVC_SDK_VERSION']
341 'MSVC_VERSION=%s, MSVC_SDK_VERSION=%s, platform_type=%s',
342 repr(msvc
.version
), repr(sdk_version
), repr(platform_def
.vc_platform
)
348 err_msg
= _msvc_script_argument_sdk_constraints(msvc
, sdk_version
, env
)
350 raise MSVCArgumentError(err_msg
)
352 sdk_list
= WinSDK
.get_sdk_version_list(msvc
.vs_def
, platform_def
)
354 if sdk_version
not in sdk_list
:
355 err_msg
= "MSVC_SDK_VERSION {} not found for platform type {}".format(
356 repr(sdk_version
), repr(platform_def
.vc_platform
)
358 raise MSVCSDKVersionNotFound(err_msg
)
360 err_msg
= _msvc_script_argument_sdk_platform_constraints(msvc
, toolset
, sdk_version
, platform_def
)
362 raise MSVCArgumentError(err_msg
)
364 argpair
= (SortOrder
.SDK
, sdk_version
)
365 arglist
.append(argpair
)
369 def _msvc_script_default_sdk(env
, msvc
, platform_def
, arglist
, force_sdk
: bool=False):
371 if msvc
.vs_def
.vc_buildtools_def
.msvc_version_numeric
< VS2015
.vc_buildtools_def
.msvc_version_numeric
:
374 if not Kind
.msvc_version_sdk_version_is_supported(msvc
.version
, env
):
377 sdk_list
= WinSDK
.get_sdk_version_list(msvc
.vs_def
, platform_def
)
378 if not len(sdk_list
):
381 sdk_default
= sdk_list
[0]
384 'MSVC_VERSION=%s, sdk_default=%s, platform_type=%s',
385 repr(msvc
.version
), repr(sdk_default
), repr(platform_def
.vc_platform
)
389 argpair
= (SortOrder
.SDK
, sdk_default
)
390 arglist
.append(argpair
)
394 def _user_script_argument_sdk(env
, sdk_version
, user_argstr
):
396 matches
= [m
for m
in re_vcvars_sdk
.finditer(user_argstr
)]
401 debug('multiple sdk version declarations: MSVC_SCRIPT_ARGS=%s', repr(user_argstr
))
402 err_msg
= f
"multiple sdk version declarations: MSVC_SCRIPT_ARGS={user_argstr!r}"
403 raise MSVCArgumentError(err_msg
)
406 user_sdk
= matches
[0].group('sdk')
409 env_argstr
= env
.get('MSVC_SDK_VERSION','')
410 debug('multiple sdk version declarations: MSVC_SDK_VERSION=%s, MSVC_SCRIPT_ARGS=%s', repr(env_argstr
), repr(user_argstr
))
412 err_msg
= "multiple sdk version declarations: MSVC_SDK_VERSION={} and MSVC_SCRIPT_ARGS={}".format(
413 repr(env_argstr
), repr(user_argstr
)
416 raise MSVCArgumentError(err_msg
)
418 _toolset_have140_cache
= None
420 def _msvc_have140_toolset():
421 global _toolset_have140_cache
423 if _toolset_have140_cache
is None:
424 suffix
= Registry
.vstudio_sxs_vc7('14.0')
425 vcinstalldirs
= [record
[0] for record
in Registry
.microsoft_query_paths(suffix
)]
426 debug('vc140 toolset: paths=%s', repr(vcinstalldirs
))
427 _toolset_have140_cache
= True if vcinstalldirs
else False
429 return _toolset_have140_cache
431 def _reset_have140_cache() -> None:
432 global _toolset_have140_cache
433 debug('reset: cache')
434 _toolset_have140_cache
= None
436 def _msvc_read_toolset_file(msvc
, filename
):
437 toolset_version
= None
439 with
open(filename
) as f
:
440 toolset_version
= f
.readlines()[0].strip()
442 'msvc_version=%s, filename=%s, toolset_version=%s',
443 repr(msvc
.version
), repr(filename
), repr(toolset_version
)
446 debug('OSError: msvc_version=%s, filename=%s', repr(msvc
.version
), repr(filename
))
448 debug('IndexError: msvc_version=%s, filename=%s', repr(msvc
.version
), repr(filename
))
449 return toolset_version
451 def _msvc_sxs_toolset_folder(msvc
, sxs_folder
):
453 if Util
.is_toolset_sxs(sxs_folder
):
454 return sxs_folder
, sxs_folder
456 for vc_buildseries_def
in msvc
.vs_def
.vc_buildtools_def
.vc_buildseries_list
:
457 key
= (vc_buildseries_def
.vc_version
, sxs_folder
)
458 sxs_version
= _msvc_sxs_bugfix_folder
.get(key
)
460 return sxs_folder
, sxs_version
462 debug('sxs folder: ignore version=%s', repr(sxs_folder
))
465 def _msvc_read_toolset_folders(msvc
, vc_dir
):
470 build_dir
= os
.path
.join(vc_dir
, "Auxiliary", "Build")
471 if os
.path
.exists(build_dir
):
472 for sxs_folder
, sxs_path
in Util
.listdir_dirs(build_dir
):
473 sxs_folder
, sxs_version
= _msvc_sxs_toolset_folder(msvc
, sxs_folder
)
476 filename
= f
'Microsoft.VCToolsVersion.{sxs_folder}.txt'
477 filepath
= os
.path
.join(sxs_path
, filename
)
478 debug('sxs toolset: check file=%s', repr(filepath
))
479 if os
.path
.exists(filepath
):
480 toolset_version
= _msvc_read_toolset_file(msvc
, filepath
)
481 if not toolset_version
:
483 toolsets_sxs
[sxs_version
] = toolset_version
485 'sxs toolset: msvc_version=%s, sxs_version=%s, toolset_version=%s',
486 repr(msvc
.version
), repr(sxs_version
), repr(toolset_version
)
489 toolset_dir
= os
.path
.join(vc_dir
, "Tools", "MSVC")
490 if os
.path
.exists(toolset_dir
):
491 for toolset_version
, toolset_path
in Util
.listdir_dirs(toolset_dir
):
492 binpath
= os
.path
.join(toolset_path
, "bin")
493 debug('toolset: check binpath=%s', repr(binpath
))
494 if os
.path
.exists(binpath
):
495 toolsets_full
.append(toolset_version
)
497 'toolset: msvc_version=%s, toolset_version=%s',
498 repr(msvc
.version
), repr(toolset_version
)
501 vcvars140
= os
.path
.join(vc_dir
, "..", "Common7", "Tools", "vsdevcmd", "ext", "vcvars", "vcvars140.bat")
502 if os
.path
.exists(vcvars140
) and _msvc_have140_toolset():
503 toolset_version
= '14.0'
504 toolsets_full
.append(toolset_version
)
506 'toolset: msvc_version=%s, toolset_version=%s',
507 repr(msvc
.version
), repr(toolset_version
)
510 toolsets_full
.sort(reverse
=True)
512 # SxS bugfix fixup (if necessary)
513 if msvc
.version
in _msvc_sxs_bugfix_map
:
514 for sxs_version
, sxs_bugfix
in _msvc_sxs_bugfix_map
[msvc
.version
]:
515 if sxs_version
in toolsets_sxs
:
516 # have SxS version (folder/file mapping exists)
518 for toolset_version
in toolsets_full
:
519 if not toolset_version
.startswith(sxs_bugfix
):
522 'sxs toolset: msvc_version=%s, sxs_version=%s, toolset_version=%s',
523 repr(msvc
.version
), repr(sxs_version
), repr(toolset_version
)
525 # SxS compatible bugfix version (equivalent to toolset search)
526 toolsets_sxs
[sxs_version
] = toolset_version
529 debug('msvc_version=%s, toolsets=%s', repr(msvc
.version
), repr(toolsets_full
))
531 return toolsets_sxs
, toolsets_full
533 def _msvc_read_toolset_default(msvc
, vc_dir
):
535 build_dir
= os
.path
.join(vc_dir
, "Auxiliary", "Build")
538 filename
= f
"Microsoft.VCToolsVersion.{msvc.vs_def.vc_buildtools_def.vc_buildtools}.default.txt"
539 filepath
= os
.path
.join(build_dir
, filename
)
541 debug('default toolset: check file=%s', repr(filepath
))
542 if os
.path
.exists(filepath
):
543 toolset_buildtools
= _msvc_read_toolset_file(msvc
, filepath
)
544 if toolset_buildtools
:
545 return toolset_buildtools
548 filename
= "Microsoft.VCToolsVersion.default.txt"
549 filepath
= os
.path
.join(build_dir
, filename
)
551 debug('default toolset: check file=%s', repr(filepath
))
552 if os
.path
.exists(filepath
):
553 toolset_default
= _msvc_read_toolset_file(msvc
, filepath
)
555 return toolset_default
559 _toolset_version_cache
= {}
560 _toolset_default_cache
= {}
562 def _reset_toolset_cache() -> None:
563 global _toolset_version_cache
564 global _toolset_default_cache
565 debug('reset: toolset cache')
566 _toolset_version_cache
= {}
567 _toolset_default_cache
= {}
569 def _msvc_version_toolsets(msvc
, vc_dir
):
571 if msvc
.version
in _toolset_version_cache
:
572 toolsets_sxs
, toolsets_full
= _toolset_version_cache
[msvc
.version
]
574 toolsets_sxs
, toolsets_full
= _msvc_read_toolset_folders(msvc
, vc_dir
)
575 _toolset_version_cache
[msvc
.version
] = toolsets_sxs
, toolsets_full
577 return toolsets_sxs
, toolsets_full
579 def _msvc_default_toolset(msvc
, vc_dir
):
581 if msvc
.version
in _toolset_default_cache
:
582 toolset_default
= _toolset_default_cache
[msvc
.version
]
584 toolset_default
= _msvc_read_toolset_default(msvc
, vc_dir
)
585 _toolset_default_cache
[msvc
.version
] = toolset_default
587 return toolset_default
589 def _msvc_version_toolset_vcvars(msvc
, vc_dir
, toolset_version
):
591 toolsets_sxs
, toolsets_full
= _msvc_version_toolsets(msvc
, vc_dir
)
593 if toolset_version
in toolsets_full
:
594 # full toolset version provided
595 toolset_vcvars
= toolset_version
596 return toolset_vcvars
598 if Util
.is_toolset_sxs(toolset_version
):
599 # SxS version provided
600 sxs_version
= toolsets_sxs
.get(toolset_version
, None)
601 if sxs_version
and sxs_version
in toolsets_full
:
602 # SxS full toolset version
603 toolset_vcvars
= sxs_version
604 return toolset_vcvars
607 for toolset_full
in toolsets_full
:
608 if toolset_full
.startswith(toolset_version
):
609 toolset_vcvars
= toolset_full
610 return toolset_vcvars
614 def _msvc_script_argument_toolset_constraints(msvc
, toolset_version
):
616 if msvc
.vs_def
.vc_buildtools_def
.msvc_version_numeric
< VS2017
.vc_buildtools_def
.msvc_version_numeric
:
618 'invalid: msvc version constraint: %s < %s VS2017',
619 repr(msvc
.vs_def
.vc_buildtools_def
.msvc_version_numeric
),
620 repr(VS2017
.vc_buildtools_def
.msvc_version_numeric
)
622 err_msg
= "MSVC_TOOLSET_VERSION ({}) constraint violation: MSVC_VERSION {} < {} VS2017".format(
623 repr(toolset_version
), repr(msvc
.version
), repr(VS2017
.vc_buildtools_def
.msvc_version
)
627 toolset_series
= Util
.get_msvc_version_prefix(toolset_version
)
629 if not toolset_series
:
630 debug('invalid: msvc version: toolset_version=%s', repr(toolset_version
))
631 err_msg
= 'MSVC_TOOLSET_VERSION {} format is not supported'.format(
632 repr(toolset_version
)
636 toolset_buildseries_def
= Config
.MSVC_BUILDSERIES_EXTERNAL
.get(toolset_series
)
637 if not toolset_buildseries_def
:
638 debug('invalid: msvc version: toolset_version=%s', repr(toolset_version
))
639 err_msg
= 'MSVC_TOOLSET_VERSION {} build series {} is not supported'.format(
640 repr(toolset_version
), repr(toolset_series
)
644 toolset_buildtools_def
= Config
.VC_BUILDTOOLS_MAP
[toolset_buildseries_def
.vc_buildseries
]
646 toolset_verstr
= toolset_buildtools_def
.msvc_version
647 toolset_vernum
= toolset_buildtools_def
.msvc_version_numeric
649 if toolset_vernum
< VS2015
.vc_buildtools_def
.msvc_version_numeric
:
651 'invalid: toolset version constraint: %s < %s VS2015',
652 repr(toolset_vernum
), repr(VS2015
.vc_buildtools_def
.msvc_version_numeric
)
654 err_msg
= "MSVC_TOOLSET_VERSION ({}) constraint violation: toolset msvc version {} < {} VS2015".format(
655 repr(toolset_version
), repr(toolset_verstr
), repr(VS2015
.vc_buildtools_def
.msvc_version
)
659 if toolset_vernum
> msvc
.vs_def
.vc_buildtools_def
.msvc_version_numeric
:
661 'invalid: toolset version constraint: toolset %s > %s msvc',
662 repr(toolset_vernum
), repr(msvc
.vs_def
.vc_buildtools_def
.msvc_version_numeric
)
664 err_msg
= "MSVC_TOOLSET_VERSION ({}) constraint violation: toolset msvc version {} > {} MSVC_VERSION".format(
665 repr(toolset_version
), repr(toolset_verstr
), repr(msvc
.version
)
669 if toolset_vernum
== VS2015
.vc_buildtools_def
.msvc_version_numeric
:
671 if Util
.is_toolset_full(toolset_version
):
672 if not Util
.is_toolset_140(toolset_version
):
674 'invalid: toolset version 14.0 constraint: %s != 14.0',
675 repr(toolset_version
)
677 err_msg
= "MSVC_TOOLSET_VERSION ({}) constraint violation: toolset msvc version {} != '14.0'".format(
678 repr(toolset_version
), repr(toolset_version
)
683 if Util
.is_toolset_full(toolset_version
):
684 debug('valid: toolset full: toolset_version=%s', repr(toolset_version
))
687 if Util
.is_toolset_sxs(toolset_version
):
688 debug('valid: toolset sxs: toolset_version=%s', repr(toolset_version
))
691 debug('invalid: method exit: toolset_version=%s', repr(toolset_version
))
692 err_msg
= f
"MSVC_TOOLSET_VERSION ({toolset_version!r}) format is not supported"
695 def _msvc_script_argument_toolset_vcvars(msvc
, toolset_version
, vc_dir
):
697 err_msg
= _msvc_script_argument_toolset_constraints(msvc
, toolset_version
)
699 raise MSVCArgumentError(err_msg
)
701 if toolset_version
.startswith('14.0') and len(toolset_version
) > len('14.0'):
702 new_toolset_version
= '14.0'
704 'rewrite toolset_version=%s => toolset_version=%s',
705 repr(toolset_version
), repr(new_toolset_version
)
707 toolset_version
= new_toolset_version
709 toolset_vcvars
= _msvc_version_toolset_vcvars(msvc
, vc_dir
, toolset_version
)
711 'toolset: toolset_version=%s, toolset_vcvars=%s',
712 repr(toolset_version
), repr(toolset_vcvars
)
715 if not toolset_vcvars
:
716 err_msg
= "MSVC_TOOLSET_VERSION {} not found for MSVC_VERSION {}".format(
717 repr(toolset_version
), repr(msvc
.version
)
719 raise MSVCToolsetVersionNotFound(err_msg
)
721 return toolset_vcvars
723 def _msvc_script_argument_toolset(env
, msvc
, vc_dir
, arglist
):
725 toolset_version
= env
['MSVC_TOOLSET_VERSION']
726 debug('MSVC_VERSION=%s, MSVC_TOOLSET_VERSION=%s', repr(msvc
.version
), repr(toolset_version
))
728 if not toolset_version
:
731 toolset_vcvars
= _msvc_script_argument_toolset_vcvars(msvc
, toolset_version
, vc_dir
)
733 # toolset may not be installed for host/target
734 argpair
= (SortOrder
.TOOLSET
, f
'-vcvars_ver={toolset_vcvars}')
735 arglist
.append(argpair
)
737 return toolset_vcvars
739 def _msvc_script_default_toolset(env
, msvc
, vc_dir
, arglist
, force_toolset
: bool=False):
741 if msvc
.vs_def
.vc_buildtools_def
.msvc_version_numeric
< VS2017
.vc_buildtools_def
.msvc_version_numeric
:
744 toolset_default
= _msvc_default_toolset(msvc
, vc_dir
)
745 if not toolset_default
:
748 debug('MSVC_VERSION=%s, toolset_default=%s', repr(msvc
.version
), repr(toolset_default
))
751 argpair
= (SortOrder
.TOOLSET
, f
'-vcvars_ver={toolset_default}')
752 arglist
.append(argpair
)
754 return toolset_default
756 def _user_script_argument_toolset(env
, toolset_version
, user_argstr
):
758 matches
= [m
for m
in re_vcvars_toolset
.finditer(user_argstr
)]
763 debug('multiple toolset version declarations: MSVC_SCRIPT_ARGS=%s', repr(user_argstr
))
764 err_msg
= f
"multiple toolset version declarations: MSVC_SCRIPT_ARGS={user_argstr!r}"
765 raise MSVCArgumentError(err_msg
)
767 if not toolset_version
:
768 user_toolset
= matches
[0].group('toolset')
771 env_argstr
= env
.get('MSVC_TOOLSET_VERSION','')
772 debug('multiple toolset version declarations: MSVC_TOOLSET_VERSION=%s, MSVC_SCRIPT_ARGS=%s', repr(env_argstr
), repr(user_argstr
))
774 err_msg
= "multiple toolset version declarations: MSVC_TOOLSET_VERSION={} and MSVC_SCRIPT_ARGS={}".format(
775 repr(env_argstr
), repr(user_argstr
)
778 raise MSVCArgumentError(err_msg
)
780 def _msvc_script_argument_spectre_constraints(msvc
, toolset
, spectre_libs
, platform_def
):
782 if msvc
.vs_def
.vc_buildtools_def
.msvc_version_numeric
< VS2017
.vc_buildtools_def
.msvc_version_numeric
:
784 'invalid: msvc version constraint: %s < %s VS2017',
785 repr(msvc
.vs_def
.vc_buildtools_def
.msvc_version_numeric
),
786 repr(VS2017
.vc_buildtools_def
.msvc_version_numeric
)
788 err_msg
= "MSVC_SPECTRE_LIBS ({}) constraint violation: MSVC_VERSION {} < {} VS2017".format(
789 repr(spectre_libs
), repr(msvc
.version
), repr(VS2017
.vc_buildtools_def
.msvc_version
)
794 if toolset
.vc_buildtools_def
.msvc_version_numeric
< VS2017
.vc_buildtools_def
.msvc_version_numeric
:
796 'invalid: toolset version constraint: %s < %s VS2017',
797 repr(toolset
.vc_buildtools_def
.msvc_version_numeric
),
798 repr(VS2017
.vc_buildtools_def
.msvc_version_numeric
)
800 err_msg
= "MSVC_SPECTRE_LIBS ({}) constraint violation: toolset version {} < {} VS2017".format(
801 repr(spectre_libs
), repr(toolset
.version
), repr(VS2017
.vc_buildtools_def
.msvc_version
)
806 if platform_def
.is_uwp
:
808 'invalid: spectre_libs=%s and platform_type=%s',
809 repr(spectre_libs
), repr(platform_def
.vc_platform
)
811 err_msg
= "MSVC_SPECTRE_LIBS ({}) are not supported for platform type ({})".format(
812 repr(spectre_libs
), repr(platform_def
.vc_platform
)
818 def _msvc_toolset_version_spectre_path(vc_dir
, toolset_version
):
819 spectre_dir
= os
.path
.join(vc_dir
, "Tools", "MSVC", toolset_version
, "lib", "spectre")
822 def _msvc_script_argument_spectre(env
, msvc
, vc_dir
, toolset
, platform_def
, arglist
):
824 spectre_libs
= env
['MSVC_SPECTRE_LIBS']
825 debug('MSVC_VERSION=%s, MSVC_SPECTRE_LIBS=%s', repr(msvc
.version
), repr(spectre_libs
))
830 if spectre_libs
not in _ARGUMENT_BOOLEAN_TRUE
:
833 err_msg
= _msvc_script_argument_spectre_constraints(msvc
, toolset
, spectre_libs
, platform_def
)
835 raise MSVCArgumentError(err_msg
)
838 spectre_dir
= _msvc_toolset_version_spectre_path(vc_dir
, toolset
.version
)
839 if not os
.path
.exists(spectre_dir
):
841 'spectre libs: msvc_version=%s, toolset_version=%s, spectre_dir=%s',
842 repr(msvc
.version
), repr(toolset
.version
), repr(spectre_dir
)
844 err_msg
= "Spectre libraries not found for MSVC_VERSION {} toolset version {}".format(
845 repr(msvc
.version
), repr(toolset
.version
)
847 raise MSVCSpectreLibsNotFound(err_msg
)
849 spectre_arg
= 'spectre'
851 # spectre libs may not be installed for host/target
852 argpair
= (SortOrder
.SPECTRE
, f
'-vcvars_spectre_libs={spectre_arg}')
853 arglist
.append(argpair
)
857 def _user_script_argument_spectre(env
, spectre
, user_argstr
):
859 matches
= [m
for m
in re_vcvars_spectre
.finditer(user_argstr
)]
864 debug('multiple spectre declarations: MSVC_SCRIPT_ARGS=%s', repr(user_argstr
))
865 err_msg
= f
"multiple spectre declarations: MSVC_SCRIPT_ARGS={user_argstr!r}"
866 raise MSVCArgumentError(err_msg
)
871 env_argstr
= env
.get('MSVC_SPECTRE_LIBS','')
872 debug('multiple spectre declarations: MSVC_SPECTRE_LIBS=%s, MSVC_SCRIPT_ARGS=%s', repr(env_argstr
), repr(user_argstr
))
874 err_msg
= "multiple spectre declarations: MSVC_SPECTRE_LIBS={} and MSVC_SCRIPT_ARGS={}".format(
875 repr(env_argstr
), repr(user_argstr
)
878 raise MSVCArgumentError(err_msg
)
880 def _msvc_script_argument_user(env
, msvc
, arglist
):
882 # subst None -> empty string
883 script_args
= env
.subst('$MSVC_SCRIPT_ARGS')
884 debug('MSVC_VERSION=%s, MSVC_SCRIPT_ARGS=%s', repr(msvc
.version
), repr(script_args
))
889 if msvc
.vs_def
.vc_buildtools_def
.msvc_version_numeric
< VS2015
.vc_buildtools_def
.msvc_version_numeric
:
891 'invalid: msvc version constraint: %s < %s VS2015',
892 repr(msvc
.vs_def
.vc_buildtools_def
.msvc_version_numeric
),
893 repr(VS2015
.vc_buildtools_def
.msvc_version_numeric
)
895 err_msg
= "MSVC_SCRIPT_ARGS ({}) constraint violation: MSVC_VERSION {} < {} VS2015".format(
896 repr(script_args
), repr(msvc
.version
), repr(VS2015
.vc_buildtools_def
.msvc_version
)
898 raise MSVCArgumentError(err_msg
)
900 # user arguments are not validated
901 argpair
= (SortOrder
.USER
, script_args
)
902 arglist
.append(argpair
)
906 def _msvc_process_construction_variables(env
) -> bool:
908 for cache_variable
in [
909 _MSVC_FORCE_DEFAULT_TOOLSET
,
910 _MSVC_FORCE_DEFAULT_SDK
,
915 for env_variable
in [
917 'MSVC_TOOLSET_VERSION',
921 if env
.get(env_variable
, None) is not None:
926 def msvc_script_arguments_has_uwp(env
):
928 if not _msvc_process_construction_variables(env
):
931 uwp_app
= env
.get('MSVC_UWP_APP')
932 is_uwp
= bool(uwp_app
and uwp_app
in _ARGUMENT_BOOLEAN_TRUE_LEGACY
)
934 debug('is_uwp=%s', is_uwp
)
937 def msvc_script_arguments(env
, version
, vc_dir
, arg
=None):
939 arguments
= [arg
] if arg
else []
942 arglist_reverse
= False
944 msvc
= _msvc_version(version
)
946 if 'MSVC_SCRIPT_ARGS' in env
:
947 user_argstr
= _msvc_script_argument_user(env
, msvc
, arglist
)
951 if _msvc_process_construction_variables(env
):
953 target_arch
= env
.get('TARGET_ARCH')
957 if 'MSVC_UWP_APP' in env
:
958 uwp
= _msvc_script_argument_uwp(env
, msvc
, arglist
, target_arch
)
963 user_uwp
= _user_script_argument_uwp(env
, uwp
, user_argstr
)
967 is_uwp
= True if uwp
else False
968 platform_def
= WinSDK
.get_msvc_platform(is_uwp
)
970 # MSVC_TOOLSET_VERSION
972 if 'MSVC_TOOLSET_VERSION' in env
:
973 toolset_version
= _msvc_script_argument_toolset(env
, msvc
, vc_dir
, arglist
)
975 toolset_version
= None
978 user_toolset
= _user_script_argument_toolset(env
, toolset_version
, user_argstr
)
982 if not toolset_version
and not user_toolset
:
983 default_toolset
= _msvc_script_default_toolset(env
, msvc
, vc_dir
, arglist
, _MSVC_FORCE_DEFAULT_TOOLSET
)
984 if _MSVC_FORCE_DEFAULT_TOOLSET
:
985 toolset_version
= default_toolset
987 default_toolset
= None
991 elif toolset_version
:
992 toolset
= _toolset_version(toolset_version
, is_user
=True)
993 elif default_toolset
:
994 toolset
= _toolset_version(default_toolset
)
1000 if 'MSVC_SDK_VERSION' in env
:
1001 sdk_version
= _msvc_script_argument_sdk(env
, msvc
, toolset
, platform_def
, arglist
)
1006 user_sdk
= _user_script_argument_sdk(env
, sdk_version
, user_argstr
)
1010 if _MSVC_FORCE_DEFAULT_SDK
:
1011 if not sdk_version
and not user_sdk
:
1012 sdk_version
= _msvc_script_default_sdk(env
, msvc
, platform_def
, arglist
, _MSVC_FORCE_DEFAULT_SDK
)
1016 if 'MSVC_SPECTRE_LIBS' in env
:
1017 spectre
= _msvc_script_argument_spectre(env
, msvc
, vc_dir
, toolset
, platform_def
, arglist
)
1022 _user_script_argument_spectre(env
, spectre
, user_argstr
)
1024 if msvc
.vs_def
.vc_buildtools_def
.msvc_version
== '14.0':
1025 if user_uwp
and sdk_version
and len(arglist
) == 2:
1026 # VS2015 toolset argument order issue: SDK store => store SDK
1027 arglist_reverse
= True
1029 if len(arglist
) > 1:
1034 arguments
.extend([argpair
[-1] for argpair
in arglist
])
1035 argstr
= ' '.join(arguments
).strip()
1037 debug('arguments: %s', repr(argstr
))
1040 def _msvc_toolset_internal(msvc_version
, toolset_version
, vc_dir
):
1042 msvc
= _msvc_version(msvc_version
)
1044 toolset_vcvars
= _msvc_script_argument_toolset_vcvars(msvc
, toolset_version
, vc_dir
)
1046 return toolset_vcvars
1048 def _msvc_toolset_versions_internal(msvc_version
, vc_dir
, full
: bool=True, sxs
: bool=False):
1050 msvc
= _msvc_version(msvc_version
)
1052 if len(msvc
.vs_def
.vc_buildtools_all
) <= 1:
1055 toolset_versions
= []
1057 toolsets_sxs
, toolsets_full
= _msvc_version_toolsets(msvc
, vc_dir
)
1060 sxs_versions
= list(toolsets_sxs
.keys())
1061 sxs_versions
.sort(reverse
=True)
1062 toolset_versions
.extend(sxs_versions
)
1065 toolset_versions
.extend(toolsets_full
)
1067 return toolset_versions
1069 def _msvc_version_toolsets_internal(msvc_version
, vc_dir
):
1071 msvc
= _msvc_version(msvc_version
)
1073 toolsets_sxs
, toolsets_full
= _msvc_version_toolsets(msvc
, vc_dir
)
1075 return toolsets_sxs
, toolsets_full
1077 def _msvc_toolset_versions_spectre_internal(msvc_version
, vc_dir
):
1079 msvc
= _msvc_version(msvc_version
)
1081 if len(msvc
.vs_def
.vc_buildtools_all
) <= 1:
1084 _
, toolsets_full
= _msvc_version_toolsets(msvc
, vc_dir
)
1086 spectre_toolset_versions
= [
1088 for toolset_version
in toolsets_full
1089 if os
.path
.exists(_msvc_toolset_version_spectre_path(vc_dir
, toolset_version
))
1092 return spectre_toolset_versions
1094 def reset() -> None:
1096 _reset_have140_cache()
1097 _reset_toolset_cache()
1099 def verify() -> None:
1101 _verify_re_sdk_dispatch_map()