summaryrefslogtreecommitdiffstats
path: root/SCons/Tool
diff options
context:
space:
mode:
authorJoseph Brill <48932340+jcbrill@users.noreply.github.com>2022-06-20 20:53:31 (GMT)
committerJoseph Brill <48932340+jcbrill@users.noreply.github.com>2022-06-20 20:53:31 (GMT)
commit010c2ad46c32827b7ed8082ec11b83404a039faa (patch)
tree9616ac0aab43888a5ffe69ba002cd1d2e458b37d /SCons/Tool
parentdbd301878f8f7bb004658b25a62d57b48ee4c8a3 (diff)
downloadSCons-010c2ad46c32827b7ed8082ec11b83404a039faa.zip
SCons-010c2ad46c32827b7ed8082ec11b83404a039faa.tar.gz
SCons-010c2ad46c32827b7ed8082ec11b83404a039faa.tar.bz2
Refactor recent portions of vc.py into MSVC module
Diffstat (limited to 'SCons/Tool')
-rw-r--r--SCons/Tool/MSCommon/MSVC/Config.py284
-rw-r--r--SCons/Tool/MSCommon/MSVC/Dispatcher.py62
-rw-r--r--SCons/Tool/MSCommon/MSVC/Exceptions.py39
-rw-r--r--SCons/Tool/MSCommon/MSVC/NotFound.py132
-rw-r--r--SCons/Tool/MSCommon/MSVC/Registry.py110
-rw-r--r--SCons/Tool/MSCommon/MSVC/ScriptArguments.py733
-rw-r--r--SCons/Tool/MSCommon/MSVC/SetupEnvDefault.py235
-rw-r--r--SCons/Tool/MSCommon/MSVC/Util.py55
-rw-r--r--SCons/Tool/MSCommon/MSVC/WinSDK.py250
-rw-r--r--SCons/Tool/MSCommon/MSVC/__init__.py50
-rw-r--r--SCons/Tool/MSCommon/__init__.py7
-rw-r--r--SCons/Tool/MSCommon/vc.py1638
12 files changed, 1968 insertions, 1627 deletions
diff --git a/SCons/Tool/MSCommon/MSVC/Config.py b/SCons/Tool/MSCommon/MSVC/Config.py
new file mode 100644
index 0000000..476dcb3
--- /dev/null
+++ b/SCons/Tool/MSCommon/MSVC/Config.py
@@ -0,0 +1,284 @@
+# MIT License
+#
+# Copyright The SCons Foundation
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+"""
+Constants and initialized data structures for Microsoft Visual C/C++.
+"""
+
+from collections import (
+ namedtuple,
+)
+
+from . import Dispatcher
+
+Dispatcher.register_modulename(__name__)
+
+UNDEFINED = object()
+
+BOOLEAN_SYMBOLS = {}
+BOOLEAN_EXTERNAL = {}
+
+for bool, symbol_list, symbol_case_list in [
+ (False, (False, 0, '0', None, ''), ('False', 'No', 'F', 'N')),
+ (True, (True, 1, '1'), ('True', 'Yes', 'T', 'Y')),
+]:
+ BOOLEAN_SYMBOLS[bool] = list(symbol_list)
+ for symbol in symbol_case_list:
+ BOOLEAN_SYMBOLS[bool].extend([symbol, symbol.lower(), symbol.upper()])
+
+ for symbol in BOOLEAN_SYMBOLS[bool]:
+ BOOLEAN_EXTERNAL[symbol] = bool
+
+MSVC_RUNTIME_DEFINITION = namedtuple('MSVCRuntime', [
+ 'vc_runtime',
+ 'vc_runtime_numeric',
+ 'vc_runtime_alias_list',
+ 'vc_runtime_vsdef_list',
+])
+
+MSVC_RUNTIME_DEFINITION_LIST = []
+
+MSVC_RUNTIME_INTERNAL = {}
+MSVC_RUNTIME_EXTERNAL = {}
+
+for vc_runtime, vc_runtime_numeric, vc_runtime_alias_list in [
+ ('140', 140, ['ucrt']),
+ ('120', 120, ['msvcr120']),
+ ('110', 110, ['msvcr110']),
+ ('100', 100, ['msvcr100']),
+ ('90', 90, ['msvcr90']),
+ ('80', 80, ['msvcr80']),
+ ('71', 71, ['msvcr71']),
+ ('70', 70, ['msvcr70']),
+ ('60', 60, ['msvcrt']),
+]:
+ vc_runtime_def = MSVC_RUNTIME_DEFINITION(
+ vc_runtime = vc_runtime,
+ vc_runtime_numeric = vc_runtime_numeric,
+ vc_runtime_alias_list = vc_runtime_alias_list,
+ vc_runtime_vsdef_list = [],
+ )
+
+ MSVC_RUNTIME_DEFINITION_LIST.append(vc_runtime_def)
+
+ MSVC_RUNTIME_INTERNAL[vc_runtime] = vc_runtime_def
+ MSVC_RUNTIME_EXTERNAL[vc_runtime] = vc_runtime_def
+
+ for vc_runtime_alias in vc_runtime_alias_list:
+ MSVC_RUNTIME_EXTERNAL[vc_runtime_alias] = vc_runtime_def
+
+MSVC_BUILDTOOLS_DEFINITION = namedtuple('MSVCBuildtools', [
+ 'vc_buildtools',
+ 'vc_buildtools_numeric',
+ 'vc_version',
+ 'vc_version_numeric',
+ 'cl_version',
+ 'cl_version_numeric',
+ 'vc_runtime_def',
+])
+
+MSVC_BUILDTOOLS_DEFINITION_LIST = []
+
+MSVC_BUILDTOOLS_INTERNAL = {}
+MSVC_BUILDTOOLS_EXTERNAL = {}
+
+VC_VERSION_MAP = {}
+
+for vc_buildtools, vc_version, cl_version, vc_runtime in [
+ ('v143', '14.3', '19.3', '140'),
+ ('v142', '14.2', '19.2', '140'),
+ ('v141', '14.1', '19.1', '140'),
+ ('v140', '14.0', '19.0', '140'),
+ ('v120', '12.0', '18.0', '120'),
+ ('v110', '11.0', '17.0', '110'),
+ ('v100', '10.0', '16.0', '100'),
+ ('v90', '9.0', '15.0', '90'),
+ ('v80', '8.0', '14.0', '80'),
+ ('v71', '7.1', '13.1', '71'),
+ ('v70', '7.0', '13.0', '70'),
+ ('v60', '6.0', '12.0', '60'),
+]:
+
+ vc_runtime_def = MSVC_RUNTIME_INTERNAL[vc_runtime]
+
+ vc_buildtools_def = MSVC_BUILDTOOLS_DEFINITION(
+ vc_buildtools = vc_buildtools,
+ vc_buildtools_numeric = int(vc_buildtools[1:]),
+ vc_version = vc_version,
+ vc_version_numeric = float(vc_version),
+ cl_version = cl_version,
+ cl_version_numeric = float(cl_version),
+ vc_runtime_def = vc_runtime_def,
+ )
+
+ MSVC_BUILDTOOLS_DEFINITION_LIST.append(vc_buildtools_def)
+
+ MSVC_BUILDTOOLS_INTERNAL[vc_buildtools] = vc_buildtools_def
+ MSVC_BUILDTOOLS_EXTERNAL[vc_buildtools] = vc_buildtools_def
+ MSVC_BUILDTOOLS_EXTERNAL[vc_version] = vc_buildtools_def
+
+ VC_VERSION_MAP[vc_version] = vc_buildtools_def
+
+MSVS_VERSION_INTERNAL = {}
+MSVS_VERSION_EXTERNAL = {}
+
+MSVC_VERSION_INTERNAL = {}
+MSVC_VERSION_EXTERNAL = {}
+
+MSVS_VERSION_MAJOR_MAP = {}
+
+CL_VERSION_MAP = {}
+
+MSVC_SDK_VERSIONS = set()
+
+VISUALSTUDIO_DEFINITION = namedtuple('VisualStudioDefinition', [
+ 'vs_product',
+ 'vs_product_alias_list',
+ 'vs_version',
+ 'vs_version_major',
+ 'vs_envvar',
+ 'vs_express',
+ 'vs_lookup',
+ 'vc_sdk_versions',
+ 'vc_ucrt_versions',
+ 'vc_uwp',
+ 'vc_buildtools_def',
+ 'vc_buildtools_all',
+])
+
+VISUALSTUDIO_DEFINITION_LIST = []
+
+VS_PRODUCT_ALIAS = {
+ '1998': ['6']
+}
+
+# vs_envvar: VisualStudioVersion defined in environment for MSVS 2012 and later
+# MSVS 2010 and earlier cl_version -> vs_def is a 1:1 mapping
+# SDK attached to product or buildtools?
+for vs_product, vs_version, vs_envvar, vs_express, vs_lookup, vc_sdk, vc_ucrt, vc_uwp, vc_buildtools_all in [
+ ('2022', '17.0', True, False, 'vswhere' , ['10.0', '8.1'], ['10'], 'uwp', ['v143', 'v142', 'v141', 'v140']),
+ ('2019', '16.0', True, False, 'vswhere' , ['10.0', '8.1'], ['10'], 'uwp', ['v142', 'v141', 'v140']),
+ ('2017', '15.0', True, True, 'vswhere' , ['10.0', '8.1'], ['10'], 'uwp', ['v141', 'v140']),
+ ('2015', '14.0', True, True, 'registry', ['10.0', '8.1'], ['10'], 'store', ['v140']),
+ ('2013', '12.0', True, True, 'registry', None, None, None, ['v120']),
+ ('2012', '11.0', True, True, 'registry', None, None, None, ['v110']),
+ ('2010', '10.0', False, True, 'registry', None, None, None, ['v100']),
+ ('2008', '9.0', False, True, 'registry', None, None, None, ['v90']),
+ ('2005', '8.0', False, True, 'registry', None, None, None, ['v80']),
+ ('2003', '7.1', False, False, 'registry', None, None, None, ['v71']),
+ ('2002', '7.0', False, False, 'registry', None, None, None, ['v70']),
+ ('1998', '6.0', False, False, 'registry', None, None, None, ['v60']),
+]:
+
+ vs_version_major = vs_version.split('.')[0]
+
+ vc_buildtools_def = MSVC_BUILDTOOLS_INTERNAL[vc_buildtools_all[0]]
+
+ vs_def = VISUALSTUDIO_DEFINITION(
+ vs_product = vs_product,
+ vs_product_alias_list = [],
+ vs_version = vs_version,
+ vs_version_major = vs_version_major,
+ vs_envvar = vs_envvar,
+ vs_express = vs_express,
+ vs_lookup = vs_lookup,
+ vc_sdk_versions = vc_sdk,
+ vc_ucrt_versions = vc_ucrt,
+ vc_uwp = vc_uwp,
+ vc_buildtools_def = vc_buildtools_def,
+ vc_buildtools_all = vc_buildtools_all,
+ )
+
+ VISUALSTUDIO_DEFINITION_LIST.append(vs_def)
+
+ vc_buildtools_def.vc_runtime_def.vc_runtime_vsdef_list.append(vs_def)
+
+ MSVS_VERSION_INTERNAL[vs_product] = vs_def
+ MSVS_VERSION_EXTERNAL[vs_product] = vs_def
+ MSVS_VERSION_EXTERNAL[vs_version] = vs_def
+
+ MSVC_VERSION_INTERNAL[vc_buildtools_def.vc_version] = vs_def
+ MSVC_VERSION_EXTERNAL[vs_product] = vs_def
+ MSVC_VERSION_EXTERNAL[vc_buildtools_def.vc_version] = vs_def
+ MSVC_VERSION_EXTERNAL[vc_buildtools_def.vc_buildtools] = vs_def
+
+ if vs_product in VS_PRODUCT_ALIAS:
+ for vs_product_alias in VS_PRODUCT_ALIAS[vs_product]:
+ vs_def.vs_product_alias_list.append(vs_product_alias)
+ MSVS_VERSION_EXTERNAL[vs_product_alias] = vs_def
+ MSVC_VERSION_EXTERNAL[vs_product_alias] = vs_def
+
+ MSVS_VERSION_MAJOR_MAP[vs_version_major] = vs_def
+
+ CL_VERSION_MAP[vc_buildtools_def.cl_version] = vs_def
+
+ if not vc_sdk:
+ continue
+
+ MSVC_SDK_VERSIONS.update(vc_sdk)
+
+# convert string version set to string version list ranked in descending order
+MSVC_SDK_VERSIONS = [str(f) for f in sorted([float(s) for s in MSVC_SDK_VERSIONS], reverse=True)]
+
+MSVS_VERSION_LEGACY = {}
+MSVC_VERSION_LEGACY = {}
+
+for vdict in (MSVS_VERSION_EXTERNAL, MSVC_VERSION_INTERNAL):
+ for key, vs_def in vdict.items():
+ if key not in MSVS_VERSION_LEGACY:
+ MSVS_VERSION_LEGACY[key] = vs_def
+ MSVC_VERSION_LEGACY[key] = vs_def
+
+# MSVC_NOTFOUND_POLICY definition:
+# error: raise exception
+# warning: issue warning and continue
+# ignore: continue
+
+MSVC_NOTFOUND_POLICY_DEFINITION = namedtuple('MSVCNotFoundPolicyDefinition', [
+ 'value',
+ 'symbol',
+])
+
+MSVC_NOTFOUND_DEFINITION_LIST = []
+
+MSVC_NOTFOUND_POLICY_INTERNAL = {}
+MSVC_NOTFOUND_POLICY_EXTERNAL = {}
+
+for policy_value, policy_symbol_list in [
+ (True, ['Error', 'Exception']),
+ (False, ['Warning', 'Warn']),
+ (None, ['Ignore', 'Suppress']),
+]:
+
+ policy_symbol = policy_symbol_list[0].lower()
+ policy_def = MSVC_NOTFOUND_POLICY_DEFINITION(policy_value, policy_symbol)
+
+ MSVC_NOTFOUND_DEFINITION_LIST.append(vs_def)
+
+ MSVC_NOTFOUND_POLICY_INTERNAL[policy_symbol] = policy_def
+
+ for policy_symbol in policy_symbol_list:
+ MSVC_NOTFOUND_POLICY_EXTERNAL[policy_symbol.lower()] = policy_def
+ MSVC_NOTFOUND_POLICY_EXTERNAL[policy_symbol] = policy_def
+ MSVC_NOTFOUND_POLICY_EXTERNAL[policy_symbol.upper()] = policy_def
+
diff --git a/SCons/Tool/MSCommon/MSVC/Dispatcher.py b/SCons/Tool/MSCommon/MSVC/Dispatcher.py
new file mode 100644
index 0000000..ebcd704
--- /dev/null
+++ b/SCons/Tool/MSCommon/MSVC/Dispatcher.py
@@ -0,0 +1,62 @@
+# MIT License
+#
+# Copyright The SCons Foundation
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+"""
+Internal method dispatcher for Microsoft Visual C/C++.
+"""
+
+import sys
+
+from ..common import (
+ debug,
+)
+
+_refs = []
+
+def register_class(ref):
+ _refs.append(ref)
+
+def register_modulename(modname):
+ module = sys.modules[modname]
+ _refs.append(module)
+
+def reset():
+ debug('')
+ for ref in _refs:
+ for method in ['reset', '_reset']:
+ if not hasattr(ref, method) or not callable(getattr(ref, method, None)):
+ continue
+ debug('call %s.%s()', ref.__name__, method)
+ func = getattr(ref, method)
+ func()
+
+def verify():
+ debug('')
+ for ref in _refs:
+ for method in ['verify', '_verify']:
+ if not hasattr(ref, method) or not callable(getattr(ref, method, None)):
+ continue
+ debug('call %s.%s()', ref.__name__, method)
+ func = getattr(ref, method)
+ func()
+
diff --git a/SCons/Tool/MSCommon/MSVC/Exceptions.py b/SCons/Tool/MSCommon/MSVC/Exceptions.py
new file mode 100644
index 0000000..7a61ec5
--- /dev/null
+++ b/SCons/Tool/MSCommon/MSVC/Exceptions.py
@@ -0,0 +1,39 @@
+# MIT License
+#
+# Copyright The SCons Foundation
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+"""
+Exceptions for Microsoft Visual C/C++.
+"""
+
+class VisualCException(Exception):
+ pass
+
+class MSVCVersionNotFound(VisualCException):
+ pass
+
+class MSVCInternalError(VisualCException):
+ pass
+
+class MSVCArgumentError(VisualCException):
+ pass
+
diff --git a/SCons/Tool/MSCommon/MSVC/NotFound.py b/SCons/Tool/MSCommon/MSVC/NotFound.py
new file mode 100644
index 0000000..7abe5ad
--- /dev/null
+++ b/SCons/Tool/MSCommon/MSVC/NotFound.py
@@ -0,0 +1,132 @@
+# MIT License
+#
+# Copyright The SCons Foundation
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+"""
+Microsoft Visual C/C++ not found policy.
+
+Notes:
+ * As implemented, the default is that a warning is issued. This can
+ be changed globally via the function set_msvc_notfound_policy and/or
+ through the environment via the MSVC_NOTFOUND_POLICY variable.
+"""
+
+import SCons.Warnings
+
+from ..common import (
+ debug,
+)
+
+from . import Dispatcher
+from . import Config
+
+from .Exceptions import (
+ MSVCVersionNotFound,
+)
+
+Dispatcher.register_modulename(__name__)
+
+_MSVC_NOTFOUND_POLICY_DEF = Config.MSVC_NOTFOUND_POLICY_INTERNAL['warning']
+
+def _msvc_notfound_policy_lookup(symbol):
+
+ try:
+ notfound_policy_def = Config.MSVC_NOTFOUND_POLICY_EXTERNAL[symbol]
+ except KeyError:
+ err_msg = "Value specified for MSVC_NOTFOUND_POLICY is not supported: {}.\n" \
+ " Valid values are: {}".format(
+ repr(symbol),
+ ', '.join([repr(s) for s in Config.MSVC_NOTFOUND_POLICY_EXTERNAL.keys()])
+ )
+ raise ValueError(err_msg)
+
+ return notfound_policy_def
+
+def set_msvc_notfound_policy(MSVC_NOTFOUND_POLICY=None):
+ """ Set the default policy when MSVC is not found.
+
+ Args:
+ MSVC_NOTFOUND_POLICY:
+ string representing the policy behavior
+ when MSVC is not found or None
+
+ Returns:
+ The previous policy is returned when the MSVC_NOTFOUND_POLICY argument
+ is not None. The active policy is returned when the MSVC_NOTFOUND_POLICY
+ argument is None.
+
+ """
+ global _MSVC_NOTFOUND_POLICY_DEF
+
+ prev_policy = _MSVC_NOTFOUND_POLICY_DEF.symbol
+
+ policy = MSVC_NOTFOUND_POLICY
+ if policy is not None:
+ _MSVC_NOTFOUND_POLICY_DEF = _msvc_notfound_policy_lookup(policy)
+
+ debug(
+ 'prev_policy=%s, set_policy=%s, policy.symbol=%s, policy.value=%s',
+ repr(prev_policy), repr(policy),
+ repr(_MSVC_NOTFOUND_POLICY_DEF.symbol), repr(_MSVC_NOTFOUND_POLICY_DEF.value)
+ )
+
+ return prev_policy
+
+def get_msvc_notfound_policy():
+ """Return the active policy when MSVC is not found."""
+ debug(
+ 'policy.symbol=%s, policy.value=%s',
+ repr(_MSVC_NOTFOUND_POLICY_DEF.symbol), repr(_MSVC_NOTFOUND_POLICY_DEF.value)
+ )
+ return _MSVC_NOTFOUND_POLICY_DEF.symbol
+
+def policy_handler(env, msg):
+
+ if env and 'MSVC_NOTFOUND_POLICY' in env:
+ # environment setting
+ notfound_policy_src = 'environment'
+ policy = env['MSVC_NOTFOUND_POLICY']
+ if policy is not None:
+ # user policy request
+ notfound_policy_def = _msvc_notfound_policy_lookup(policy)
+ else:
+ # active global setting
+ notfound_policy_def = _MSVC_NOTFOUND_POLICY_DEF
+ else:
+ # active global setting
+ notfound_policy_src = 'default'
+ policy = None
+ notfound_policy_def = _MSVC_NOTFOUND_POLICY_DEF
+
+ debug(
+ 'source=%s, set_policy=%s, policy.symbol=%s, policy.value=%s',
+ notfound_policy_src, repr(policy), repr(notfound_policy_def.symbol), repr(notfound_policy_def.value)
+ )
+
+ if notfound_policy_def.value is None:
+ # ignore
+ pass
+ elif notfound_policy_def.value:
+ raise MSVCVersionNotFound(msg)
+ else:
+ SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, msg)
+
diff --git a/SCons/Tool/MSCommon/MSVC/Registry.py b/SCons/Tool/MSCommon/MSVC/Registry.py
new file mode 100644
index 0000000..848b125
--- /dev/null
+++ b/SCons/Tool/MSCommon/MSVC/Registry.py
@@ -0,0 +1,110 @@
+# MIT License
+#
+# Copyright The SCons Foundation
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+"""
+Windows registry functions for Microsoft Visual C/C++.
+"""
+
+import os
+
+from SCons.Util import (
+ HKEY_LOCAL_MACHINE,
+ HKEY_CURRENT_USER,
+ HKEY_LOCAL_MACHINE,
+ HKEY_CURRENT_USER,
+)
+
+from .. common import (
+ debug,
+ read_reg,
+)
+
+from . import Dispatcher
+from . import Util
+
+Dispatcher.register_modulename(__name__)
+
+def read_value(hkey, subkey_valname):
+ try:
+ rval = read_reg(subkey_valname, hkroot=hkey)
+ except OSError:
+ debug('OSError: hkey=%s, subkey=%s', repr(hkey), repr(subkey_valname))
+ return None
+ except IndexError:
+ debug('IndexError: hkey=%s, subkey=%s', repr(hkey), repr(subkey_valname))
+ return None
+ debug('hkey=%s, subkey=%s, rval=%s', repr(hkey), repr(subkey_valname), repr(rval))
+ return rval
+
+def registry_query_path(key, val, suffix):
+ extval = val + '\\' + suffix if suffix else val
+ qpath = read_value(key, extval)
+ if qpath and os.path.exists(qpath):
+ qpath = Util.process_path(qpath)
+ else:
+ qpath = None
+ return (qpath, key, val, extval)
+
+REG_SOFTWARE_MICROSOFT = [
+ (HKEY_LOCAL_MACHINE, r'Software\Wow6432Node\Microsoft'),
+ (HKEY_CURRENT_USER, r'Software\Wow6432Node\Microsoft'), # SDK queries
+ (HKEY_LOCAL_MACHINE, r'Software\Microsoft'),
+ (HKEY_CURRENT_USER, r'Software\Microsoft'),
+]
+
+def microsoft_query_paths(suffix, usrval=None):
+ paths = []
+ records = []
+ for key, val in REG_SOFTWARE_MICROSOFT:
+ extval = val + '\\' + suffix if suffix else val
+ qpath = read_value(key, extval)
+ if qpath and os.path.exists(qpath):
+ qpath = Util.process_path(qpath)
+ if qpath not in paths:
+ paths.append(qpath)
+ records.append((qpath, key, val, extval, usrval))
+ return records
+
+def microsoft_query_keys(suffix, usrval=None):
+ records = []
+ for key, val in REG_SOFTWARE_MICROSOFT:
+ extval = val + '\\' + suffix if suffix else val
+ rval = read_value(key, extval)
+ if rval:
+ records.append((key, val, extval, usrval))
+ return records
+
+def microsoft_sdks(version):
+ return '\\'.join([r'Microsoft SDKs\Windows', 'v' + version, r'InstallationFolder'])
+
+def sdk_query_paths(version):
+ q = microsoft_sdks(version)
+ return microsoft_query_paths(q)
+
+def windows_kits(version):
+ return r'Windows Kits\Installed Roots\KitsRoot' + version
+
+def windows_kit_query_paths(version):
+ q = windows_kits(version)
+ return microsoft_query_paths(q)
+
diff --git a/SCons/Tool/MSCommon/MSVC/ScriptArguments.py b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
new file mode 100644
index 0000000..324f8be
--- /dev/null
+++ b/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
@@ -0,0 +1,733 @@
+# MIT License
+#
+# Copyright The SCons Foundation
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+"""
+Batch file argument functions for Microsoft Visual C/C++.
+"""
+
+import os
+import re
+import enum
+
+from collections import (
+ namedtuple,
+)
+
+from ..common import (
+ debug,
+)
+
+from . import Dispatcher
+from . import Util
+from . import Config
+from . import WinSDK
+
+from .Exceptions import (
+ MSVCInternalError,
+ MSVCArgumentError,
+)
+
+Dispatcher.register_modulename(__name__)
+
+# TODO: verify SDK 10 version folder names 10.0.XXXXX.0 {1,3} last?
+re_sdk_version_100 = re.compile(r'^10[.][0-9][.][0-9]{5}[.][0-9]{1}$')
+re_sdk_version_81 = re.compile(r'^8[.]1$')
+
+re_sdk_dispatch_map = {
+ '10.0': re_sdk_version_100,
+ '8.1': re_sdk_version_81,
+}
+
+def _verify_re_sdk_dispatch_map():
+ debug('')
+ for sdk_version in Config.MSVC_SDK_VERSIONS:
+ if sdk_version in re_sdk_dispatch_map:
+ continue
+ err_msg = 'sdk version {} not in re_sdk_dispatch_map'.format(sdk_version)
+ raise MSVCInternalError(err_msg)
+ return None
+
+# capture msvc version
+re_toolset_version = re.compile(r'^(?P<version>[1-9][0-9]?[.][0-9])[0-9.]*$', re.IGNORECASE)
+
+re_toolset_full = re.compile(r'''^(?:
+ (?:[1-9][0-9][.][0-9]{1,2})| # XX.Y - XX.YY
+ (?:[1-9][0-9][.][0-9]{2}[.][0-9]{1,5}) # XX.YY.Z - XX.YY.ZZZZZ
+)$''', re.VERBOSE)
+
+re_toolset_140 = re.compile(r'''^(?:
+ (?:14[.]0{1,2})| # 14.0 - 14.00
+ (?:14[.]0{2}[.]0{1,5}) # 14.00.0 - 14.00.00000
+)$''', re.VERBOSE)
+
+# valid SxS formats will be matched with re_toolset_full: match 3 '.' format
+re_toolset_sxs = re.compile(r'^[1-9][0-9][.][0-9]{2}[.][0-9]{2}[.][0-9]{1,2}$')
+
+# MSVC_SCRIPT_ARGS
+re_vcvars_uwp = re.compile(r'(?:(?<!\S)|^)(?P<uwp>(?:uwp|store))(?:(?!\S)|$)',re.IGNORECASE)
+re_vcvars_sdk = re.compile(r'(?:(?<!\S)|^)(?P<sdk>(?:[1-9][0-9]*[.]\S*))(?:(?!\S)|$)',re.IGNORECASE)
+re_vcvars_toolset = re.compile(r'(?:(?<!\S)|^)(?P<toolset_arg>(?:[-]{1,2}|[/])vcvars_ver[=](?P<toolset>\S*))(?:(?!\S)|$)', re.IGNORECASE)
+re_vcvars_spectre = re.compile(r'(?:(?<!\S)|^)(?P<spectre_arg>(?:[-]{1,2}|[/])vcvars_spectre_libs[=](?P<spectre>\S*))(?:(?!\S)|$)',re.IGNORECASE)
+
+# Force default sdk argument
+MSVC_FORCE_DEFAULT_SDK = False
+
+# Force default toolset argument
+MSVC_FORCE_DEFAULT_TOOLSET = False
+
+# MSVC batch file arguments:
+#
+# VS2022: UWP, SDK, TOOLSET, SPECTRE
+# VS2019: UWP, SDK, TOOLSET, SPECTRE
+# VS2017: UWP, SDK, TOOLSET, SPECTRE
+# VS2015: UWP, SDK
+#
+# MSVC_SCRIPT_ARGS: VS2015+
+#
+# MSVC_UWP_APP: VS2015+
+# MSVC_SDK_VERSION: VS2015+
+# MSVC_TOOLSET_VERSION: VS2017+
+# MSVC_SPECTRE_LIBS: VS2017+
+
+@enum.unique
+class SortOrder(enum.IntEnum):
+ ARCH = 0 # arch
+ UWP = 1 # MSVC_UWP_APP
+ SDK = 2 # MSVC_SDK_VERSION
+ TOOLSET = 3 # MSVC_TOOLSET_VERSION
+ SPECTRE = 4 # MSVC_SPECTRE_LIBS
+ USER = 5 # MSVC_SCRIPT_ARGS
+
+VS2019 = Config.MSVS_VERSION_INTERNAL['2019']
+VS2017 = Config.MSVS_VERSION_INTERNAL['2017']
+VS2015 = Config.MSVS_VERSION_INTERNAL['2015']
+
+MSVC_VERSION_ARGS_DEFINITION = namedtuple('MSVCVersionArgsDefinition', [
+ 'version', # fully qualified msvc version (e.g., '14.1Exp')
+ 'vs_def',
+])
+
+def _msvc_version(version):
+
+ verstr = Util.get_version_prefix(version)
+ vs_def = Config.MSVC_VERSION_INTERNAL[verstr]
+
+ version_args = MSVC_VERSION_ARGS_DEFINITION(
+ version = version,
+ vs_def = vs_def,
+ )
+
+ return version_args
+
+def _msvc_script_argument_uwp(env, msvc, arglist):
+
+ uwp_app = env['MSVC_UWP_APP']
+ debug('MSVC_VERSION=%s, MSVC_UWP_APP=%s', repr(msvc.version), repr(uwp_app))
+
+ if not uwp_app:
+ return None
+
+ if uwp_app not in Config.BOOLEAN_SYMBOLS[True]:
+ return None
+
+ if msvc.vs_def.vc_buildtools_def.vc_version_numeric < VS2015.vc_buildtools_def.vc_version_numeric:
+ debug(
+ 'invalid: msvc version constraint: %s < %s VS2015',
+ repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric),
+ repr(VS2015.vc_buildtools_def.vc_version_numeric)
+ )
+ err_msg = "MSVC_UWP_APP ({}) constraint violation: MSVC_VERSION {} < {} VS2015".format(
+ repr(uwp_app), repr(msvc.version), repr(VS2015.vc_buildtools_def.vc_version)
+ )
+ raise MSVCArgumentError(err_msg)
+
+ # VS2017+ rewrites uwp => store for 14.0 toolset
+ uwp_arg = msvc.vs_def.vc_uwp
+
+ # store/uwp may not be fully installed
+ argpair = (SortOrder.UWP, uwp_arg)
+ arglist.append(argpair)
+
+ return uwp_arg
+
+def _user_script_argument_uwp(env, uwp, user_argstr):
+
+ matches = [m for m in re_vcvars_uwp.finditer(user_argstr)]
+ if not matches:
+ return None
+
+ if len(matches) > 1:
+ debug('multiple uwp declarations: MSVC_SCRIPT_ARGS=%s', repr(user_argstr))
+ err_msg = "multiple uwp declarations: MSVC_SCRIPT_ARGS={}".format(repr(user_argstr))
+ raise MSVCArgumentError(err_msg)
+
+ if not uwp:
+ return None
+
+ env_argstr = env.get('MSVC_UWP_APP','')
+ debug('multiple uwp declarations: MSVC_UWP_APP=%s, MSVC_SCRIPT_ARGS=%s', repr(env_argstr), repr(user_argstr))
+
+ err_msg = "multiple uwp declarations: MSVC_UWP_APP={} and MSVC_SCRIPT_ARGS={}".format(
+ repr(env_argstr), repr(user_argstr)
+ )
+
+ raise MSVCArgumentError(err_msg)
+
+def _msvc_script_argument_sdk_constraints(msvc, sdk_version):
+
+ if msvc.vs_def.vc_buildtools_def.vc_version_numeric < VS2015.vc_buildtools_def.vc_version_numeric:
+ debug(
+ 'invalid: msvc_version constraint: %s < %s VS2015',
+ repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric),
+ repr(VS2015.vc_buildtools_def.vc_version_numeric)
+ )
+ err_msg = "MSVC_SDK_VERSION ({}) constraint violation: MSVC_VERSION {} < {} VS2015".format(
+ repr(sdk_version), repr(msvc.version), repr(VS2015.vc_buildtools_def.vc_version)
+ )
+ return err_msg
+
+ for msvc_sdk_version in msvc.vs_def.vc_sdk_versions:
+ re_sdk_version = re_sdk_dispatch_map[msvc_sdk_version]
+ if re_sdk_version.match(sdk_version):
+ debug('valid: sdk_version=%s', repr(sdk_version))
+ return None
+
+ debug('invalid: method exit: sdk_version=%s', repr(sdk_version))
+ err_msg = "MSVC_SDK_VERSION ({}) is not supported".format(repr(sdk_version))
+ return err_msg
+
+def _msvc_script_argument_sdk(env, msvc, platform_type, arglist):
+
+ sdk_version = env['MSVC_SDK_VERSION']
+ debug(
+ 'MSVC_VERSION=%s, MSVC_SDK_VERSION=%s, platform_type=%s',
+ repr(msvc.version), repr(sdk_version), repr(platform_type)
+ )
+
+ if not sdk_version:
+ return None
+
+ err_msg = _msvc_script_argument_sdk_constraints(msvc, sdk_version)
+ if err_msg:
+ raise MSVCArgumentError(err_msg)
+
+ sdk_list = WinSDK.get_sdk_version_list(msvc.vs_def.vc_sdk_versions, platform_type)
+
+ if sdk_version not in sdk_list:
+ err_msg = "MSVC_SDK_VERSION {} not found for platform type {}".format(
+ repr(sdk_version), repr(platform_type)
+ )
+ raise MSVCArgumentError(err_msg)
+
+ argpair = (SortOrder.SDK, sdk_version)
+ arglist.append(argpair)
+
+ return sdk_version
+
+def _msvc_script_default_sdk(env, msvc, platform_type, arglist):
+
+ if msvc.vs_def.vc_buildtools_def.vc_version_numeric < VS2015.vc_buildtools_def.vc_version_numeric:
+ return None
+
+ sdk_list = WinSDK.get_sdk_version_list(msvc.vs_def.vc_sdk_versions, platform_type)
+ if not len(sdk_list):
+ return None
+
+ sdk_default = sdk_list[0]
+
+ debug(
+ 'MSVC_VERSION=%s, sdk_default=%s, platform_type=%s',
+ repr(msvc.version), repr(sdk_default), repr(platform_type)
+ )
+
+ argpair = (SortOrder.SDK, sdk_default)
+ arglist.append(argpair)
+
+ return sdk_default
+
+def _user_script_argument_sdk(env, sdk_version, user_argstr):
+
+ matches = [m for m in re_vcvars_sdk.finditer(user_argstr)]
+ if not matches:
+ return None
+
+ if len(matches) > 1:
+ debug('multiple sdk version declarations: MSVC_SCRIPT_ARGS=%s', repr(user_argstr))
+ err_msg = "multiple sdk version declarations: MSVC_SCRIPT_ARGS={}".format(repr(user_argstr))
+ raise MSVCArgumentError(err_msg)
+
+ if not sdk_version:
+ user_sdk = matches[0].group('sdk')
+ return user_sdk
+
+ env_argstr = env.get('MSVC_SDK_VERSION','')
+ debug('multiple sdk version declarations: MSVC_SDK_VERSION=%s, MSVC_SCRIPT_ARGS=%s', repr(env_argstr), repr(user_argstr))
+
+ err_msg = "multiple sdk version declarations: MSVC_SDK_VERSION={} and MSVC_SCRIPT_ARGS={}".format(
+ repr(env_argstr), repr(user_argstr)
+ )
+
+ raise MSVCArgumentError(err_msg)
+
+def _msvc_read_toolset_file(msvc, filename):
+ toolset_version = None
+ try:
+ with open(filename) as f:
+ toolset_version = f.readlines()[0].strip()
+ debug(
+ 'msvc_version=%s, filename=%s, toolset_version=%s',
+ repr(msvc.version), repr(filename), repr(toolset_version)
+ )
+ except OSError:
+ debug('OSError: msvc_version=%s, filename=%s', repr(msvc.version), repr(filename))
+ except IndexError:
+ debug('IndexError: msvc_version=%s, filename=%s', repr(msvc.version), repr(filename))
+ return toolset_version
+
+def _msvc_read_toolset_folders(msvc, vc_dir):
+
+ toolsets_sxs = {}
+ toolsets_full = []
+
+ build_dir = os.path.join(vc_dir, "Auxiliary", "Build")
+ sxs_toolsets = [f.name for f in os.scandir(build_dir) if f.is_dir()]
+ for sxs_toolset in sxs_toolsets:
+ filename = 'Microsoft.VCToolsVersion.{}.txt'.format(sxs_toolset)
+ filepath = os.path.join(build_dir, sxs_toolset, filename)
+ debug('sxs toolset: check file=%s', repr(filepath))
+ if os.path.exists(filepath):
+ toolset_version = _msvc_read_toolset_file(msvc, filepath)
+ if not toolset_version:
+ continue
+ toolsets_sxs[sxs_toolset] = toolset_version
+ debug(
+ 'sxs toolset: msvc_version=%s, sxs_version=%s, toolset_version=%s',
+ repr(msvc.version), repr(sxs_toolset), toolset_version
+ )
+
+ toolset_dir = os.path.join(vc_dir, "Tools", "MSVC")
+ toolsets = [f.name for f in os.scandir(toolset_dir) if f.is_dir()]
+ for toolset_version in toolsets:
+ binpath = os.path.join(toolset_dir, toolset_version, "bin")
+ debug('toolset: check binpath=%s', repr(binpath))
+ if os.path.exists(binpath):
+ toolsets_full.append(toolset_version)
+ debug(
+ 'toolset: msvc_version=%s, toolset_version=%s',
+ repr(msvc.version), repr(toolset_version)
+ )
+
+ toolsets_full.sort(reverse=True)
+ debug('msvc_version=%s, toolsets=%s', repr(msvc.version), repr(toolsets_full))
+
+ return toolsets_sxs, toolsets_full
+
+def _msvc_read_toolset_default(msvc, vc_dir):
+
+ build_dir = os.path.join(vc_dir, "Auxiliary", "Build")
+
+ # VS2019+
+ filename = "Microsoft.VCToolsVersion.{}.default.txt".format(msvc.vs_def.vc_buildtools_def.vc_buildtools)
+ filepath = os.path.join(build_dir, filename)
+
+ debug('default toolset: check file=%s', repr(filepath))
+ if os.path.exists(filepath):
+ toolset_buildtools = _msvc_read_toolset_file(msvc, filepath)
+ if toolset_buildtools:
+ return toolset_buildtools
+
+ # VS2017+
+ filename = "Microsoft.VCToolsVersion.default.txt"
+ filepath = os.path.join(build_dir, filename)
+
+ debug('default toolset: check file=%s', repr(filepath))
+ if os.path.exists(filepath):
+ toolset_default = _msvc_read_toolset_file(msvc, filepath)
+ if toolset_default:
+ return toolset_default
+
+ return None
+
+_toolset_version_cache = {}
+_toolset_default_cache = {}
+
+def _reset_toolset_cache():
+ debug('reset: toolset cache')
+ _toolset_version_cache = {}
+ _toolset_default_cache = {}
+
+def _msvc_version_toolsets(msvc, vc_dir):
+
+ if msvc.version in _toolset_version_cache:
+ toolsets_sxs, toolsets_full = _toolset_version_cache[msvc.version]
+ else:
+ toolsets_sxs, toolsets_full = _msvc_read_toolset_folders(msvc, vc_dir)
+ _toolset_version_cache[msvc.version] = toolsets_sxs, toolsets_full
+
+ return toolsets_sxs, toolsets_full
+
+def _msvc_default_toolset(msvc, vc_dir):
+
+ if msvc.version in _toolset_default_cache:
+ toolset_default = _toolset_default_cache[msvc.version]
+ else:
+ toolset_default = _msvc_read_toolset_default(msvc, vc_dir)
+ _toolset_default_cache[msvc.version] = toolset_default
+
+ return toolset_default
+
+def _msvc_version_toolset_vcvars(msvc, vc_dir, toolset_version):
+
+ if toolset_version == '14.0':
+ return toolset_version
+
+ toolsets_sxs, toolsets_full = _msvc_version_toolsets(msvc, vc_dir)
+
+ if msvc.vs_def.vc_buildtools_def.vc_version_numeric == VS2019.vc_buildtools_def.vc_version_numeric:
+ # necessary to detect toolset not found
+ if toolset_version == '14.28.16.8':
+ new_toolset_version = '14.28'
+ # VS2019\Common7\Tools\vsdevcmd\ext\vcvars.bat AzDO Bug#1293526
+ # special handling of the 16.8 SxS toolset, use VC\Auxiliary\Build\14.28 directory and SxS files
+ # if SxS version 14.28 not present/installed, fallback selection of toolset VC\Tools\MSVC\14.28.nnnnn.
+ debug(
+ 'rewrite toolset_version=%s => toolset_version=%s',
+ repr(toolset_version), repr(new_toolset_version)
+ )
+ toolset_version = new_toolset_version
+
+ if toolset_version in toolsets_sxs:
+ toolset_vcvars = toolsets_sxs[toolset_version]
+ return toolset_vcvars
+
+ for toolset_full in toolsets_full:
+ if toolset_full.startswith(toolset_version):
+ toolset_vcvars = toolset_full
+ return toolset_vcvars
+
+ return None
+
+def _msvc_script_argument_toolset_constraints(msvc, toolset_version):
+
+ if msvc.vs_def.vc_buildtools_def.vc_version_numeric < VS2017.vc_buildtools_def.vc_version_numeric:
+ debug(
+ 'invalid: msvc version constraint: %s < %s VS2017',
+ repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric),
+ repr(VS2017.vc_buildtools_def.vc_version_numeric)
+ )
+ err_msg = "MSVC_TOOLSET_VERSION ({}) constraint violation: MSVC_VERSION {} < {} VS2017".format(
+ repr(toolset_version), repr(msvc.version), repr(VS2017.vc_buildtools_def.vc_version)
+ )
+ return err_msg
+
+ m = re_toolset_version.match(toolset_version)
+ if not m:
+ debug('invalid: re_toolset_version: toolset_version=%s', repr(toolset_version))
+ err_msg = 'MSVC_TOOLSET_VERSION {} format is not supported'.format(
+ repr(toolset_version)
+ )
+ return err_msg
+
+ toolset_ver = m.group('version')
+ toolset_vernum = float(toolset_ver)
+
+ if toolset_vernum < VS2015.vc_buildtools_def.vc_version_numeric:
+ debug(
+ 'invalid: toolset version constraint: %s < %s VS2015',
+ repr(toolset_vernum), repr(VS2015.vc_buildtools_def.vc_version_numeric)
+ )
+ err_msg = "MSVC_TOOLSET_VERSION ({}) constraint violation: toolset version {} < {} VS2015".format(
+ repr(toolset_version), repr(toolset_ver), repr(VS2015.vc_buildtools_def.vc_version)
+ )
+ return err_msg
+
+ if toolset_vernum > msvc.vs_def.vc_buildtools_def.vc_version_numeric:
+ debug(
+ 'invalid: toolset version constraint: toolset %s > %s msvc',
+ repr(toolset_vernum), repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric)
+ )
+ err_msg = "MSVC_TOOLSET_VERSION ({}) constraint violation: toolset version {} > {} MSVC_VERSION".format(
+ repr(toolset_version), repr(toolset_ver), repr(msvc.version)
+ )
+ return err_msg
+
+ if toolset_vernum == VS2015.vc_buildtools_def.vc_version_numeric:
+ # tooset = 14.0
+ if re_toolset_full.match(toolset_version):
+ if not re_toolset_140.match(toolset_version):
+ debug(
+ 'invalid: toolset version 14.0 constraint: %s != 14.0',
+ repr(toolset_version)
+ )
+ err_msg = "MSVC_TOOLSET_VERSION ({}) constraint violation: toolset version {} != '14.0'".format(
+ repr(toolset_version), repr(toolset_version)
+ )
+ return err_msg
+ return None
+
+ if re_toolset_full.match(toolset_version):
+ debug('valid: re_toolset_full: toolset_version=%s', repr(toolset_version))
+ return None
+
+ if re_toolset_sxs.match(toolset_version):
+ debug('valid: re_toolset_sxs: toolset_version=%s', repr(toolset_version))
+ return None
+
+ debug('invalid: method exit: toolset_version=%s', repr(toolset_version))
+ err_msg = "MSVC_TOOLSET_VERSION ({}) format is not supported".format(repr(toolset_version))
+ return err_msg
+
+def _msvc_script_argument_toolset(env, msvc, vc_dir, arglist):
+
+ toolset_version = env['MSVC_TOOLSET_VERSION']
+ debug('MSVC_VERSION=%s, MSVC_TOOLSET_VERSION=%s', repr(msvc.version), repr(toolset_version))
+
+ if not toolset_version:
+ return None
+
+ err_msg = _msvc_script_argument_toolset_constraints(msvc, toolset_version)
+ if err_msg:
+ raise MSVCArgumentError(err_msg)
+
+ if toolset_version.startswith('14.0') and len(toolset_version) > len('14.0'):
+ new_toolset_version = '14.0'
+ debug(
+ 'rewrite toolset_version=%s => toolset_version=%s',
+ repr(toolset_version), repr(new_toolset_version)
+ )
+ toolset_version = new_toolset_version
+
+ toolset_vcvars = _msvc_version_toolset_vcvars(msvc, vc_dir, toolset_version)
+ debug(
+ 'toolset: toolset_version=%s, toolset_vcvars=%s',
+ repr(toolset_version), repr(toolset_vcvars)
+ )
+
+ if not toolset_vcvars:
+ err_msg = "MSVC_TOOLSET_VERSION {} not found for MSVC_VERSION {}".format(
+ repr(toolset_version), repr(msvc.version)
+ )
+ raise MSVCArgumentError(err_msg)
+
+ argpair = (SortOrder.TOOLSET, '-vcvars_ver={}'.format(toolset_vcvars))
+ arglist.append(argpair)
+
+ return toolset_vcvars
+
+def _msvc_script_default_toolset(env, msvc, vc_dir, arglist):
+
+ if msvc.vs_def.vc_buildtools_def.vc_version_numeric < VS2017.vc_buildtools_def.vc_version_numeric:
+ return None
+
+ toolset_default = _msvc_default_toolset(msvc, vc_dir)
+ if not toolset_default:
+ return None
+
+ debug('MSVC_VERSION=%s, toolset_default=%s', repr(msvc.version), repr(toolset_default))
+
+ argpair = (SortOrder.TOOLSET, '-vcvars_ver={}'.format(toolset_default))
+ arglist.append(argpair)
+
+ return toolset_default
+
+def _user_script_argument_toolset(env, toolset_version, user_argstr):
+
+ matches = [m for m in re_vcvars_toolset.finditer(user_argstr)]
+ if not matches:
+ return None
+
+ if len(matches) > 1:
+ debug('multiple toolset version declarations: MSVC_SCRIPT_ARGS=%s', repr(user_argstr))
+ err_msg = "multiple toolset version declarations: MSVC_SCRIPT_ARGS={}".format(repr(user_argstr))
+ raise MSVCArgumentError(err_msg)
+
+ if not toolset_version:
+ user_toolset = matches[0].group('toolset')
+ return user_toolset
+
+ env_argstr = env.get('MSVC_TOOLSET_VERSION','')
+ debug('multiple toolset version declarations: MSVC_TOOLSET_VERSION=%s, MSVC_SCRIPT_ARGS=%s', repr(env_argstr), repr(user_argstr))
+
+ err_msg = "multiple toolset version declarations: MSVC_TOOLSET_VERSION={} and MSVC_SCRIPT_ARGS={}".format(
+ repr(env_argstr), repr(user_argstr)
+ )
+
+ raise MSVCArgumentError(err_msg)
+
+def _msvc_script_argument_spectre(env, msvc, arglist):
+
+ spectre_libs = env['MSVC_SPECTRE_LIBS']
+ debug('MSVC_VERSION=%s, MSVC_SPECTRE_LIBS=%s', repr(msvc.version), repr(spectre_libs))
+
+ if not spectre_libs:
+ return None
+
+ if spectre_libs not in (True, '1'):
+ return None
+
+ if msvc.vs_def.vc_buildtools_def.vc_version_numeric < VS2017.vc_buildtools_def.vc_version_numeric:
+ debug(
+ 'invalid: msvc version constraint: %s < %s VS2017',
+ repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric),
+ repr(VS2017.vc_buildtools_def.vc_version_numeric)
+ )
+ err_msg = "MSVC_SPECTRE_LIBS ({}) constraint violation: MSVC_VERSION {} < {} VS2017".format(
+ repr(spectre_libs), repr(msvc.version), repr(VS2017.vc_buildtools_def.vc_version)
+ )
+ raise MSVCArgumentError(err_msg)
+
+ spectre_arg = 'spectre'
+
+ # spectre libs may not be installed
+ argpair = (SortOrder.SPECTRE, '-vcvars_spectre_libs={}'.format(spectre_arg))
+ arglist.append(argpair)
+
+ return spectre_arg
+
+def _msvc_script_argument_user(env, msvc, arglist):
+
+ # subst None -> empty string
+ script_args = env.subst('$MSVC_SCRIPT_ARGS')
+ debug('MSVC_VERSION=%s, MSVC_SCRIPT_ARGS=%s', repr(msvc.version), repr(script_args))
+
+ if not script_args:
+ return None
+
+ if msvc.vs_def.vc_buildtools_def.vc_version_numeric < VS2015.vc_buildtools_def.vc_version_numeric:
+ debug(
+ 'invalid: msvc version constraint: %s < %s VS2015',
+ repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric),
+ repr(VS2015.vc_buildtools_def.vc_version_numeric)
+ )
+ err_msg = "MSVC_SCRIPT_ARGS ({}) constraint violation: MSVC_VERSION {} < {} VS2015".format(
+ repr(script_args), repr(msvc.version), repr(VS2015.vc_buildtools_def.vc_version)
+ )
+ raise MSVCArgumentError(err_msg)
+
+ # user arguments are not validated
+ argpair = (SortOrder.USER, script_args)
+ arglist.append(argpair)
+
+ return script_args
+
+def _user_script_argument_spectre(env, spectre, user_argstr):
+
+ matches = [m for m in re_vcvars_spectre.finditer(user_argstr)]
+ if not matches:
+ return None
+
+ if len(matches) > 1:
+ debug('multiple spectre declarations: MSVC_SCRIPT_ARGS=%s', repr(user_argstr))
+ err_msg = "multiple spectre declarations: MSVC_SCRIPT_ARGS={}".format(repr(user_argstr))
+ raise MSVCArgumentError(err_msg)
+
+ if not spectre:
+ return None
+
+ env_argstr = env.get('MSVC_SPECTRE_LIBS','')
+ debug('multiple spectre declarations: MSVC_SPECTRE_LIBS=%s, MSVC_SCRIPT_ARGS=%s', repr(env_argstr), repr(user_argstr))
+
+ err_msg = "multiple spectre declarations: MSVC_SPECTRE_LIBS={} and MSVC_SCRIPT_ARGS={}".format(
+ repr(env_argstr), repr(user_argstr)
+ )
+
+ raise MSVCArgumentError(err_msg)
+
+def msvc_script_arguments(env, version, vc_dir, arg):
+
+ arglist = []
+
+ msvc = _msvc_version(version)
+
+ if arg:
+ argpair = (SortOrder.ARCH, arg)
+ arglist.append(argpair)
+
+ if 'MSVC_SCRIPT_ARGS' in env:
+ user_argstr = _msvc_script_argument_user(env, msvc, arglist)
+ else:
+ user_argstr = None
+
+ if 'MSVC_UWP_APP' in env:
+ uwp = _msvc_script_argument_uwp(env, msvc, arglist)
+ else:
+ uwp = None
+
+ if user_argstr:
+ _user_script_argument_uwp(env, uwp, user_argstr)
+
+ platform_type = 'uwp' if uwp else 'desktop'
+
+ if 'MSVC_SDK_VERSION' in env:
+ sdk_version = _msvc_script_argument_sdk(env, msvc, platform_type, arglist)
+ else:
+ sdk_version = None
+
+ if user_argstr:
+ user_sdk = _user_script_argument_sdk(env, sdk_version, user_argstr)
+ else:
+ user_sdk = None
+
+ if MSVC_FORCE_DEFAULT_SDK:
+ if not sdk_version and not user_sdk:
+ sdk_version = _msvc_script_default_sdk(env, msvc, platform_type, arglist)
+
+ if 'MSVC_TOOLSET_VERSION' in env:
+ toolset_version = _msvc_script_argument_toolset(env, msvc, vc_dir, arglist)
+ else:
+ toolset_version = None
+
+ if user_argstr:
+ user_toolset = _user_script_argument_toolset(env, toolset_version, user_argstr)
+ else:
+ user_toolset = None
+
+ if MSVC_FORCE_DEFAULT_TOOLSET:
+ if not toolset_version and not user_toolset:
+ toolset_version = _msvc_script_default_toolset(env, msvc, vc_dir, arglist)
+
+ if 'MSVC_SPECTRE_LIBS' in env:
+ spectre = _msvc_script_argument_spectre(env, msvc, arglist)
+ else:
+ spectre = None
+
+ if user_argstr:
+ _user_script_argument_spectre(env, spectre, user_argstr)
+
+ if arglist:
+ arglist.sort()
+ argstr = ' '.join([argpair[-1] for argpair in arglist]).strip()
+ else:
+ argstr = ''
+
+ debug('arguments: %s', repr(argstr))
+ return argstr
+
+def reset():
+ debug('')
+ _reset_toolset_cache()
+
+def verify():
+ debug('')
+ _verify_re_sdk_dispatch_map()
+
diff --git a/SCons/Tool/MSCommon/MSVC/SetupEnvDefault.py b/SCons/Tool/MSCommon/MSVC/SetupEnvDefault.py
new file mode 100644
index 0000000..8a79007
--- /dev/null
+++ b/SCons/Tool/MSCommon/MSVC/SetupEnvDefault.py
@@ -0,0 +1,235 @@
+# MIT License
+#
+# Copyright The SCons Foundation
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+"""
+Determine if and/or when an error/warning should be issued when there
+are no versions of msvc installed. If there is at least one version of
+msvc installed, these routines do (almost) nothing.
+
+Notes:
+ * When msvc is the default compiler because there are no compilers
+ installed, a build may fail due to the cl.exe command not being
+ recognized. Currently, there is no easy way to detect during
+ msvc initialization if the default environment will be used later
+ to build a program and/or library. There is no error/warning
+ as there are legitimate SCons uses that do not require a c compiler.
+ * An error is indicated by returning a non-empty tool list from the
+ function register_iserror.
+"""
+
+import re
+
+from .. common import (
+ debug,
+)
+
+from . import Dispatcher
+
+Dispatcher.register_modulename(__name__)
+
+class _Data:
+
+ separator = r';'
+
+ need_init = True
+
+ @classmethod
+ def reset(cls):
+ debug('msvc default:init')
+ cls.n_setup = 0 # number of calls to msvc_setup_env_once
+ cls.default_ismsvc = False # is msvc the default compiler
+ cls.default_tools_re_list = [] # list of default tools regular expressions
+ cls.msvc_tools_init = set() # tools registered via msvc_exists
+ cls.msvc_tools = None # tools registered via msvc_setup_env_once
+ cls.msvc_installed = False # is msvc installed (vcs_installed > 0)
+ cls.msvc_nodefault = False # is there a default version of msvc
+ cls.need_init = True # reset initialization indicator
+
+def _initialize(env, msvc_exists_func):
+ if _Data.need_init:
+ _Data.reset()
+ _Data.need_init = False
+ _Data.msvc_installed = msvc_exists_func(env)
+ debug('msvc default:msvc_installed=%s', _Data.msvc_installed)
+
+def register_tool(env, tool, msvc_exists_func):
+ debug('msvc default:tool=%s', tool)
+ if _Data.need_init:
+ _initialize(env, msvc_exists_func)
+ if _Data.msvc_installed:
+ return None
+ if not tool:
+ return None
+ if _Data.n_setup == 0:
+ if tool not in _Data.msvc_tools_init:
+ _Data.msvc_tools_init.add(tool)
+ debug('msvc default:tool=%s, msvc_tools_init=%s', tool, _Data.msvc_tools_init)
+ return None
+ if tool not in _Data.msvc_tools:
+ _Data.msvc_tools.add(tool)
+ debug('msvc default:tool=%s, msvc_tools=%s', tool, _Data.msvc_tools)
+
+def register_setup(env, msvc_exists_func):
+ debug('msvc default')
+ if _Data.need_init:
+ _initialize(env, msvc_exists_func)
+ _Data.n_setup += 1
+ if not _Data.msvc_installed:
+ _Data.msvc_tools = set(_Data.msvc_tools_init)
+ if _Data.n_setup == 1:
+ tool_list = env.get('TOOLS', None)
+ if tool_list and tool_list[0] == 'default':
+ if len(tool_list) > 1 and tool_list[1] in _Data.msvc_tools:
+ # msvc tools are the default compiler
+ _Data.default_ismsvc = True
+ _Data.msvc_nodefault = False
+ debug(
+ 'msvc default:n_setup=%d, msvc_installed=%s, default_ismsvc=%s',
+ _Data.n_setup, _Data.msvc_installed, _Data.default_ismsvc
+ )
+
+def set_nodefault():
+ # default msvc version, msvc not installed
+ _Data.msvc_nodefault = True
+ debug('msvc default:msvc_nodefault=%s', _Data.msvc_nodefault)
+
+def register_iserror(env, tool, msvc_exists_func):
+
+ register_tool(env, tool, msvc_exists_func)
+
+ if _Data.msvc_installed:
+ # msvc installed
+ return None
+
+ if not _Data.msvc_nodefault:
+ # msvc version specified
+ return None
+
+ tool_list = env.get('TOOLS', None)
+ if not tool_list:
+ # tool list is empty
+ return None
+
+ debug(
+ 'msvc default:n_setup=%s, default_ismsvc=%s, msvc_tools=%s, tool_list=%s',
+ _Data.n_setup, _Data.default_ismsvc, _Data.msvc_tools, tool_list
+ )
+
+ if not _Data.default_ismsvc:
+
+ # Summary:
+ # * msvc is not installed
+ # * msvc version not specified (default)
+ # * msvc is not the default compiler
+
+ # construct tools set
+ tools_set = set(tool_list)
+
+ else:
+
+ if _Data.n_setup == 1:
+ # first setup and msvc is default compiler:
+ # build default tools regex for current tool state
+ tools = _Data.separator.join(tool_list)
+ tools_nchar = len(tools)
+ debug('msvc default:add regex:nchar=%d, tools=%s', tools_nchar, tools)
+ re_default_tools = re.compile(re.escape(tools))
+ _Data.default_tools_re_list.insert(0, (tools_nchar, re_default_tools))
+ # early exit: no error for default environment when msvc is not installed
+ return None
+
+ # Summary:
+ # * msvc is not installed
+ # * msvc version not specified (default)
+ # * environment tools list is not empty
+ # * default tools regex list constructed
+ # * msvc tools set constructed
+ #
+ # Algorithm using tools string and sets:
+ # * convert environment tools list to a string
+ # * iteratively remove default tools sequences via regex
+ # substition list built from longest sequence (first)
+ # to shortest sequence (last)
+ # * build environment tools set with remaining tools
+ # * compute intersection of environment tools and msvc tools sets
+ # * if the intersection is:
+ # empty - no error: default tools and/or no additional msvc tools
+ # not empty - error: user specified one or more msvc tool(s)
+ #
+ # This will not produce an error or warning when there are no
+ # msvc installed instances nor any other recognized compilers
+ # and the default environment is needed for a build. The msvc
+ # compiler is forcibly added to the environment tools list when
+ # there are no compilers installed on win32. In this case, cl.exe
+ # will not be found on the path resulting in a failed build.
+
+ # construct tools string
+ tools = _Data.separator.join(tool_list)
+ tools_nchar = len(tools)
+
+ debug('msvc default:check tools:nchar=%d, tools=%s', tools_nchar, tools)
+
+ # iteratively remove default tool sequences (longest to shortest)
+ re_nchar_min, re_tools_min = _Data.default_tools_re_list[-1]
+ if tools_nchar >= re_nchar_min and re_tools_min.search(tools):
+ # minimum characters satisfied and minimum pattern exists
+ for re_nchar, re_default_tool in _Data.default_tools_re_list:
+ if tools_nchar < re_nchar:
+ # not enough characters for pattern
+ continue
+ tools = re_default_tool.sub('', tools).strip(_Data.separator)
+ tools_nchar = len(tools)
+ debug('msvc default:check tools:nchar=%d, tools=%s', tools_nchar, tools)
+ if tools_nchar < re_nchar_min or not re_tools_min.search(tools):
+ # less than minimum characters or minimum pattern does not exist
+ break
+
+ # construct non-default list(s) tools set
+ tools_set = {msvc_tool for msvc_tool in tools.split(_Data.separator) if msvc_tool}
+
+ debug('msvc default:tools=%s', tools_set)
+ if not tools_set:
+ return None
+
+ # compute intersection of remaining tools set and msvc tools set
+ tools_found = _Data.msvc_tools.intersection(tools_set)
+ debug('msvc default:tools_exist=%s', tools_found)
+ if not tools_found:
+ return None
+
+ # construct in same order as tools list
+ tools_found_list = []
+ seen_tool = set()
+ for tool in tool_list:
+ if tool not in seen_tool:
+ seen_tool.add(tool)
+ if tool in tools_found:
+ tools_found_list.append(tool)
+
+ # return tool list in order presented
+ return tools_found_list
+
+def reset():
+ debug('')
+ _Data.reset()
+
diff --git a/SCons/Tool/MSCommon/MSVC/Util.py b/SCons/Tool/MSCommon/MSVC/Util.py
new file mode 100644
index 0000000..15abdcd
--- /dev/null
+++ b/SCons/Tool/MSCommon/MSVC/Util.py
@@ -0,0 +1,55 @@
+# MIT License
+#
+# Copyright The SCons Foundation
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+"""
+Helper functions for Microsoft Visual C/C++.
+"""
+
+import os
+import re
+
+def listdir_dirs(p):
+ dirs = []
+ for dir_name in os.listdir(p):
+ dir_path = os.path.join(p, dir_name)
+ if os.path.isdir(dir_path):
+ dirs.append((dir_name, dir_path))
+ return dirs
+
+def process_path(p):
+ if p:
+ p = os.path.normpath(p)
+ p = os.path.realpath(p)
+ p = os.path.normcase(p)
+ return p
+
+re_version_prefix = re.compile(r'^(?P<version>[0-9.]+).*')
+
+def get_version_prefix(version):
+ m = re_version_prefix.match(version)
+ if m:
+ rval = m.group('version')
+ else:
+ rval = ''
+ return rval
+
diff --git a/SCons/Tool/MSCommon/MSVC/WinSDK.py b/SCons/Tool/MSCommon/MSVC/WinSDK.py
new file mode 100644
index 0000000..e95c72e
--- /dev/null
+++ b/SCons/Tool/MSCommon/MSVC/WinSDK.py
@@ -0,0 +1,250 @@
+# MIT License
+#
+# Copyright The SCons Foundation
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+"""
+Windows SDK functions for Microsoft Visual C/C++.
+"""
+
+import os
+
+from ..common import (
+ debug,
+)
+
+from . import Dispatcher
+from . import Util
+from . import Config
+from . import Registry
+
+from .Exceptions import (
+ MSVCInternalError,
+)
+
+Dispatcher.register_modulename(__name__)
+
+def _new_sdk_map():
+ sdk_map = {
+ 'desktop': [],
+ 'uwp': [],
+ }
+ return sdk_map
+
+def _sdk_10_layout(version):
+
+ folder_prefix = version + '.'
+
+ sdk_map = _new_sdk_map()
+
+ sdk_roots = Registry.sdk_query_paths(version)
+
+ sdk_version_platform_seen = set()
+ sdk_roots_seen = set()
+
+ for sdk_t in sdk_roots:
+
+ sdk_root = sdk_t[0]
+ if sdk_root in sdk_roots_seen:
+ continue
+ sdk_roots_seen.add(sdk_root)
+
+ if not os.path.exists(sdk_root):
+ continue
+
+ sdk_include_path = os.path.join(sdk_root, 'include')
+ if not os.path.exists(sdk_include_path):
+ continue
+
+ for version_nbr, version_nbr_path in Util.listdir_dirs(sdk_include_path):
+
+ if not version_nbr.startswith(folder_prefix):
+ continue
+
+ sdk_inc_path = Util.process_path(os.path.join(version_nbr_path, 'um'))
+ if not os.path.exists(sdk_inc_path):
+ continue
+
+ for platform_type, sdk_inc_file in [
+ ('desktop', 'winsdkver.h'),
+ ('uwp', 'windows.h'),
+ ]:
+
+ if not os.path.exists(os.path.join(sdk_inc_path, sdk_inc_file)):
+ continue
+
+ key = (version_nbr, platform_type)
+ if key in sdk_version_platform_seen:
+ continue
+ sdk_version_platform_seen.add(key)
+
+ sdk_map[platform_type].append(version_nbr)
+
+ for key, val in sdk_map.items():
+ val.sort(reverse=True)
+
+ return sdk_map
+
+def _sdk_81_layout(version):
+
+ version_nbr = version
+
+ sdk_map = _new_sdk_map()
+
+ sdk_roots = Registry.sdk_query_paths(version)
+
+ sdk_version_platform_seen = set()
+ sdk_roots_seen = set()
+
+ for sdk_t in sdk_roots:
+
+ sdk_root = sdk_t[0]
+ if sdk_root in sdk_roots_seen:
+ continue
+ sdk_roots_seen.add(sdk_root)
+
+ # msvc does not check for existence of root or other files
+
+ sdk_inc_path = Util.process_path(os.path.join(sdk_root, r'include\um'))
+ if not os.path.exists(sdk_inc_path):
+ continue
+
+ for platform_type, sdk_inc_file in [
+ ('desktop', 'winsdkver.h'),
+ ('uwp', 'windows.h'),
+ ]:
+
+ if not os.path.exists(os.path.join(sdk_inc_path, sdk_inc_file)):
+ continue
+
+ key = (version_nbr, platform_type)
+ if key in sdk_version_platform_seen:
+ continue
+ sdk_version_platform_seen.add(key)
+
+ sdk_map[platform_type].append(version_nbr)
+
+ for key, val in sdk_map.items():
+ val.sort(reverse=True)
+
+ return sdk_map
+
+_sdk_map_cache = {}
+_sdk_cache = {}
+
+def _reset_sdk_cache():
+ debug('')
+ _sdk_map_cache = {}
+ _sdk_cache = {}
+
+def _sdk_10(key, reg_version):
+ if key in _sdk_map_cache:
+ sdk_map = _sdk_map_cache[key]
+ else:
+ sdk_map = _sdk_10_layout(reg_version)
+ _sdk_map_cache[key] = sdk_map
+ return sdk_map
+
+def _sdk_81(key, reg_version):
+ if key in _sdk_map_cache:
+ sdk_map = _sdk_map_cache[key]
+ else:
+ sdk_map = _sdk_81_layout(reg_version)
+ _sdk_map_cache[key] = sdk_map
+ return sdk_map
+
+def _combine_sdk_map_list(sdk_map_list):
+ combined_sdk_map = _new_sdk_map()
+ for sdk_map in sdk_map_list:
+ for key, val in sdk_map.items():
+ combined_sdk_map[key].extend(val)
+ return combined_sdk_map
+
+_sdk_dispatch_map = {
+ '10.0': (_sdk_10, '10.0'),
+ '8.1': (_sdk_81, '8.1'),
+}
+
+def _verify_sdk_dispatch_map():
+ debug('')
+ for sdk_version in Config.MSVC_SDK_VERSIONS:
+ if sdk_version in _sdk_dispatch_map:
+ continue
+ err_msg = 'sdk version {} not in sdk_dispatch_map'.format(sdk_version)
+ raise MSVCInternalError(err_msg)
+ return None
+
+def _version_list_sdk_map(version_list):
+
+ sdk_map_list = []
+ for version in version_list:
+ func, reg_version = _sdk_dispatch_map[version]
+ sdk_map = func(version, reg_version)
+ sdk_map_list.append(sdk_map)
+
+ combined_sdk_map = _combine_sdk_map_list(sdk_map_list)
+ return combined_sdk_map
+
+def _sdk_map(version_list):
+ key = tuple(version_list)
+ if key in _sdk_cache:
+ sdk_map = _sdk_cache[key]
+ else:
+ version_numlist = [float(v) for v in version_list]
+ version_numlist.sort(reverse=True)
+ key = tuple([str(v) for v in version_numlist])
+ sdk_map = _version_list_sdk_map(key)
+ _sdk_cache[key] = sdk_map
+ return sdk_map
+
+def get_sdk_version_list(version_list, platform_type):
+ sdk_map = _sdk_map(version_list)
+ sdk_list = sdk_map.get(platform_type, [])
+ return sdk_list
+
+def get_msvc_sdk_version_list(msvc_version, msvc_uwp_app=False):
+ debug('msvc_version=%s, msvc_uwp_app=%s', repr(msvc_version), repr(msvc_uwp_app))
+
+ sdk_versions = []
+
+ verstr = Util.get_version_prefix(msvc_version)
+ vs_def = Config.MSVC_VERSION_EXTERNAL.get(verstr, None)
+ if not vs_def:
+ debug('vs_def is not defined')
+ return sdk_versions
+
+ is_uwp = True if msvc_uwp_app in Config.BOOLEAN_SYMBOLS[True] else False
+ platform_type = 'uwp' if is_uwp else 'desktop'
+ sdk_list = get_sdk_version_list(vs_def.vc_sdk_versions, platform_type)
+
+ sdk_versions.extend(sdk_list)
+ debug('sdk_versions=%s', repr(sdk_versions))
+
+ return sdk_versions
+
+def reset():
+ debug('')
+ _reset_sdk_cache()
+
+def verify():
+ debug('')
+ _verify_sdk_dispatch_map()
+
diff --git a/SCons/Tool/MSCommon/MSVC/__init__.py b/SCons/Tool/MSCommon/MSVC/__init__.py
new file mode 100644
index 0000000..afd993f
--- /dev/null
+++ b/SCons/Tool/MSCommon/MSVC/__init__.py
@@ -0,0 +1,50 @@
+# MIT License
+#
+# Copyright The SCons Foundation
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+"""
+Functions for Microsoft Visual C/C++.
+"""
+
+from . import Exceptions
+from . import Util
+
+from . import Dispatcher as _Dispatcher
+
+from . import Config
+from . import Registry
+from . import SetupEnvDefault
+from . import NotFound
+from . import WinSDK
+from . import ScriptArguments
+
+from .NotFound import (
+ set_msvc_notfound_policy,
+ get_msvc_notfound_policy,
+)
+
+def reset():
+ _Dispatcher.reset()
+
+#reset() # testing
+_Dispatcher.verify()
+
diff --git a/SCons/Tool/MSCommon/__init__.py b/SCons/Tool/MSCommon/__init__.py
index de78f84..9f35e94 100644
--- a/SCons/Tool/MSCommon/__init__.py
+++ b/SCons/Tool/MSCommon/__init__.py
@@ -32,14 +32,17 @@ import SCons.Util
from SCons.Tool.MSCommon.sdk import mssdk_exists, mssdk_setup_env
+from SCons.Tool.MSCommon.MSVC import (
+ set_msvc_notfound_policy,
+ get_msvc_notfound_policy,
+)
+
from SCons.Tool.MSCommon.vc import (
msvc_exists,
msvc_setup_env_tool,
msvc_setup_env_once,
msvc_version_to_maj_min,
msvc_find_vswhere,
- set_msvc_notfound_policy,
- get_msvc_notfound_policy,
get_msvc_sdk_versions,
)
diff --git a/SCons/Tool/MSCommon/vc.py b/SCons/Tool/MSCommon/vc.py
index ab05323..5a27f44 100644
--- a/SCons/Tool/MSCommon/vc.py
+++ b/SCons/Tool/MSCommon/vc.py
@@ -51,7 +51,6 @@ from collections import (
namedtuple,
OrderedDict,
)
-import enum
import SCons.Util
import SCons.Warnings
@@ -61,9 +60,10 @@ from . import common
from .common import CONFIG_CACHE, debug
from .sdk import get_installed_sdks
-
-class VisualCException(Exception):
- pass
+from . import MSVC
+from .MSVC.Exceptions import (
+ VisualCException
+)
class UnsupportedVersion(VisualCException):
pass
@@ -89,296 +89,10 @@ class MSVCScriptNotFound(VisualCException):
class MSVCUseSettingsError(VisualCException):
pass
-class MSVCVersionNotFound(VisualCException):
- pass
-
-class MSVCArgumentError(VisualCException):
- pass
-
-class MSVCInternalError(VisualCException):
- pass
-
class BatchFileExecutionWarning(SCons.Warnings.WarningOnByDefault):
pass
-class _Dispatcher:
-
- classrefs = []
-
- @classmethod
- def register(cls, classref):
- cls.classrefs.append(classref)
-
- @classmethod
- def reset(cls):
- debug('reset %s', cls.__name__)
- for classref in cls.classrefs:
- for method in ['reset', '_reset']:
- if not hasattr(classref, method) or not callable(getattr(classref, method, None)):
- continue
- debug('call %s.%s()', classref.__name__, method)
- func = getattr(classref, method)
- func()
-
- @classmethod
- def verify(cls):
- debug('verify %s', cls.__name__)
- for classref in cls.classrefs:
- for method in ['verify', '_verify']:
- if not hasattr(classref, method) or not callable(getattr(classref, method, None)):
- continue
- debug('call %s.%s()', classref.__name__, method)
- func = getattr(classref, method)
- func()
-
-class _Config:
-
- BOOLEAN_SYMBOLS = {}
- BOOLEAN_EXTERNAL = {}
-
- for bool, symbol_list, symbol_case_list in [
- (False, (False, 0, '0', None, ''), ('False', 'No', 'F', 'N')),
- (True, (True, 1, '1'), ('True', 'Yes', 'T', 'Y')),
- ]:
- BOOLEAN_SYMBOLS[bool] = list(symbol_list)
- for symbol in symbol_case_list:
- BOOLEAN_SYMBOLS[bool].extend([symbol, symbol.lower(), symbol.upper()])
-
- for symbol in BOOLEAN_SYMBOLS[bool]:
- BOOLEAN_EXTERNAL[symbol] = bool
-
- MSVC_RUNTIME_DEFINITION = namedtuple('MSVCRuntime', [
- 'vc_runtime',
- 'vc_runtime_numeric',
- 'vc_runtime_alias_list',
- 'vc_runtime_vsdef_list',
- ])
-
- MSVC_RUNTIME_DEFINITION_LIST = []
-
- MSVC_RUNTIME_INTERNAL = {}
- MSVC_RUNTIME_EXTERNAL = {}
-
- for vc_runtime, vc_runtime_numeric, vc_runtime_alias_list in [
- ('140', 140, ['ucrt']),
- ('120', 120, ['msvcr120']),
- ('110', 110, ['msvcr110']),
- ('100', 100, ['msvcr100']),
- ('90', 90, ['msvcr90']),
- ('80', 80, ['msvcr80']),
- ('71', 71, ['msvcr71']),
- ('70', 70, ['msvcr70']),
- ('60', 60, ['msvcrt']),
- ]:
- vc_runtime_def = MSVC_RUNTIME_DEFINITION(
- vc_runtime = vc_runtime,
- vc_runtime_numeric = vc_runtime_numeric,
- vc_runtime_alias_list = vc_runtime_alias_list,
- vc_runtime_vsdef_list = [],
- )
-
- MSVC_RUNTIME_DEFINITION_LIST.append(vc_runtime_def)
-
- MSVC_RUNTIME_INTERNAL[vc_runtime] = vc_runtime_def
- MSVC_RUNTIME_EXTERNAL[vc_runtime] = vc_runtime_def
-
- for vc_runtime_alias in vc_runtime_alias_list:
- MSVC_RUNTIME_EXTERNAL[vc_runtime_alias] = vc_runtime_def
-
- MSVC_BUILDTOOLS_DEFINITION = namedtuple('MSVCBuildtools', [
- 'vc_buildtools',
- 'vc_buildtools_numeric',
- 'vc_version',
- 'vc_version_numeric',
- 'cl_version',
- 'cl_version_numeric',
- 'vc_runtime_def',
- ])
-
- MSVC_BUILDTOOLS_DEFINITION_LIST = []
-
- MSVC_BUILDTOOLS_INTERNAL = {}
- MSVC_BUILDTOOLS_EXTERNAL = {}
-
- VC_VERSION_MAP = {}
-
- for vc_buildtools, vc_version, cl_version, vc_runtime in [
- ('v143', '14.3', '19.3', '140'),
- ('v142', '14.2', '19.2', '140'),
- ('v141', '14.1', '19.1', '140'),
- ('v140', '14.0', '19.0', '140'),
- ('v120', '12.0', '18.0', '120'),
- ('v110', '11.0', '17.0', '110'),
- ('v100', '10.0', '16.0', '100'),
- ('v90', '9.0', '15.0', '90'),
- ('v80', '8.0', '14.0', '80'),
- ('v71', '7.1', '13.1', '71'),
- ('v70', '7.0', '13.0', '70'),
- ('v60', '6.0', '12.0', '60'),
- ]:
-
- vc_runtime_def = MSVC_RUNTIME_INTERNAL[vc_runtime]
-
- vc_buildtools_def = MSVC_BUILDTOOLS_DEFINITION(
- vc_buildtools = vc_buildtools,
- vc_buildtools_numeric = int(vc_buildtools[1:]),
- vc_version = vc_version,
- vc_version_numeric = float(vc_version),
- cl_version = cl_version,
- cl_version_numeric = float(cl_version),
- vc_runtime_def = vc_runtime_def,
- )
-
- MSVC_BUILDTOOLS_DEFINITION_LIST.append(vc_buildtools_def)
-
- MSVC_BUILDTOOLS_INTERNAL[vc_buildtools] = vc_buildtools_def
- MSVC_BUILDTOOLS_EXTERNAL[vc_buildtools] = vc_buildtools_def
- MSVC_BUILDTOOLS_EXTERNAL[vc_version] = vc_buildtools_def
-
- VC_VERSION_MAP[vc_version] = vc_buildtools_def
-
- MSVS_VERSION_INTERNAL = {}
- MSVS_VERSION_EXTERNAL = {}
-
- MSVC_VERSION_INTERNAL = {}
- MSVC_VERSION_EXTERNAL = {}
-
- MSVS_VERSION_MAJOR_MAP = {}
-
- CL_VERSION_MAP = {}
-
- MSVC_SDK_VERSIONS = set()
-
- VISUALSTUDIO_DEFINITION = namedtuple('VisualStudioDefinition', [
- 'vs_product',
- 'vs_product_alias_list',
- 'vs_version',
- 'vs_version_major',
- 'vs_envvar',
- 'vs_express',
- 'vs_lookup',
- 'vc_sdk_versions',
- 'vc_ucrt_versions',
- 'vc_uwp',
- 'vc_buildtools_def',
- 'vc_buildtools_all',
- ])
-
- VISUALSTUDIO_DEFINITION_LIST = []
-
- VS_PRODUCT_ALIAS = {
- '1998': ['6']
- }
-
- # vs_envvar: VisualStudioVersion defined in environment for MSVS 2012 and later
- # MSVS 2010 and earlier cl_version -> vs_def is a 1:1 mapping
- # SDK attached to product or buildtools?
- for vs_product, vs_version, vs_envvar, vs_express, vs_lookup, vc_sdk, vc_ucrt, vc_uwp, vc_buildtools_all in [
- ('2022', '17.0', True, False, 'vswhere' , ['10.0', '8.1'], ['10'], 'uwp', ['v143', 'v142', 'v141', 'v140']),
- ('2019', '16.0', True, False, 'vswhere' , ['10.0', '8.1'], ['10'], 'uwp', ['v142', 'v141', 'v140']),
- ('2017', '15.0', True, True, 'vswhere' , ['10.0', '8.1'], ['10'], 'uwp', ['v141', 'v140']),
- ('2015', '14.0', True, True, 'registry', ['10.0', '8.1'], ['10'], 'store', ['v140']),
- ('2013', '12.0', True, True, 'registry', None, None, None, ['v120']),
- ('2012', '11.0', True, True, 'registry', None, None, None, ['v110']),
- ('2010', '10.0', False, True, 'registry', None, None, None, ['v100']),
- ('2008', '9.0', False, True, 'registry', None, None, None, ['v90']),
- ('2005', '8.0', False, True, 'registry', None, None, None, ['v80']),
- ('2003', '7.1', False, False, 'registry', None, None, None, ['v71']),
- ('2002', '7.0', False, False, 'registry', None, None, None, ['v70']),
- ('1998', '6.0', False, False, 'registry', None, None, None, ['v60']),
- ]:
-
- vs_version_major = vs_version.split('.')[0]
-
- vc_buildtools_def = MSVC_BUILDTOOLS_INTERNAL[vc_buildtools_all[0]]
-
- vs_def = VISUALSTUDIO_DEFINITION(
- vs_product = vs_product,
- vs_product_alias_list = [],
- vs_version = vs_version,
- vs_version_major = vs_version_major,
- vs_envvar = vs_envvar,
- vs_express = vs_express,
- vs_lookup = vs_lookup,
- vc_sdk_versions = vc_sdk,
- vc_ucrt_versions = vc_ucrt,
- vc_uwp = vc_uwp,
- vc_buildtools_def = vc_buildtools_def,
- vc_buildtools_all = vc_buildtools_all,
- )
-
- VISUALSTUDIO_DEFINITION_LIST.append(vs_def)
-
- vc_buildtools_def.vc_runtime_def.vc_runtime_vsdef_list.append(vs_def)
-
- MSVS_VERSION_INTERNAL[vs_product] = vs_def
- MSVS_VERSION_EXTERNAL[vs_product] = vs_def
- MSVS_VERSION_EXTERNAL[vs_version] = vs_def
-
- MSVC_VERSION_INTERNAL[vc_buildtools_def.vc_version] = vs_def
- MSVC_VERSION_EXTERNAL[vs_product] = vs_def
- MSVC_VERSION_EXTERNAL[vc_buildtools_def.vc_version] = vs_def
- MSVC_VERSION_EXTERNAL[vc_buildtools_def.vc_buildtools] = vs_def
-
- if vs_product in VS_PRODUCT_ALIAS:
- for vs_product_alias in VS_PRODUCT_ALIAS[vs_product]:
- vs_def.vs_product_alias_list.append(vs_product_alias)
- MSVS_VERSION_EXTERNAL[vs_product_alias] = vs_def
- MSVC_VERSION_EXTERNAL[vs_product_alias] = vs_def
-
- MSVS_VERSION_MAJOR_MAP[vs_version_major] = vs_def
-
- CL_VERSION_MAP[vc_buildtools_def.cl_version] = vs_def
-
- if not vc_sdk:
- continue
-
- MSVC_SDK_VERSIONS.update(vc_sdk)
-
- # convert string version set to string version list ranked in descending order
- MSVC_SDK_VERSIONS = [str(f) for f in sorted([float(s) for s in MSVC_SDK_VERSIONS], reverse=True)]
-
- MSVS_VERSION_LEGACY = {}
- MSVC_VERSION_LEGACY = {}
-
- for vdict in (MSVS_VERSION_EXTERNAL, MSVC_VERSION_INTERNAL):
- for key, vs_def in vdict.items():
- if key not in MSVS_VERSION_LEGACY:
- MSVS_VERSION_LEGACY[key] = vs_def
- MSVC_VERSION_LEGACY[key] = vs_def
-
-# MSVC_NOTFOUND_POLICY definition:
-# error: raise exception
-# warning: issue warning and continue
-# ignore: continue
-
-_MSVC_NOTFOUND_POLICY_DEFINITION = namedtuple('MSVCNotFoundPolicyDefinition', [
- 'value',
- 'symbol',
-])
-
-_MSVC_NOTFOUND_POLICY_INTERNAL = {}
-_MSVC_NOTFOUND_POLICY_EXTERNAL = {}
-
-for policy_value, policy_symbol_list in [
- (True, ['Error', 'Exception']),
- (False, ['Warning', 'Warn']),
- (None, ['Ignore', 'Suppress']),
-]:
-
- policy_symbol = policy_symbol_list[0].lower()
- policy_def = _MSVC_NOTFOUND_POLICY_DEFINITION(policy_value, policy_symbol)
-
- _MSVC_NOTFOUND_POLICY_INTERNAL[policy_symbol] = policy_def
-
- for policy_symbol in policy_symbol_list:
- _MSVC_NOTFOUND_POLICY_EXTERNAL[policy_symbol.lower()] = policy_def
- _MSVC_NOTFOUND_POLICY_EXTERNAL[policy_symbol] = policy_def
- _MSVC_NOTFOUND_POLICY_EXTERNAL[policy_symbol.upper()] = policy_def
-
-_MSVC_NOTFOUND_POLICY_DEF = _MSVC_NOTFOUND_POLICY_INTERNAL['warning']
-
# Dict to 'canonalize' the arch
_ARCH_TO_CANONICAL = {
"amd64" : "amd64",
@@ -1253,7 +967,7 @@ def reset_installed_vcs():
"""Make it try again to find VC. This is just for the tests."""
global __INSTALLED_VCS_RUN
__INSTALLED_VCS_RUN = None
- _Dispatcher.reset()
+ MSVC.reset()
def get_default_installed_msvc(env=None):
vcs = get_installed_vcs(env)
@@ -1344,295 +1058,6 @@ def script_env(script, args=None):
return cache_data
-def _msvc_notfound_policy_lookup(symbol):
-
- try:
- notfound_policy_def = _MSVC_NOTFOUND_POLICY_EXTERNAL[symbol]
- except KeyError:
- err_msg = "Value specified for MSVC_NOTFOUND_POLICY is not supported: {}.\n" \
- " Valid values are: {}".format(
- repr(symbol),
- ', '.join([repr(s) for s in _MSVC_NOTFOUND_POLICY_EXTERNAL.keys()])
- )
- raise ValueError(err_msg)
-
- return notfound_policy_def
-
-def set_msvc_notfound_policy(MSVC_NOTFOUND_POLICY=None):
- """ Set the default policy when MSVC is not found.
-
- Args:
- MSVC_NOTFOUND_POLICY:
- string representing the policy behavior
- when MSVC is not found or None
-
- Returns:
- The previous policy is returned when the MSVC_NOTFOUND_POLICY argument
- is not None. The active policy is returned when the MSVC_NOTFOUND_POLICY
- argument is None.
-
- """
- global _MSVC_NOTFOUND_POLICY_DEF
-
- prev_policy = _MSVC_NOTFOUND_POLICY_DEF.symbol
-
- policy = MSVC_NOTFOUND_POLICY
- if policy is not None:
- _MSVC_NOTFOUND_POLICY_DEF = _msvc_notfound_policy_lookup(policy)
-
- debug(
- 'prev_policy=%s, set_policy=%s, policy.symbol=%s, policy.value=%s',
- repr(prev_policy), repr(policy),
- repr(_MSVC_NOTFOUND_POLICY_DEF.symbol), repr(_MSVC_NOTFOUND_POLICY_DEF.value)
- )
-
- return prev_policy
-
-def get_msvc_notfound_policy():
- """Return the active policy when MSVC is not found."""
- debug(
- 'policy.symbol=%s, policy.value=%s',
- repr(_MSVC_NOTFOUND_POLICY_DEF.symbol), repr(_MSVC_NOTFOUND_POLICY_DEF.value)
- )
- return _MSVC_NOTFOUND_POLICY_DEF.symbol
-
-def _msvc_notfound_policy_handler(env, msg):
-
- if env and 'MSVC_NOTFOUND_POLICY' in env:
- # environment setting
- notfound_policy_src = 'environment'
- policy = env['MSVC_NOTFOUND_POLICY']
- if policy is not None:
- # user policy request
- notfound_policy_def = _msvc_notfound_policy_lookup(policy)
- else:
- # active global setting
- notfound_policy_def = _MSVC_NOTFOUND_POLICY_DEF
- else:
- # active global setting
- notfound_policy_src = 'default'
- policy = None
- notfound_policy_def = _MSVC_NOTFOUND_POLICY_DEF
-
- debug(
- 'source=%s, set_policy=%s, policy.symbol=%s, policy.value=%s',
- notfound_policy_src, repr(policy), repr(notfound_policy_def.symbol), repr(notfound_policy_def.value)
- )
-
- if notfound_policy_def.value is None:
- # ignore
- pass
- elif notfound_policy_def.value:
- raise MSVCVersionNotFound(msg)
- else:
- SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, msg)
-
-class _MSVCSetupEnvDefault:
- """
- Determine if and/or when an error/warning should be issued when there
- are no versions of msvc installed. If there is at least one version of
- msvc installed, these routines do (almost) nothing.
-
- Notes:
- * When msvc is the default compiler because there are no compilers
- installed, a build may fail due to the cl.exe command not being
- recognized. Currently, there is no easy way to detect during
- msvc initialization if the default environment will be used later
- to build a program and/or library. There is no error/warning
- as there are legitimate SCons uses that do not require a c compiler.
- * As implemented, the default is that a warning is issued. This can
- be changed globally via the function set_msvc_notfound_policy and/or
- through the environment via the MSVC_NOTFOUND_POLICY variable.
- """
-
- separator = r';'
-
- need_init = True
-
- @classmethod
- def reset(cls):
- debug('msvc default:init')
- cls.n_setup = 0 # number of calls to msvc_setup_env_once
- cls.default_ismsvc = False # is msvc the default compiler
- cls.default_tools_re_list = [] # list of default tools regular expressions
- cls.msvc_tools_init = set() # tools registered via msvc_exists
- cls.msvc_tools = None # tools registered via msvc_setup_env_once
- cls.msvc_installed = False # is msvc installed (vcs_installed > 0)
- cls.msvc_nodefault = False # is there a default version of msvc
- cls.need_init = True # reset initialization indicator
-
- @classmethod
- def _initialize(cls, env):
- if cls.need_init:
- cls.reset()
- cls.need_init = False
- vcs = get_installed_vcs(env)
- cls.msvc_installed = len(vcs) > 0
- debug('msvc default:msvc_installed=%s', cls.msvc_installed)
-
- @classmethod
- def register_tool(cls, env, tool):
- debug('msvc default:tool=%s', tool)
- if cls.need_init:
- cls._initialize(env)
- if cls.msvc_installed:
- return None
- if not tool:
- return None
- if cls.n_setup == 0:
- if tool not in cls.msvc_tools_init:
- cls.msvc_tools_init.add(tool)
- debug('msvc default:tool=%s, msvc_tools_init=%s', tool, cls.msvc_tools_init)
- return None
- if tool not in cls.msvc_tools:
- cls.msvc_tools.add(tool)
- debug('msvc default:tool=%s, msvc_tools=%s', tool, cls.msvc_tools)
-
- @classmethod
- def register_setup(cls, env):
- debug('msvc default')
- if cls.need_init:
- cls._initialize(env)
- cls.n_setup += 1
- if not cls.msvc_installed:
- cls.msvc_tools = set(cls.msvc_tools_init)
- if cls.n_setup == 1:
- tool_list = env.get('TOOLS', None)
- if tool_list and tool_list[0] == 'default':
- if len(tool_list) > 1 and tool_list[1] in cls.msvc_tools:
- # msvc tools are the default compiler
- cls.default_ismsvc = True
- cls.msvc_nodefault = False
- debug(
- 'msvc default:n_setup=%d, msvc_installed=%s, default_ismsvc=%s',
- cls.n_setup, cls.msvc_installed, cls.default_ismsvc
- )
-
- @classmethod
- def set_nodefault(cls):
- # default msvc version, msvc not installed
- cls.msvc_nodefault = True
- debug('msvc default:msvc_nodefault=%s', cls.msvc_nodefault)
-
- @classmethod
- def register_iserror(cls, env, tool):
-
- cls.register_tool(env, tool)
-
- if cls.msvc_installed:
- # msvc installed
- return None
-
- if not cls.msvc_nodefault:
- # msvc version specified
- return None
-
- tool_list = env.get('TOOLS', None)
- if not tool_list:
- # tool list is empty
- return None
-
- debug(
- 'msvc default:n_setup=%s, default_ismsvc=%s, msvc_tools=%s, tool_list=%s',
- cls.n_setup, cls.default_ismsvc, cls.msvc_tools, tool_list
- )
-
- if not cls.default_ismsvc:
-
- # Summary:
- # * msvc is not installed
- # * msvc version not specified (default)
- # * msvc is not the default compiler
-
- # construct tools set
- tools_set = set(tool_list)
-
- else:
-
- if cls.n_setup == 1:
- # first setup and msvc is default compiler:
- # build default tools regex for current tool state
- tools = cls.separator.join(tool_list)
- tools_nchar = len(tools)
- debug('msvc default:add regex:nchar=%d, tools=%s', tools_nchar, tools)
- re_default_tools = re.compile(re.escape(tools))
- cls.default_tools_re_list.insert(0, (tools_nchar, re_default_tools))
- # early exit: no error for default environment when msvc is not installed
- return None
-
- # Summary:
- # * msvc is not installed
- # * msvc version not specified (default)
- # * environment tools list is not empty
- # * default tools regex list constructed
- # * msvc tools set constructed
- #
- # Algorithm using tools string and sets:
- # * convert environment tools list to a string
- # * iteratively remove default tools sequences via regex
- # substition list built from longest sequence (first)
- # to shortest sequence (last)
- # * build environment tools set with remaining tools
- # * compute intersection of environment tools and msvc tools sets
- # * if the intersection is:
- # empty - no error: default tools and/or no additional msvc tools
- # not empty - error: user specified one or more msvc tool(s)
- #
- # This will not produce an error or warning when there are no
- # msvc installed instances nor any other recognized compilers
- # and the default environment is needed for a build. The msvc
- # compiler is forcibly added to the environment tools list when
- # there are no compilers installed on win32. In this case, cl.exe
- # will not be found on the path resulting in a failed build.
-
- # construct tools string
- tools = cls.separator.join(tool_list)
- tools_nchar = len(tools)
-
- debug('msvc default:check tools:nchar=%d, tools=%s', tools_nchar, tools)
-
- # iteratively remove default tool sequences (longest to shortest)
- re_nchar_min, re_tools_min = cls.default_tools_re_list[-1]
- if tools_nchar >= re_nchar_min and re_tools_min.search(tools):
- # minimum characters satisfied and minimum pattern exists
- for re_nchar, re_default_tool in cls.default_tools_re_list:
- if tools_nchar < re_nchar:
- # not enough characters for pattern
- continue
- tools = re_default_tool.sub('', tools).strip(cls.separator)
- tools_nchar = len(tools)
- debug('msvc default:check tools:nchar=%d, tools=%s', tools_nchar, tools)
- if tools_nchar < re_nchar_min or not re_tools_min.search(tools):
- # less than minimum characters or minimum pattern does not exist
- break
-
- # construct non-default list(s) tools set
- tools_set = {msvc_tool for msvc_tool in tools.split(cls.separator) if msvc_tool}
-
- debug('msvc default:tools=%s', tools_set)
- if not tools_set:
- return None
-
- # compute intersection of remaining tools set and msvc tools set
- tools_found = cls.msvc_tools.intersection(tools_set)
- debug('msvc default:tools_exist=%s', tools_found)
- if not tools_found:
- return None
-
- # construct in same order as tools list
- tools_found_list = []
- seen_tool = set()
- for tool in tool_list:
- if tool not in seen_tool:
- seen_tool.add(tool)
- if tool in tools_found:
- tools_found_list.append(tool)
-
- # return tool list in order presented
- return tools_found_list
-
-_Dispatcher.register(_MSVCSetupEnvDefault)
-
def get_default_version(env):
msvc_version = env.get('MSVC_VERSION')
msvs_version = env.get('MSVS_VERSION')
@@ -1673,16 +1098,16 @@ def msvc_setup_env_once(env, tool=None):
if not has_run:
debug('tool=%s', repr(tool))
- _MSVCSetupEnvDefault.register_setup(env)
+ MSVC.SetupEnvDefault.register_setup(env, msvc_exists)
msvc_setup_env(env)
env["MSVC_SETUP_RUN"] = True
- req_tools = _MSVCSetupEnvDefault.register_iserror(env, tool)
+ req_tools = MSVC.SetupEnvDefault.register_iserror(env, tool, msvc_exists)
if req_tools:
msg = "No versions of the MSVC compiler were found.\n" \
" Visual Studio C/C++ compilers may not be set correctly.\n" \
" Requested tool(s) are: {}".format(req_tools)
- _msvc_notfound_policy_handler(env, msg)
+ MSVC.Notfound.policy_handler(env, msg)
def msvc_find_valid_batch_script(env, version):
"""Find and execute appropriate batch script to set up build env.
@@ -1724,7 +1149,7 @@ def msvc_find_valid_batch_script(env, version):
debug('use_script 2 %s, args:%s', repr(vc_script), arg)
found = None
if vc_script:
- arg = _ScriptArguments.msvc_script_arguments(env, version, vc_dir, arg)
+ arg = MSVC.ScriptArguments.msvc_script_arguments(env, version, vc_dir, arg)
try:
d = script_env(vc_script, args=arg)
found = vc_script
@@ -1769,7 +1194,7 @@ def msvc_find_valid_batch_script(env, version):
" No versions of the MSVC compiler were found.\n" \
" Visual Studio C/C++ compilers may not be set correctly".format(version)
- _msvc_notfound_policy_handler(env, msg)
+ MSVC.NotFound.policy_handler(env, msg)
return d
@@ -1805,7 +1230,7 @@ def msvc_setup_env(env):
version = get_default_version(env)
if version is None:
if not msvc_setup_env_user(env):
- _MSVCSetupEnvDefault.set_nodefault()
+ MSVC.SetupEnvDefault.set_nodefault()
return None
# XXX: we set-up both MSVS version for backward
@@ -1899,7 +1324,7 @@ def msvc_setup_env_user(env=None):
def msvc_setup_env_tool(env=None, version=None, tool=None):
debug('tool=%s, version=%s', repr(tool), repr(version))
- _MSVCSetupEnvDefault.register_tool(env, tool)
+ MSVC.SetupEnvDefault.register_tool(env, tool, msvc_exists)
rval = False
if not rval and msvc_exists(env, version):
rval = True
@@ -1920,1043 +1345,6 @@ def get_msvc_sdk_versions(msvc_version=None, msvc_uwp_app=False):
debug('no msvc versions detected')
return rval
- rval = _WindowsSDK.get_msvc_sdk_version_list(msvc_version, msvc_uwp_app)
+ rval = MSVC.WinSDK.get_msvc_sdk_version_list(msvc_version, msvc_uwp_app)
return rval
-class _Util:
-
- @staticmethod
- def listdir_dirs(p):
- dirs = []
- for dir_name in os.listdir(p):
- dir_path = os.path.join(p, dir_name)
- if os.path.isdir(dir_path):
- dirs.append((dir_name, dir_path))
- return dirs
-
- @staticmethod
- def process_path(p):
- if p:
- p = os.path.normpath(p)
- p = os.path.realpath(p)
- p = os.path.normcase(p)
- return p
-
-class _Registry:
-
- def read_value(hkey, subkey_valname):
- try:
- rval = common.read_reg(subkey_valname, hkroot=hkey)
- except OSError:
- debug('OSError: hkey=%s, subkey=%s', repr(hkey), repr(subkey_valname))
- return None
- except IndexError:
- debug('IndexError: hkey=%s, subkey=%s', repr(hkey), repr(subkey_valname))
- return None
- debug('hkey=%s, subkey=%s, rval=%s', repr(hkey), repr(subkey_valname), repr(rval))
- return rval
-
- @classmethod
- def registry_query_path(cls, key, val, suffix):
- extval = val + '\\' + suffix if suffix else val
- qpath = cls.read_value(key, extval)
- if qpath and os.path.exists(qpath):
- qpath = _Util.process_path(qpath)
- else:
- qpath = None
- return (qpath, key, val, extval)
-
- REG_SOFTWARE_MICROSOFT = [
- (SCons.Util.HKEY_LOCAL_MACHINE, r'Software\Wow6432Node\Microsoft'),
- (SCons.Util.HKEY_CURRENT_USER, r'Software\Wow6432Node\Microsoft'), # SDK queries
- (SCons.Util.HKEY_LOCAL_MACHINE, r'Software\Microsoft'),
- (SCons.Util.HKEY_CURRENT_USER, r'Software\Microsoft'),
- ]
-
- @classmethod
- def microsoft_query_paths(cls, suffix, usrval=None):
- paths = []
- records = []
- for key, val in cls.REG_SOFTWARE_MICROSOFT:
- extval = val + '\\' + suffix if suffix else val
- qpath = cls.read_value(key, extval)
- if qpath and os.path.exists(qpath):
- qpath = _Util.process_path(qpath)
- if qpath not in paths:
- paths.append(qpath)
- records.append((qpath, key, val, extval, usrval))
- return records
-
- @classmethod
- def microsoft_query_keys(cls, suffix, usrval=None):
- records = []
- for key, val in cls.REG_SOFTWARE_MICROSOFT:
- extval = val + '\\' + suffix if suffix else val
- rval = cls.read_value(key, extval)
- if rval:
- records.append((key, val, extval, usrval))
- return records
-
- @classmethod
- def microsoft_sdks(cls, version):
- return '\\'.join([r'Microsoft SDKs\Windows', 'v' + version, r'InstallationFolder'])
-
- @classmethod
- def sdk_query_paths(cls, version):
- q = cls.microsoft_sdks(version)
- return cls.microsoft_query_paths(q)
-
- @classmethod
- def windows_kits(cls, version):
- return r'Windows Kits\Installed Roots\KitsRoot' + version
-
- @classmethod
- def windows_kit_query_paths(cls, version):
- q = cls.windows_kits(version)
- return cls.microsoft_query_paths(q)
-
-class _WindowsSDK:
-
- @classmethod
- def _new_sdk_map(cls):
- sdk_map = {
- 'desktop': [],
- 'uwp': [],
- }
- return sdk_map
-
- @classmethod
- def _sdk_10_layout(cls, version):
-
- folder_prefix = version + '.'
-
- sdk_map = cls._new_sdk_map()
-
- sdk_roots = _Registry.sdk_query_paths(version)
-
- sdk_version_platform_seen = set()
- sdk_roots_seen = set()
-
- for sdk_t in sdk_roots:
-
- sdk_root = sdk_t[0]
- if sdk_root in sdk_roots_seen:
- continue
- sdk_roots_seen.add(sdk_root)
-
- if not os.path.exists(sdk_root):
- continue
-
- sdk_include_path = os.path.join(sdk_root, 'include')
- if not os.path.exists(sdk_include_path):
- continue
-
- for version_nbr, version_nbr_path in _Util.listdir_dirs(sdk_include_path):
-
- if not version_nbr.startswith(folder_prefix):
- continue
-
- sdk_inc_path = _Util.process_path(os.path.join(version_nbr_path, 'um'))
- if not os.path.exists(sdk_inc_path):
- continue
-
- for platform_type, sdk_inc_file in [
- ('desktop', 'winsdkver.h'),
- ('uwp', 'windows.h'),
- ]:
-
- if not os.path.exists(os.path.join(sdk_inc_path, sdk_inc_file)):
- continue
-
- key = (version_nbr, platform_type)
- if key in sdk_version_platform_seen:
- continue
- sdk_version_platform_seen.add(key)
-
- sdk_map[platform_type].append(version_nbr)
-
- for key, val in sdk_map.items():
- val.sort(reverse=True)
-
- return sdk_map
-
- @classmethod
- def _sdk_81_layout(cls, version):
-
- version_nbr = version
-
- sdk_map = cls._new_sdk_map()
-
- sdk_roots = _Registry.sdk_query_paths(version)
-
- sdk_version_platform_seen = set()
- sdk_roots_seen = set()
-
- for sdk_t in sdk_roots:
-
- sdk_root = sdk_t[0]
- if sdk_root in sdk_roots_seen:
- continue
- sdk_roots_seen.add(sdk_root)
-
- # msvc does not check for existence of root or other files
-
- sdk_inc_path = _Util.process_path(os.path.join(sdk_root, r'include\um'))
- if not os.path.exists(sdk_inc_path):
- continue
-
- for platform_type, sdk_inc_file in [
- ('desktop', 'winsdkver.h'),
- ('uwp', 'windows.h'),
- ]:
-
- if not os.path.exists(os.path.join(sdk_inc_path, sdk_inc_file)):
- continue
-
- key = (version_nbr, platform_type)
- if key in sdk_version_platform_seen:
- continue
- sdk_version_platform_seen.add(key)
-
- sdk_map[platform_type].append(version_nbr)
-
- for key, val in sdk_map.items():
- val.sort(reverse=True)
-
- return sdk_map
-
- sdk_map_cache = {}
- sdk_cache = {}
-
- @classmethod
- def _reset_sdk_cache(cls):
- debug('reset %s: sdk cache', cls.__name__)
- cls._sdk_map_cache = {}
- cls._sdk_cache = {}
-
- @classmethod
- def _sdk_10(cls, key, reg_version):
- if key in cls.sdk_map_cache:
- sdk_map = cls.sdk_map_cache[key]
- else:
- sdk_map = cls._sdk_10_layout(reg_version)
- cls.sdk_map_cache[key] = sdk_map
- return sdk_map
-
- @classmethod
- def _sdk_81(cls, key, reg_version):
- if key in cls.sdk_map_cache:
- sdk_map = cls.sdk_map_cache[key]
- else:
- sdk_map = cls._sdk_81_layout(reg_version)
- cls.sdk_map_cache[key] = sdk_map
- return sdk_map
-
- @classmethod
- def _combine_sdk_map_list(cls, sdk_map_list):
- combined_sdk_map = cls._new_sdk_map()
- for sdk_map in sdk_map_list:
- for key, val in sdk_map.items():
- combined_sdk_map[key].extend(val)
- return combined_sdk_map
-
- sdk_dispatch_map = None
-
- @classmethod
- def _init_sdk_dispatch_map(cls):
- cls.sdk_dispatch_map = {
- '10.0': (cls._sdk_10, '10.0'),
- '8.1': (cls._sdk_81, '8.1'),
- }
-
- @classmethod
- def _verify_sdk_dispatch_map(cls):
- debug('%s verify sdk_dispatch_map', cls.__name__)
- cls._init_sdk_dispatch_map()
- for sdk_version in _Config.MSVC_SDK_VERSIONS:
- if sdk_version in cls.sdk_dispatch_map:
- continue
- err_msg = 'sdk version {} not in {}.sdk_dispatch_map'.format(sdk_version, cls.__name__)
- raise MSVCInternalError(err_msg)
- return None
-
- @classmethod
- def _version_list_sdk_map(cls, version_list):
-
- if not cls.sdk_dispatch_map:
- cls._init_sdk_dispatch_map()
-
- sdk_map_list = []
- for version in version_list:
- func, reg_version = cls.sdk_dispatch_map[version]
- sdk_map = func(version, reg_version)
- sdk_map_list.append(sdk_map)
-
- combined_sdk_map = cls._combine_sdk_map_list(sdk_map_list)
- return combined_sdk_map
-
- @classmethod
- def _sdk_map(cls, version_list):
- key = tuple(version_list)
- if key in cls.sdk_cache:
- sdk_map = cls.sdk_cache[key]
- else:
- version_numlist = [float(v) for v in version_list]
- version_numlist.sort(reverse=True)
- key = tuple([str(v) for v in version_numlist])
- sdk_map = cls._version_list_sdk_map(key)
- cls.sdk_cache[key] = sdk_map
- return sdk_map
-
- @classmethod
- def get_sdk_version_list(cls, version_list, platform_type):
- sdk_map = cls._sdk_map(version_list)
- sdk_list = sdk_map.get(platform_type, [])
- return sdk_list
-
- @classmethod
- def get_msvc_sdk_version_list(cls, msvc_version=None, msvc_uwp_app=False):
- debug('msvc_version=%s, msvc_uwp_app=%s', repr(msvc_version), repr(msvc_uwp_app))
-
- sdk_versions = []
-
- verstr = get_msvc_version_numeric(msvc_version)
- vs_def = _Config.MSVC_VERSION_EXTERNAL.get(verstr, None)
- if not vs_def:
- debug('vs_def is not defined')
- return sdk_versions
-
- is_uwp = True if msvc_uwp_app in _Config.BOOLEAN_SYMBOLS[True] else False
- platform_type = 'uwp' if is_uwp else 'desktop'
- sdk_list = _WindowsSDK.get_sdk_version_list(vs_def.vc_sdk_versions, platform_type)
-
- sdk_versions.extend(sdk_list)
- debug('sdk_versions=%s', repr(sdk_versions))
-
- return sdk_versions
-
- @classmethod
- def reset(cls):
- debug('reset %s', cls.__name__)
- cls._reset_sdk_cache()
-
- @classmethod
- def verify(cls):
- debug('verify %s', cls.__name__)
- cls._verify_sdk_dispatch_map()
-
-_Dispatcher.register(_WindowsSDK)
-
-class _ScriptArguments:
-
- # TODO: verify SDK 10 version folder names 10.0.XXXXX.0 {1,3} last?
- re_sdk_version_100 = re.compile(r'^10[.][0-9][.][0-9]{5}[.][0-9]{1}$')
- re_sdk_version_81 = re.compile(r'^8[.]1$')
-
- re_sdk_dispatch_map = {
- '10.0': re_sdk_version_100,
- '8.1': re_sdk_version_81,
- }
-
- @classmethod
- def _verify_re_sdk_dispatch_map(cls):
- debug('%s verify re_sdk_dispatch_map', cls.__name__)
- for sdk_version in _Config.MSVC_SDK_VERSIONS:
- if sdk_version in cls.re_sdk_dispatch_map:
- continue
- err_msg = 'sdk version {} not in {}.re_sdk_dispatch_map'.format(sdk_version, cls.__name__)
- raise MSVCInternalError(err_msg)
- return None
-
- # capture msvc version
- re_toolset_version = re.compile(r'^(?P<version>[1-9][0-9]?[.][0-9])[0-9.]*$', re.IGNORECASE)
-
- re_toolset_full = re.compile(r'''^(?:
- (?:[1-9][0-9][.][0-9]{1,2})| # XX.Y - XX.YY
- (?:[1-9][0-9][.][0-9]{2}[.][0-9]{1,5}) # XX.YY.Z - XX.YY.ZZZZZ
- )$''', re.VERBOSE)
-
- re_toolset_140 = re.compile(r'''^(?:
- (?:14[.]0{1,2})| # 14.0 - 14.00
- (?:14[.]0{2}[.]0{1,5}) # 14.00.0 - 14.00.00000
- )$''', re.VERBOSE)
-
- # valid SxS formats will be matched with re_toolset_full: match 3 '.' format
- re_toolset_sxs = re.compile(r'^[1-9][0-9][.][0-9]{2}[.][0-9]{2}[.][0-9]{1,2}$')
-
- # MSVC_SCRIPT_ARGS
- re_vcvars_uwp = re.compile(r'(?:(?<!\S)|^)(?P<uwp>(?:uwp|store))(?:(?!\S)|$)',re.IGNORECASE)
- re_vcvars_sdk = re.compile(r'(?:(?<!\S)|^)(?P<sdk>(?:[1-9][0-9]*[.]\S*))(?:(?!\S)|$)',re.IGNORECASE)
- re_vcvars_toolset = re.compile(r'(?:(?<!\S)|^)(?P<toolset_arg>(?:[-]{1,2}|[/])vcvars_ver[=](?P<toolset>\S*))(?:(?!\S)|$)', re.IGNORECASE)
- re_vcvars_spectre = re.compile(r'(?:(?<!\S)|^)(?P<spectre_arg>(?:[-]{1,2}|[/])vcvars_spectre_libs[=](?P<spectre>\S*))(?:(?!\S)|$)',re.IGNORECASE)
-
- # Force default sdk argument
- MSVC_FORCE_DEFAULT_SDK = False
-
- # Force default toolset argument
- MSVC_FORCE_DEFAULT_TOOLSET = False
-
- # MSVC batch file arguments:
- #
- # VS2022: UWP, SDK, TOOLSET, SPECTRE
- # VS2019: UWP, SDK, TOOLSET, SPECTRE
- # VS2017: UWP, SDK, TOOLSET, SPECTRE
- # VS2015: UWP, SDK
- #
- # MSVC_SCRIPT_ARGS: VS2015+
- #
- # MSVC_UWP_APP: VS2015+
- # MSVC_SDK_VERSION: VS2015+
- # MSVC_TOOLSET_VERSION: VS2017+
- # MSVC_SPECTRE_LIBS: VS2017+
-
- @enum.unique
- class SortOrder(enum.IntEnum):
- ARCH = 0 # arch
- UWP = 1 # MSVC_UWP_APP
- SDK = 2 # MSVC_SDK_VERSION
- TOOLSET = 3 # MSVC_TOOLSET_VERSION
- SPECTRE = 4 # MSVC_SPECTRE_LIBS
- USER = 5 # MSVC_SCRIPT_ARGS
-
- VS2019 = _Config.MSVS_VERSION_INTERNAL['2019']
- VS2017 = _Config.MSVS_VERSION_INTERNAL['2017']
- VS2015 = _Config.MSVS_VERSION_INTERNAL['2015']
-
- MSVC_VERSION_ARGS_DEFINITION = namedtuple('MSVCVersionArgsDefinition', [
- 'version', # fully qualified msvc version (e.g., '14.1Exp')
- 'vs_def',
- ])
-
- @classmethod
- def _msvc_version(cls, version):
-
- verstr = get_msvc_version_numeric(version)
- vs_def = _Config.MSVC_VERSION_INTERNAL[verstr]
-
- version_args = cls.MSVC_VERSION_ARGS_DEFINITION(
- version = version,
- vs_def = vs_def,
- )
-
- return version_args
-
- @classmethod
- def _msvc_script_argument_uwp(cls, env, msvc, arglist):
-
- uwp_app = env['MSVC_UWP_APP']
- debug('MSVC_VERSION=%s, MSVC_UWP_APP=%s', repr(msvc.version), repr(uwp_app))
-
- if not uwp_app:
- return None
-
- if uwp_app not in _Config.BOOLEAN_SYMBOLS[True]:
- return None
-
- if msvc.vs_def.vc_buildtools_def.vc_version_numeric < cls.VS2015.vc_buildtools_def.vc_version_numeric:
- debug(
- 'invalid: msvc version constraint: %s < %s VS2015',
- repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric),
- repr(cls.VS2015.vc_buildtools_def.vc_version_numeric)
- )
- err_msg = "MSVC_UWP_APP ({}) constraint violation: MSVC_VERSION {} < {} VS2015".format(
- repr(uwp_app), repr(msvc.version), repr(cls.VS2015.vc_buildtools_def.vc_version)
- )
- raise MSVCArgumentError(err_msg)
-
- # VS2017+ rewrites uwp => store for 14.0 toolset
- uwp_arg = msvc.vs_def.vc_uwp
-
- # store/uwp may not be fully installed
- argpair = (cls.SortOrder.UWP, uwp_arg)
- arglist.append(argpair)
-
- return uwp_arg
-
- @classmethod
- def _user_script_argument_uwp(cls, env, uwp, user_argstr):
-
- matches = [m for m in cls.re_vcvars_uwp.finditer(user_argstr)]
- if not matches:
- return None
-
- if len(matches) > 1:
- debug('multiple uwp declarations: MSVC_SCRIPT_ARGS=%s', repr(user_argstr))
- err_msg = "multiple uwp declarations: MSVC_SCRIPT_ARGS={}".format(repr(user_argstr))
- raise MSVCArgumentError(err_msg)
-
- if not uwp:
- return None
-
- env_argstr = env.get('MSVC_UWP_APP','')
- debug('multiple uwp declarations: MSVC_UWP_APP=%s, MSVC_SCRIPT_ARGS=%s', repr(env_argstr), repr(user_argstr))
-
- err_msg = "multiple uwp declarations: MSVC_UWP_APP={} and MSVC_SCRIPT_ARGS={}".format(
- repr(env_argstr), repr(user_argstr)
- )
-
- raise MSVCArgumentError(err_msg)
-
- @classmethod
- def _msvc_script_argument_sdk_constraints(cls, msvc, sdk_version):
-
- if msvc.vs_def.vc_buildtools_def.vc_version_numeric < cls.VS2015.vc_buildtools_def.vc_version_numeric:
- debug(
- 'invalid: msvc_version constraint: %s < %s VS2015',
- repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric),
- repr(cls.VS2015.vc_buildtools_def.vc_version_numeric)
- )
- err_msg = "MSVC_SDK_VERSION ({}) constraint violation: MSVC_VERSION {} < {} VS2015".format(
- repr(sdk_version), repr(msvc.version), repr(cls.VS2015.vc_buildtools_def.vc_version)
- )
- return err_msg
-
- for msvc_sdk_version in msvc.vs_def.vc_sdk_versions:
- re_sdk_version = cls.re_sdk_dispatch_map[msvc_sdk_version]
- if re_sdk_version.match(sdk_version):
- debug('valid: sdk_version=%s', repr(sdk_version))
- return None
-
- debug('invalid: method exit: sdk_version=%s', repr(sdk_version))
- err_msg = "MSVC_SDK_VERSION ({}) is not supported".format(repr(sdk_version))
- return err_msg
-
- @classmethod
- def _msvc_script_argument_sdk(cls, env, msvc, platform_type, arglist):
-
- sdk_version = env['MSVC_SDK_VERSION']
- debug(
- 'MSVC_VERSION=%s, MSVC_SDK_VERSION=%s, platform_type=%s',
- repr(msvc.version), repr(sdk_version), repr(platform_type)
- )
-
- if not sdk_version:
- return None
-
- err_msg = cls._msvc_script_argument_sdk_constraints(msvc, sdk_version)
- if err_msg:
- raise MSVCArgumentError(err_msg)
-
- sdk_list = _WindowsSDK.get_sdk_version_list(msvc.vs_def.vc_sdk_versions, platform_type)
-
- if sdk_version not in sdk_list:
- err_msg = "MSVC_SDK_VERSION {} not found for platform type {}".format(
- repr(sdk_version), repr(platform_type)
- )
- raise MSVCArgumentError(err_msg)
-
- argpair = (cls.SortOrder.SDK, sdk_version)
- arglist.append(argpair)
-
- return sdk_version
-
- @classmethod
- def _msvc_script_default_sdk(cls, env, msvc, platform_type, arglist):
-
- if msvc.vs_def.vc_buildtools_def.vc_version_numeric < cls.VS2015.vc_buildtools_def.vc_version_numeric:
- return None
-
- sdk_list = _WindowsSDK.get_sdk_version_list(msvc.vs_def.vc_sdk_versions, platform_type)
- if not len(sdk_list):
- return None
-
- sdk_default = sdk_list[0]
-
- debug(
- 'MSVC_VERSION=%s, sdk_default=%s, platform_type=%s',
- repr(msvc.version), repr(sdk_default), repr(platform_type)
- )
-
- argpair = (cls.SortOrder.SDK, sdk_default)
- arglist.append(argpair)
-
- return sdk_default
-
- @classmethod
- def _user_script_argument_sdk(cls, env, sdk_version, user_argstr):
-
- matches = [m for m in cls.re_vcvars_sdk.finditer(user_argstr)]
- if not matches:
- return None
-
- if len(matches) > 1:
- debug('multiple sdk version declarations: MSVC_SCRIPT_ARGS=%s', repr(user_argstr))
- err_msg = "multiple sdk version declarations: MSVC_SCRIPT_ARGS={}".format(repr(user_argstr))
- raise MSVCArgumentError(err_msg)
-
- if not sdk_version:
- user_sdk = matches[0].group('sdk')
- return user_sdk
-
- env_argstr = env.get('MSVC_SDK_VERSION','')
- debug('multiple sdk version declarations: MSVC_SDK_VERSION=%s, MSVC_SCRIPT_ARGS=%s', repr(env_argstr), repr(user_argstr))
-
- err_msg = "multiple sdk version declarations: MSVC_SDK_VERSION={} and MSVC_SCRIPT_ARGS={}".format(
- repr(env_argstr), repr(user_argstr)
- )
-
- raise MSVCArgumentError(err_msg)
-
- @classmethod
- def _msvc_read_toolset_file(cls, msvc, filename):
- toolset_version = None
- try:
- with open(filename) as f:
- toolset_version = f.readlines()[0].strip()
- debug(
- 'msvc_version=%s, filename=%s, toolset_version=%s',
- repr(msvc.version), repr(filename), repr(toolset_version)
- )
- except OSError:
- debug('OSError: msvc_version=%s, filename=%s', repr(msvc.version), repr(filename))
- except IndexError:
- debug('IndexError: msvc_version=%s, filename=%s', repr(msvc.version), repr(filename))
- return toolset_version
-
- @classmethod
- def _msvc_read_toolset_folders(cls, msvc, vc_dir):
-
- toolsets_sxs = {}
- toolsets_full = []
-
- build_dir = os.path.join(vc_dir, "Auxiliary", "Build")
- sxs_toolsets = [f.name for f in os.scandir(build_dir) if f.is_dir()]
- for sxs_toolset in sxs_toolsets:
- filename = 'Microsoft.VCToolsVersion.{}.txt'.format(sxs_toolset)
- filepath = os.path.join(build_dir, sxs_toolset, filename)
- debug('sxs toolset: check file=%s', repr(filepath))
- if os.path.exists(filepath):
- toolset_version = cls._msvc_read_toolset_file(msvc, filepath)
- if not toolset_version:
- continue
- toolsets_sxs[sxs_toolset] = toolset_version
- debug(
- 'sxs toolset: msvc_version=%s, sxs_version=%s, toolset_version=%s',
- repr(msvc.version), repr(sxs_toolset), toolset_version
- )
-
- toolset_dir = os.path.join(vc_dir, "Tools", "MSVC")
- toolsets = [f.name for f in os.scandir(toolset_dir) if f.is_dir()]
- for toolset_version in toolsets:
- binpath = os.path.join(toolset_dir, toolset_version, "bin")
- debug('toolset: check binpath=%s', repr(binpath))
- if os.path.exists(binpath):
- toolsets_full.append(toolset_version)
- debug(
- 'toolset: msvc_version=%s, toolset_version=%s',
- repr(msvc.version), repr(toolset_version)
- )
-
- toolsets_full.sort(reverse=True)
- debug('msvc_version=%s, toolsets=%s', repr(msvc.version), repr(toolsets_full))
-
- return toolsets_sxs, toolsets_full
-
- @classmethod
- def _msvc_read_toolset_default(cls, msvc, vc_dir):
-
- build_dir = os.path.join(vc_dir, "Auxiliary", "Build")
-
- # VS2019+
- filename = "Microsoft.VCToolsVersion.{}.default.txt".format(msvc.vs_def.vc_buildtools_def.vc_buildtools)
- filepath = os.path.join(build_dir, filename)
-
- debug('default toolset: check file=%s', repr(filepath))
- if os.path.exists(filepath):
- toolset_buildtools = cls._msvc_read_toolset_file(msvc, filepath)
- if toolset_buildtools:
- return toolset_buildtools
-
- # VS2017+
- filename = "Microsoft.VCToolsVersion.default.txt"
- filepath = os.path.join(build_dir, filename)
-
- debug('default toolset: check file=%s', repr(filepath))
- if os.path.exists(filepath):
- toolset_default = cls._msvc_read_toolset_file(msvc, filepath)
- if toolset_default:
- return toolset_default
-
- return None
-
- _toolset_version_cache = {}
- _toolset_default_cache = {}
-
- @classmethod
- def _reset_toolset_cache(cls):
- debug('reset %s: toolset cache', cls.__name__)
- cls._toolset_version_cache = {}
- cls._toolset_default_cache = {}
-
- @classmethod
- def _msvc_version_toolsets(cls, msvc, vc_dir):
-
- if msvc.version in cls._toolset_version_cache:
- toolsets_sxs, toolsets_full = cls._toolset_version_cache[msvc.version]
- else:
- toolsets_sxs, toolsets_full = cls._msvc_read_toolset_folders(msvc, vc_dir)
- cls._toolset_version_cache[msvc.version] = toolsets_sxs, toolsets_full
-
- return toolsets_sxs, toolsets_full
-
- @classmethod
- def _msvc_default_toolset(cls, msvc, vc_dir):
-
- if msvc.version in cls._toolset_default_cache:
- toolset_default = cls._toolset_default_cache[msvc.version]
- else:
- toolset_default = cls._msvc_read_toolset_default(msvc, vc_dir)
- cls._toolset_default_cache[msvc.version] = toolset_default
-
- return toolset_default
-
- @classmethod
- def _msvc_version_toolset_vcvars(cls, msvc, vc_dir, toolset_version):
-
- if toolset_version == '14.0':
- return toolset_version
-
- toolsets_sxs, toolsets_full = cls._msvc_version_toolsets(msvc, vc_dir)
-
- if msvc.vs_def.vc_buildtools_def.vc_version_numeric == cls.VS2019.vc_buildtools_def.vc_version_numeric:
- # necessary to detect toolset not found
- if toolset_version == '14.28.16.8':
- new_toolset_version = '14.28'
- # VS2019\Common7\Tools\vsdevcmd\ext\vcvars.bat AzDO Bug#1293526
- # special handling of the 16.8 SxS toolset, use VC\Auxiliary\Build\14.28 directory and SxS files
- # if SxS version 14.28 not present/installed, fallback selection of toolset VC\Tools\MSVC\14.28.nnnnn.
- debug(
- 'rewrite toolset_version=%s => toolset_version=%s',
- repr(toolset_version), repr(new_toolset_version)
- )
- toolset_version = new_toolset_version
-
- if toolset_version in toolsets_sxs:
- toolset_vcvars = toolsets_sxs[toolset_version]
- return toolset_vcvars
-
- for toolset_full in toolsets_full:
- if toolset_full.startswith(toolset_version):
- toolset_vcvars = toolset_full
- return toolset_vcvars
-
- return None
-
- @classmethod
- def _msvc_script_argument_toolset_constraints(cls, msvc, toolset_version):
-
- if msvc.vs_def.vc_buildtools_def.vc_version_numeric < cls.VS2017.vc_buildtools_def.vc_version_numeric:
- debug(
- 'invalid: msvc version constraint: %s < %s VS2017',
- repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric),
- repr(cls.VS2017.vc_buildtools_def.vc_version_numeric)
- )
- err_msg = "MSVC_TOOLSET_VERSION ({}) constraint violation: MSVC_VERSION {} < {} VS2017".format(
- repr(toolset_version), repr(msvc.version), repr(cls.VS2017.vc_buildtools_def.vc_version)
- )
- return err_msg
-
- m = cls.re_toolset_version.match(toolset_version)
- if not m:
- debug('invalid: re_toolset_version: toolset_version=%s', repr(toolset_version))
- err_msg = 'MSVC_TOOLSET_VERSION {} format is not supported'.format(
- repr(toolset_version)
- )
- return err_msg
-
- toolset_ver = m.group('version')
- toolset_vernum = float(toolset_ver)
-
- if toolset_vernum < cls.VS2015.vc_buildtools_def.vc_version_numeric:
- debug(
- 'invalid: toolset version constraint: %s < %s VS2015',
- repr(toolset_vernum), repr(cls.VS2015.vc_buildtools_def.vc_version_numeric)
- )
- err_msg = "MSVC_TOOLSET_VERSION ({}) constraint violation: toolset version {} < {} VS2015".format(
- repr(toolset_version), repr(toolset_ver), repr(cls.VS2015.vc_buildtools_def.vc_version)
- )
- return err_msg
-
- if toolset_vernum > msvc.vs_def.vc_buildtools_def.vc_version_numeric:
- debug(
- 'invalid: toolset version constraint: toolset %s > %s msvc',
- repr(toolset_vernum), repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric)
- )
- err_msg = "MSVC_TOOLSET_VERSION ({}) constraint violation: toolset version {} > {} MSVC_VERSION".format(
- repr(toolset_version), repr(toolset_ver), repr(msvc.version)
- )
- return err_msg
-
- if toolset_vernum == cls.VS2015.vc_buildtools_def.vc_version_numeric:
- # tooset = 14.0
- if cls.re_toolset_full.match(toolset_version):
- if not cls.re_toolset_140.match(toolset_version):
- debug(
- 'invalid: toolset version 14.0 constraint: %s != 14.0',
- repr(toolset_version)
- )
- err_msg = "MSVC_TOOLSET_VERSION ({}) constraint violation: toolset version {} != '14.0'".format(
- repr(toolset_version), repr(toolset_version)
- )
- return err_msg
- return None
-
- if cls.re_toolset_full.match(toolset_version):
- debug('valid: re_toolset_full: toolset_version=%s', repr(toolset_version))
- return None
-
- if cls.re_toolset_sxs.match(toolset_version):
- debug('valid: re_toolset_sxs: toolset_version=%s', repr(toolset_version))
- return None
-
- debug('invalid: method exit: toolset_version=%s', repr(toolset_version))
- err_msg = "MSVC_TOOLSET_VERSION ({}) format is not supported".format(repr(toolset_version))
- return err_msg
-
- @classmethod
- def _msvc_script_argument_toolset(cls, env, msvc, vc_dir, arglist):
-
- toolset_version = env['MSVC_TOOLSET_VERSION']
- debug('MSVC_VERSION=%s, MSVC_TOOLSET_VERSION=%s', repr(msvc.version), repr(toolset_version))
-
- if not toolset_version:
- return None
-
- err_msg = cls._msvc_script_argument_toolset_constraints(msvc, toolset_version)
- if err_msg:
- raise MSVCArgumentError(err_msg)
-
- if toolset_version.startswith('14.0') and len(toolset_version) > len('14.0'):
- new_toolset_version = '14.0'
- debug(
- 'rewrite toolset_version=%s => toolset_version=%s',
- repr(toolset_version), repr(new_toolset_version)
- )
- toolset_version = new_toolset_version
-
- toolset_vcvars = cls._msvc_version_toolset_vcvars(msvc, vc_dir, toolset_version)
- debug(
- 'toolset: toolset_version=%s, toolset_vcvars=%s',
- repr(toolset_version), repr(toolset_vcvars)
- )
-
- if not toolset_vcvars:
- err_msg = "MSVC_TOOLSET_VERSION {} not found for MSVC_VERSION {}".format(
- repr(toolset_version), repr(msvc.version)
- )
- raise MSVCArgumentError(err_msg)
-
- argpair = (cls.SortOrder.TOOLSET, '-vcvars_ver={}'.format(toolset_vcvars))
- arglist.append(argpair)
-
- return toolset_vcvars
-
- @classmethod
- def _msvc_script_default_toolset(cls, env, msvc, vc_dir, arglist):
-
- if msvc.vs_def.vc_buildtools_def.vc_version_numeric < cls.VS2017.vc_buildtools_def.vc_version_numeric:
- return None
-
- toolset_default = cls._msvc_default_toolset(msvc, vc_dir)
- if not toolset_default:
- return None
-
- debug('MSVC_VERSION=%s, toolset_default=%s', repr(msvc.version), repr(toolset_default))
-
- argpair = (cls.SortOrder.TOOLSET, '-vcvars_ver={}'.format(toolset_default))
- arglist.append(argpair)
-
- return toolset_default
-
- @classmethod
- def _user_script_argument_toolset(cls, env, toolset_version, user_argstr):
-
- matches = [m for m in cls.re_vcvars_toolset.finditer(user_argstr)]
- if not matches:
- return None
-
- if len(matches) > 1:
- debug('multiple toolset version declarations: MSVC_SCRIPT_ARGS=%s', repr(user_argstr))
- err_msg = "multiple toolset version declarations: MSVC_SCRIPT_ARGS={}".format(repr(user_argstr))
- raise MSVCArgumentError(err_msg)
-
- if not toolset_version:
- user_toolset = matches[0].group('toolset')
- return user_toolset
-
- env_argstr = env.get('MSVC_TOOLSET_VERSION','')
- debug('multiple toolset version declarations: MSVC_TOOLSET_VERSION=%s, MSVC_SCRIPT_ARGS=%s', repr(env_argstr), repr(user_argstr))
-
- err_msg = "multiple toolset version declarations: MSVC_TOOLSET_VERSION={} and MSVC_SCRIPT_ARGS={}".format(
- repr(env_argstr), repr(user_argstr)
- )
-
- raise MSVCArgumentError(err_msg)
-
- @classmethod
- def _msvc_script_argument_spectre(cls, env, msvc, arglist):
-
- spectre_libs = env['MSVC_SPECTRE_LIBS']
- debug('MSVC_VERSION=%s, MSVC_SPECTRE_LIBS=%s', repr(msvc.version), repr(spectre_libs))
-
- if not spectre_libs:
- return None
-
- if spectre_libs not in (True, '1'):
- return None
-
- if msvc.vs_def.vc_buildtools_def.vc_version_numeric < cls.VS2017.vc_buildtools_def.vc_version_numeric:
- debug(
- 'invalid: msvc version constraint: %s < %s VS2017',
- repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric),
- repr(cls.VS2017.vc_buildtools_def.vc_version_numeric)
- )
- err_msg = "MSVC_SPECTRE_LIBS ({}) constraint violation: MSVC_VERSION {} < {} VS2017".format(
- repr(spectre_libs), repr(msvc.version), repr(cls.VS2017.vc_buildtools_def.vc_version)
- )
- raise MSVCArgumentError(err_msg)
-
- spectre_arg = 'spectre'
-
- # spectre libs may not be installed
- argpair = (cls.SortOrder.SPECTRE, '-vcvars_spectre_libs={}'.format(spectre_arg))
- arglist.append(argpair)
-
- return spectre_arg
-
- @classmethod
- def _msvc_script_argument_user(cls, env, msvc, arglist):
-
- # subst None -> empty string
- script_args = env.subst('$MSVC_SCRIPT_ARGS')
- debug('MSVC_VERSION=%s, MSVC_SCRIPT_ARGS=%s', repr(msvc.version), repr(script_args))
-
- if not script_args:
- return None
-
- if msvc.vs_def.vc_buildtools_def.vc_version_numeric < cls.VS2015.vc_buildtools_def.vc_version_numeric:
- debug(
- 'invalid: msvc version constraint: %s < %s VS2015',
- repr(msvc.vs_def.vc_buildtools_def.vc_version_numeric),
- repr(cls.VS2015.vc_buildtools_def.vc_version_numeric)
- )
- err_msg = "MSVC_SCRIPT_ARGS ({}) constraint violation: MSVC_VERSION {} < {} VS2015".format(
- repr(script_args), repr(msvc.version), repr(cls.VS2015.vc_buildtools_def.vc_version)
- )
- raise MSVCArgumentError(err_msg)
-
- # user arguments are not validated
- argpair = (cls.SortOrder.USER, script_args)
- arglist.append(argpair)
-
- return script_args
-
- @classmethod
- def _user_script_argument_spectre(cls, env, spectre, user_argstr):
-
- matches = [m for m in cls.re_vcvars_spectre.finditer(user_argstr)]
- if not matches:
- return None
-
- if len(matches) > 1:
- debug('multiple spectre declarations: MSVC_SCRIPT_ARGS=%s', repr(user_argstr))
- err_msg = "multiple spectre declarations: MSVC_SCRIPT_ARGS={}".format(repr(user_argstr))
- raise MSVCArgumentError(err_msg)
-
- if not spectre:
- return None
-
- env_argstr = env.get('MSVC_SPECTRE_LIBS','')
- debug('multiple spectre declarations: MSVC_SPECTRE_LIBS=%s, MSVC_SCRIPT_ARGS=%s', repr(env_argstr), repr(user_argstr))
-
- err_msg = "multiple spectre declarations: MSVC_SPECTRE_LIBS={} and MSVC_SCRIPT_ARGS={}".format(
- repr(env_argstr), repr(user_argstr)
- )
-
- raise MSVCArgumentError(err_msg)
-
- @classmethod
- def msvc_script_arguments(cls, env, version, vc_dir, arg):
-
- arglist = []
-
- msvc = cls._msvc_version(version)
-
- if arg:
- argpair = (cls.SortOrder.ARCH, arg)
- arglist.append(argpair)
-
- if 'MSVC_SCRIPT_ARGS' in env:
- user_argstr = cls._msvc_script_argument_user(env, msvc, arglist)
- else:
- user_argstr = None
-
- if 'MSVC_UWP_APP' in env:
- uwp = cls._msvc_script_argument_uwp(env, msvc, arglist)
- else:
- uwp = None
-
- if user_argstr:
- cls._user_script_argument_uwp(env, uwp, user_argstr)
-
- platform_type = 'uwp' if uwp else 'desktop'
-
- if 'MSVC_SDK_VERSION' in env:
- sdk_version = cls._msvc_script_argument_sdk(env, msvc, platform_type, arglist)
- else:
- sdk_version = None
-
- if user_argstr:
- user_sdk = cls._user_script_argument_sdk(env, sdk_version, user_argstr)
- else:
- user_sdk = None
-
- if cls.MSVC_FORCE_DEFAULT_SDK:
- if not sdk_version and not user_sdk:
- sdk_version = cls._msvc_script_default_sdk(env, msvc, platform_type, arglist)
-
- if 'MSVC_TOOLSET_VERSION' in env:
- toolset_version = cls._msvc_script_argument_toolset(env, msvc, vc_dir, arglist)
- else:
- toolset_version = None
-
- if user_argstr:
- user_toolset = cls._user_script_argument_toolset(env, toolset_version, user_argstr)
- else:
- user_toolset = None
-
- if cls.MSVC_FORCE_DEFAULT_TOOLSET:
- if not toolset_version and not user_toolset:
- toolset_version = cls._msvc_script_default_toolset(env, msvc, vc_dir, arglist)
-
- if 'MSVC_SPECTRE_LIBS' in env:
- spectre = cls._msvc_script_argument_spectre(env, msvc, arglist)
- else:
- spectre = None
-
- if user_argstr:
- cls._user_script_argument_spectre(env, spectre, user_argstr)
-
- if arglist:
- arglist.sort()
- argstr = ' '.join([argpair[-1] for argpair in arglist]).strip()
- else:
- argstr = ''
-
- debug('arguments: %s', repr(argstr))
- return argstr
-
- @classmethod
- def reset(cls):
- debug('reset %s', cls.__name__)
- cls._reset_toolset_cache()
-
- @classmethod
- def verify(cls):
- debug('verify %s', cls.__name__)
- cls._verify_re_sdk_dispatch_map()
-
-_Dispatcher.register(_ScriptArguments)
-
-# internal consistency check
-_Dispatcher.verify()