mapnik/scons/scons-local-4.8.1/SCons/Tool/MSCommon/MSVC/ScriptArguments.py
2024-09-09 10:56:17 +01:00

1102 lines
38 KiB
Python
Vendored

# 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 (
CONFIG_CACHE_FORCE_DEFAULT_ARGUMENTS,
debug,
)
from . import Util
from . import Config
from . import Registry
from . import WinSDK
from . import Kind
from .Exceptions import (
MSVCInternalError,
MSVCSDKVersionNotFound,
MSVCToolsetVersionNotFound,
MSVCSpectreLibsNotFound,
MSVCArgumentError,
)
from . import Dispatcher
Dispatcher.register_modulename(__name__)
# Script argument: boolean True
_ARGUMENT_BOOLEAN_TRUE_LEGACY = (True, '1') # MSVC_UWP_APP
_ARGUMENT_BOOLEAN_TRUE = (True,)
# 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 = f'sdk version {sdk_version} not in re_sdk_dispatch_map'
raise MSVCInternalError(err_msg)
return None
# SxS version bugfix
_msvc_sxs_bugfix_map = {}
_msvc_sxs_bugfix_folder = {}
_msvc_sxs_bugfix_version = {}
for msvc_version, sxs_version, sxs_bugfix in [
# 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.
('14.2', '14.28.16.8', '14.28')
]:
_msvc_sxs_bugfix_map.setdefault(msvc_version, []).append((sxs_version, sxs_bugfix))
_msvc_sxs_bugfix_folder[(msvc_version, sxs_bugfix)] = sxs_version
_msvc_sxs_bugfix_version[(msvc_version, sxs_version)] = sxs_bugfix
# 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
# Force default arguments
_MSVC_FORCE_DEFAULT_ARGUMENTS = False
def _msvc_force_default_sdk(force: bool=True) -> None:
global _MSVC_FORCE_DEFAULT_SDK
_MSVC_FORCE_DEFAULT_SDK = force
debug('_MSVC_FORCE_DEFAULT_SDK=%s', repr(force))
def _msvc_force_default_toolset(force: bool=True) -> None:
global _MSVC_FORCE_DEFAULT_TOOLSET
_MSVC_FORCE_DEFAULT_TOOLSET = force
debug('_MSVC_FORCE_DEFAULT_TOOLSET=%s', repr(force))
def msvc_force_default_arguments(force=None):
global _MSVC_FORCE_DEFAULT_ARGUMENTS
prev_policy = _MSVC_FORCE_DEFAULT_ARGUMENTS
if force is not None:
_MSVC_FORCE_DEFAULT_ARGUMENTS = force
_msvc_force_default_sdk(force)
_msvc_force_default_toolset(force)
return prev_policy
if CONFIG_CACHE_FORCE_DEFAULT_ARGUMENTS:
msvc_force_default_arguments(force=True)
# UWP SDK 8.1 and SDK 10:
#
# https://stackoverflow.com/questions/46659238/build-windows-app-compatible-for-8-1-and-10
# VS2019 - UWP (Except for Win10Mobile)
# VS2017 - UWP
# VS2015 - UWP, Win8.1 StoreApp, WP8/8.1 StoreApp
# VS2013 - Win8/8.1 StoreApp, WP8/8.1 StoreApp
# SPECTRE LIBS (msvc documentation):
# "There are no versions of Spectre-mitigated libraries for Universal Windows (UWP) apps or
# components. App-local deployment of such libraries isn't possible."
# 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):
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', # full version (e.g., '14.1Exp', '14.32.31326')
'vs_def',
])
TOOLSET_VERSION_ARGS_DEFINITION = namedtuple('ToolsetVersionArgsDefinition', [
'version', # full version (e.g., '14.1Exp', '14.32.31326')
'vc_buildtools_def',
'is_user',
])
def _msvc_version(version):
verstr = Util.get_msvc_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 _toolset_version(version, is_user=False):
vc_series = Util.get_msvc_version_prefix(version)
vc_buildseries_def = Config.MSVC_BUILDSERIES_EXTERNAL[vc_series]
vc_buildtools_def = Config.VC_BUILDTOOLS_MAP[vc_buildseries_def.vc_buildseries]
version_args = TOOLSET_VERSION_ARGS_DEFINITION(
version = version,
vc_buildtools_def = vc_buildtools_def,
is_user = is_user,
)
return version_args
def _msvc_script_argument_uwp(env, msvc, arglist, target_arch):
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 _ARGUMENT_BOOLEAN_TRUE_LEGACY:
return None
if msvc.vs_def.vc_buildtools_def.msvc_version_numeric < VS2015.vc_buildtools_def.msvc_version_numeric:
debug(
'invalid: msvc version constraint: %s < %s VS2015',
repr(msvc.vs_def.vc_buildtools_def.msvc_version_numeric),
repr(VS2015.vc_buildtools_def.msvc_version_numeric)
)
err_msg = "MSVC_UWP_APP ({}) constraint violation: MSVC_VERSION {} < {} VS2015".format(
repr(uwp_app), repr(msvc.version), repr(VS2015.vc_buildtools_def.msvc_version)
)
raise MSVCArgumentError(err_msg)
is_supported, is_target = Kind.msvc_version_uwp_is_supported(msvc.version, target_arch, env)
if not is_supported:
_, kind_str = Kind.get_msvc_version_kind(msvc.version)
debug(
'invalid: msvc_version constraint: %s %s %s',
repr(msvc.version), repr(kind_str), repr(target_arch)
)
if is_target and target_arch:
err_msg = "MSVC_UWP_APP ({}) TARGET_ARCH ({}) is not supported for MSVC_VERSION {} ({})".format(
repr(uwp_app), repr(target_arch), repr(msvc.version), repr(kind_str)
)
else:
err_msg = "MSVC_UWP_APP ({}) is not supported for MSVC_VERSION {} ({})".format(
repr(uwp_app), repr(msvc.version), repr(kind_str)
)
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) -> bool:
matches = [m for m in re_vcvars_uwp.finditer(user_argstr)]
if not matches:
return False
if len(matches) > 1:
debug('multiple uwp declarations: MSVC_SCRIPT_ARGS=%s', repr(user_argstr))
err_msg = f"multiple uwp declarations: MSVC_SCRIPT_ARGS={user_argstr!r}"
raise MSVCArgumentError(err_msg)
if not uwp:
return True
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, env):
if msvc.vs_def.vc_buildtools_def.msvc_version_numeric < VS2015.vc_buildtools_def.msvc_version_numeric:
debug(
'invalid: msvc_version constraint: %s < %s VS2015',
repr(msvc.vs_def.vc_buildtools_def.msvc_version_numeric),
repr(VS2015.vc_buildtools_def.msvc_version_numeric)
)
err_msg = "MSVC_SDK_VERSION ({}) constraint violation: MSVC_VERSION {} < {} VS2015".format(
repr(sdk_version), repr(msvc.version), repr(VS2015.vc_buildtools_def.msvc_version)
)
return err_msg
if not Kind.msvc_version_sdk_version_is_supported(msvc.version, env):
_, kind_str = Kind.get_msvc_version_kind(msvc.version)
debug('invalid: msvc_version constraint: %s %s', repr(msvc.version), repr(kind_str))
err_msg = "MSVC_SDK_VERSION ({}) is not supported for MSVC_VERSION {} ({})".format(
repr(sdk_version), repr(msvc.version), repr(kind_str)
)
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 = f"MSVC_SDK_VERSION ({sdk_version!r}) is not supported"
return err_msg
def _msvc_script_argument_sdk_platform_constraints(msvc, toolset, sdk_version, platform_def):
if sdk_version == '8.1' and platform_def.is_uwp:
vc_buildtools_def = toolset.vc_buildtools_def if toolset else msvc.vs_def.vc_buildtools_def
if vc_buildtools_def.msvc_version_numeric > VS2015.vc_buildtools_def.msvc_version_numeric:
debug(
'invalid: uwp/store SDK 8.1 msvc_version constraint: %s > %s VS2015',
repr(vc_buildtools_def.msvc_version_numeric),
repr(VS2015.vc_buildtools_def.msvc_version_numeric)
)
if toolset and toolset.is_user:
err_msg = "MSVC_SDK_VERSION ({}) and platform type ({}) constraint violation: toolset {} MSVC_VERSION {} > {} VS2015".format(
repr(sdk_version), repr(platform_def.vc_platform),
repr(toolset.version), repr(msvc.version), repr(VS2015.vc_buildtools_def.msvc_version)
)
else:
err_msg = "MSVC_SDK_VERSION ({}) and platform type ({}) constraint violation: MSVC_VERSION {} > {} VS2015".format(
repr(sdk_version), repr(platform_def.vc_platform),
repr(msvc.version), repr(VS2015.vc_buildtools_def.msvc_version)
)
return err_msg
return None
def _msvc_script_argument_sdk(env, msvc, toolset, platform_def, 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_def.vc_platform)
)
if not sdk_version:
return None
err_msg = _msvc_script_argument_sdk_constraints(msvc, sdk_version, env)
if err_msg:
raise MSVCArgumentError(err_msg)
sdk_list = WinSDK.get_sdk_version_list(msvc.vs_def, platform_def)
if sdk_version not in sdk_list:
err_msg = "MSVC_SDK_VERSION {} not found for platform type {}".format(
repr(sdk_version), repr(platform_def.vc_platform)
)
raise MSVCSDKVersionNotFound(err_msg)
err_msg = _msvc_script_argument_sdk_platform_constraints(msvc, toolset, sdk_version, platform_def)
if err_msg:
raise MSVCArgumentError(err_msg)
argpair = (SortOrder.SDK, sdk_version)
arglist.append(argpair)
return sdk_version
def _msvc_script_default_sdk(env, msvc, platform_def, arglist, force_sdk: bool=False):
if msvc.vs_def.vc_buildtools_def.msvc_version_numeric < VS2015.vc_buildtools_def.msvc_version_numeric:
return None
if not Kind.msvc_version_sdk_version_is_supported(msvc.version, env):
return None
sdk_list = WinSDK.get_sdk_version_list(msvc.vs_def, platform_def)
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_def.vc_platform)
)
if force_sdk:
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 = f"multiple sdk version declarations: MSVC_SCRIPT_ARGS={user_argstr!r}"
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)
_toolset_have140_cache = None
def _msvc_have140_toolset():
global _toolset_have140_cache
if _toolset_have140_cache is None:
suffix = Registry.vstudio_sxs_vc7('14.0')
vcinstalldirs = [record[0] for record in Registry.microsoft_query_paths(suffix)]
debug('vc140 toolset: paths=%s', repr(vcinstalldirs))
_toolset_have140_cache = True if vcinstalldirs else False
return _toolset_have140_cache
def _reset_have140_cache() -> None:
global _toolset_have140_cache
debug('reset: cache')
_toolset_have140_cache = None
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_sxs_toolset_folder(msvc, sxs_folder):
if Util.is_toolset_sxs(sxs_folder):
return sxs_folder, sxs_folder
for vc_buildseries_def in msvc.vs_def.vc_buildtools_def.vc_buildseries_list:
key = (vc_buildseries_def.vc_version, sxs_folder)
sxs_version = _msvc_sxs_bugfix_folder.get(key)
if sxs_version:
return sxs_folder, sxs_version
debug('sxs folder: ignore version=%s', repr(sxs_folder))
return None, None
def _msvc_read_toolset_folders(msvc, vc_dir):
toolsets_sxs = {}
toolsets_full = []
build_dir = os.path.join(vc_dir, "Auxiliary", "Build")
if os.path.exists(build_dir):
for sxs_folder, sxs_path in Util.listdir_dirs(build_dir):
sxs_folder, sxs_version = _msvc_sxs_toolset_folder(msvc, sxs_folder)
if not sxs_version:
continue
filename = f'Microsoft.VCToolsVersion.{sxs_folder}.txt'
filepath = os.path.join(sxs_path, 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_version] = toolset_version
debug(
'sxs toolset: msvc_version=%s, sxs_version=%s, toolset_version=%s',
repr(msvc.version), repr(sxs_version), repr(toolset_version)
)
toolset_dir = os.path.join(vc_dir, "Tools", "MSVC")
if os.path.exists(toolset_dir):
for toolset_version, toolset_path in Util.listdir_dirs(toolset_dir):
binpath = os.path.join(toolset_path, "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)
)
vcvars140 = os.path.join(vc_dir, "..", "Common7", "Tools", "vsdevcmd", "ext", "vcvars", "vcvars140.bat")
if os.path.exists(vcvars140) and _msvc_have140_toolset():
toolset_version = '14.0'
toolsets_full.append(toolset_version)
debug(
'toolset: msvc_version=%s, toolset_version=%s',
repr(msvc.version), repr(toolset_version)
)
toolsets_full.sort(reverse=True)
# SxS bugfix fixup (if necessary)
if msvc.version in _msvc_sxs_bugfix_map:
for sxs_version, sxs_bugfix in _msvc_sxs_bugfix_map[msvc.version]:
if sxs_version in toolsets_sxs:
# have SxS version (folder/file mapping exists)
continue
for toolset_version in toolsets_full:
if not toolset_version.startswith(sxs_bugfix):
continue
debug(
'sxs toolset: msvc_version=%s, sxs_version=%s, toolset_version=%s',
repr(msvc.version), repr(sxs_version), repr(toolset_version)
)
# SxS compatible bugfix version (equivalent to toolset search)
toolsets_sxs[sxs_version] = toolset_version
break
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 = f"Microsoft.VCToolsVersion.{msvc.vs_def.vc_buildtools_def.vc_buildtools}.default.txt"
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() -> None:
global _toolset_version_cache
global _toolset_default_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):
toolsets_sxs, toolsets_full = _msvc_version_toolsets(msvc, vc_dir)
if toolset_version in toolsets_full:
# full toolset version provided
toolset_vcvars = toolset_version
return toolset_vcvars
if Util.is_toolset_sxs(toolset_version):
# SxS version provided
sxs_version = toolsets_sxs.get(toolset_version, None)
if sxs_version and sxs_version in toolsets_full:
# SxS full toolset version
toolset_vcvars = sxs_version
return toolset_vcvars
return None
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.msvc_version_numeric < VS2017.vc_buildtools_def.msvc_version_numeric:
debug(
'invalid: msvc version constraint: %s < %s VS2017',
repr(msvc.vs_def.vc_buildtools_def.msvc_version_numeric),
repr(VS2017.vc_buildtools_def.msvc_version_numeric)
)
err_msg = "MSVC_TOOLSET_VERSION ({}) constraint violation: MSVC_VERSION {} < {} VS2017".format(
repr(toolset_version), repr(msvc.version), repr(VS2017.vc_buildtools_def.msvc_version)
)
return err_msg
toolset_series = Util.get_msvc_version_prefix(toolset_version)
if not toolset_series:
debug('invalid: msvc version: toolset_version=%s', repr(toolset_version))
err_msg = 'MSVC_TOOLSET_VERSION {} format is not supported'.format(
repr(toolset_version)
)
return err_msg
toolset_buildseries_def = Config.MSVC_BUILDSERIES_EXTERNAL.get(toolset_series)
if not toolset_buildseries_def:
debug('invalid: msvc version: toolset_version=%s', repr(toolset_version))
err_msg = 'MSVC_TOOLSET_VERSION {} build series {} is not supported'.format(
repr(toolset_version), repr(toolset_series)
)
return err_msg
toolset_buildtools_def = Config.VC_BUILDTOOLS_MAP[toolset_buildseries_def.vc_buildseries]
toolset_verstr = toolset_buildtools_def.msvc_version
toolset_vernum = toolset_buildtools_def.msvc_version_numeric
if toolset_vernum < VS2015.vc_buildtools_def.msvc_version_numeric:
debug(
'invalid: toolset version constraint: %s < %s VS2015',
repr(toolset_vernum), repr(VS2015.vc_buildtools_def.msvc_version_numeric)
)
err_msg = "MSVC_TOOLSET_VERSION ({}) constraint violation: toolset msvc version {} < {} VS2015".format(
repr(toolset_version), repr(toolset_verstr), repr(VS2015.vc_buildtools_def.msvc_version)
)
return err_msg
if toolset_vernum > msvc.vs_def.vc_buildtools_def.msvc_version_numeric:
debug(
'invalid: toolset version constraint: toolset %s > %s msvc',
repr(toolset_vernum), repr(msvc.vs_def.vc_buildtools_def.msvc_version_numeric)
)
err_msg = "MSVC_TOOLSET_VERSION ({}) constraint violation: toolset msvc version {} > {} MSVC_VERSION".format(
repr(toolset_version), repr(toolset_verstr), repr(msvc.version)
)
return err_msg
if toolset_vernum == VS2015.vc_buildtools_def.msvc_version_numeric:
# tooset = 14.0
if Util.is_toolset_full(toolset_version):
if not Util.is_toolset_140(toolset_version):
debug(
'invalid: toolset version 14.0 constraint: %s != 14.0',
repr(toolset_version)
)
err_msg = "MSVC_TOOLSET_VERSION ({}) constraint violation: toolset msvc version {} != '14.0'".format(
repr(toolset_version), repr(toolset_version)
)
return err_msg
return None
if Util.is_toolset_full(toolset_version):
debug('valid: toolset full: toolset_version=%s', repr(toolset_version))
return None
if Util.is_toolset_sxs(toolset_version):
debug('valid: toolset sxs: toolset_version=%s', repr(toolset_version))
return None
debug('invalid: method exit: toolset_version=%s', repr(toolset_version))
err_msg = f"MSVC_TOOLSET_VERSION ({toolset_version!r}) format is not supported"
return err_msg
def _msvc_script_argument_toolset_vcvars(msvc, toolset_version, vc_dir):
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 MSVCToolsetVersionNotFound(err_msg)
return toolset_vcvars
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
toolset_vcvars = _msvc_script_argument_toolset_vcvars(msvc, toolset_version, vc_dir)
# toolset may not be installed for host/target
argpair = (SortOrder.TOOLSET, f'-vcvars_ver={toolset_vcvars}')
arglist.append(argpair)
return toolset_vcvars
def _msvc_script_default_toolset(env, msvc, vc_dir, arglist, force_toolset: bool=False):
if msvc.vs_def.vc_buildtools_def.msvc_version_numeric < VS2017.vc_buildtools_def.msvc_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))
if force_toolset:
argpair = (SortOrder.TOOLSET, f'-vcvars_ver={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 = f"multiple toolset version declarations: MSVC_SCRIPT_ARGS={user_argstr!r}"
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_constraints(msvc, toolset, spectre_libs, platform_def):
if msvc.vs_def.vc_buildtools_def.msvc_version_numeric < VS2017.vc_buildtools_def.msvc_version_numeric:
debug(
'invalid: msvc version constraint: %s < %s VS2017',
repr(msvc.vs_def.vc_buildtools_def.msvc_version_numeric),
repr(VS2017.vc_buildtools_def.msvc_version_numeric)
)
err_msg = "MSVC_SPECTRE_LIBS ({}) constraint violation: MSVC_VERSION {} < {} VS2017".format(
repr(spectre_libs), repr(msvc.version), repr(VS2017.vc_buildtools_def.msvc_version)
)
return err_msg
if toolset:
if toolset.vc_buildtools_def.msvc_version_numeric < VS2017.vc_buildtools_def.msvc_version_numeric:
debug(
'invalid: toolset version constraint: %s < %s VS2017',
repr(toolset.vc_buildtools_def.msvc_version_numeric),
repr(VS2017.vc_buildtools_def.msvc_version_numeric)
)
err_msg = "MSVC_SPECTRE_LIBS ({}) constraint violation: toolset version {} < {} VS2017".format(
repr(spectre_libs), repr(toolset.version), repr(VS2017.vc_buildtools_def.msvc_version)
)
return err_msg
if platform_def.is_uwp:
debug(
'invalid: spectre_libs=%s and platform_type=%s',
repr(spectre_libs), repr(platform_def.vc_platform)
)
err_msg = "MSVC_SPECTRE_LIBS ({}) are not supported for platform type ({})".format(
repr(spectre_libs), repr(platform_def.vc_platform)
)
return err_msg
return None
def _msvc_toolset_version_spectre_path(vc_dir, toolset_version):
spectre_dir = os.path.join(vc_dir, "Tools", "MSVC", toolset_version, "lib", "spectre")
return spectre_dir
def _msvc_script_argument_spectre(env, msvc, vc_dir, toolset, platform_def, 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 _ARGUMENT_BOOLEAN_TRUE:
return None
err_msg = _msvc_script_argument_spectre_constraints(msvc, toolset, spectre_libs, platform_def)
if err_msg:
raise MSVCArgumentError(err_msg)
if toolset:
spectre_dir = _msvc_toolset_version_spectre_path(vc_dir, toolset.version)
if not os.path.exists(spectre_dir):
debug(
'spectre libs: msvc_version=%s, toolset_version=%s, spectre_dir=%s',
repr(msvc.version), repr(toolset.version), repr(spectre_dir)
)
err_msg = "Spectre libraries not found for MSVC_VERSION {} toolset version {}".format(
repr(msvc.version), repr(toolset.version)
)
raise MSVCSpectreLibsNotFound(err_msg)
spectre_arg = 'spectre'
# spectre libs may not be installed for host/target
argpair = (SortOrder.SPECTRE, f'-vcvars_spectre_libs={spectre_arg}')
arglist.append(argpair)
return spectre_arg
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 = f"multiple spectre declarations: MSVC_SCRIPT_ARGS={user_argstr!r}"
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_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.msvc_version_numeric < VS2015.vc_buildtools_def.msvc_version_numeric:
debug(
'invalid: msvc version constraint: %s < %s VS2015',
repr(msvc.vs_def.vc_buildtools_def.msvc_version_numeric),
repr(VS2015.vc_buildtools_def.msvc_version_numeric)
)
err_msg = "MSVC_SCRIPT_ARGS ({}) constraint violation: MSVC_VERSION {} < {} VS2015".format(
repr(script_args), repr(msvc.version), repr(VS2015.vc_buildtools_def.msvc_version)
)
raise MSVCArgumentError(err_msg)
# user arguments are not validated
argpair = (SortOrder.USER, script_args)
arglist.append(argpair)
return script_args
def _msvc_process_construction_variables(env) -> bool:
for cache_variable in [
_MSVC_FORCE_DEFAULT_TOOLSET,
_MSVC_FORCE_DEFAULT_SDK,
]:
if cache_variable:
return True
for env_variable in [
'MSVC_UWP_APP',
'MSVC_TOOLSET_VERSION',
'MSVC_SDK_VERSION',
'MSVC_SPECTRE_LIBS',
]:
if env.get(env_variable, None) is not None:
return True
return False
def msvc_script_arguments_has_uwp(env):
if not _msvc_process_construction_variables(env):
return False
uwp_app = env.get('MSVC_UWP_APP')
is_uwp = bool(uwp_app and uwp_app in _ARGUMENT_BOOLEAN_TRUE_LEGACY)
debug('is_uwp=%s', is_uwp)
return is_uwp
def msvc_script_arguments(env, version, vc_dir, arg=None):
arguments = [arg] if arg else []
arglist = []
arglist_reverse = False
msvc = _msvc_version(version)
if 'MSVC_SCRIPT_ARGS' in env:
user_argstr = _msvc_script_argument_user(env, msvc, arglist)
else:
user_argstr = None
if _msvc_process_construction_variables(env):
target_arch = env.get('TARGET_ARCH')
# MSVC_UWP_APP
if 'MSVC_UWP_APP' in env:
uwp = _msvc_script_argument_uwp(env, msvc, arglist, target_arch)
else:
uwp = None
if user_argstr:
user_uwp = _user_script_argument_uwp(env, uwp, user_argstr)
else:
user_uwp = None
is_uwp = True if uwp else False
platform_def = WinSDK.get_msvc_platform(is_uwp)
# MSVC_TOOLSET_VERSION
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 not toolset_version and not user_toolset:
default_toolset = _msvc_script_default_toolset(env, msvc, vc_dir, arglist, _MSVC_FORCE_DEFAULT_TOOLSET)
if _MSVC_FORCE_DEFAULT_TOOLSET:
toolset_version = default_toolset
else:
default_toolset = None
if user_toolset:
toolset = None
elif toolset_version:
toolset = _toolset_version(toolset_version, is_user=True)
elif default_toolset:
toolset = _toolset_version(default_toolset)
else:
toolset = None
# MSVC_SDK_VERSION
if 'MSVC_SDK_VERSION' in env:
sdk_version = _msvc_script_argument_sdk(env, msvc, toolset, platform_def, 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_def, arglist, _MSVC_FORCE_DEFAULT_SDK)
# MSVC_SPECTRE_LIBS
if 'MSVC_SPECTRE_LIBS' in env:
spectre = _msvc_script_argument_spectre(env, msvc, vc_dir, toolset, platform_def, arglist)
else:
spectre = None
if user_argstr:
_user_script_argument_spectre(env, spectre, user_argstr)
if msvc.vs_def.vc_buildtools_def.msvc_version == '14.0':
if user_uwp and sdk_version and len(arglist) == 2:
# VS2015 toolset argument order issue: SDK store => store SDK
arglist_reverse = True
if len(arglist) > 1:
arglist.sort()
if arglist_reverse:
arglist.reverse()
arguments.extend([argpair[-1] for argpair in arglist])
argstr = ' '.join(arguments).strip()
debug('arguments: %s', repr(argstr))
return argstr
def _msvc_toolset_internal(msvc_version, toolset_version, vc_dir):
msvc = _msvc_version(msvc_version)
toolset_vcvars = _msvc_script_argument_toolset_vcvars(msvc, toolset_version, vc_dir)
return toolset_vcvars
def _msvc_toolset_versions_internal(msvc_version, vc_dir, full: bool=True, sxs: bool=False):
msvc = _msvc_version(msvc_version)
if len(msvc.vs_def.vc_buildtools_all) <= 1:
return None
toolset_versions = []
toolsets_sxs, toolsets_full = _msvc_version_toolsets(msvc, vc_dir)
if sxs:
sxs_versions = list(toolsets_sxs.keys())
sxs_versions.sort(reverse=True)
toolset_versions.extend(sxs_versions)
if full:
toolset_versions.extend(toolsets_full)
return toolset_versions
def _msvc_version_toolsets_internal(msvc_version, vc_dir):
msvc = _msvc_version(msvc_version)
toolsets_sxs, toolsets_full = _msvc_version_toolsets(msvc, vc_dir)
return toolsets_sxs, toolsets_full
def _msvc_toolset_versions_spectre_internal(msvc_version, vc_dir):
msvc = _msvc_version(msvc_version)
if len(msvc.vs_def.vc_buildtools_all) <= 1:
return None
_, toolsets_full = _msvc_version_toolsets(msvc, vc_dir)
spectre_toolset_versions = [
toolset_version
for toolset_version in toolsets_full
if os.path.exists(_msvc_toolset_version_spectre_path(vc_dir, toolset_version))
]
return spectre_toolset_versions
def reset() -> None:
debug('')
_reset_have140_cache()
_reset_toolset_cache()
def verify() -> None:
debug('')
_verify_re_sdk_dispatch_map()