Path: blob/main/test/lib/python3.9/site-packages/setuptools/msvc.py
4798 views
"""1Improved support for Microsoft Visual C++ compilers.23Known supported compilers:4--------------------------5Microsoft Visual C++ 9.0:6Microsoft Visual C++ Compiler for Python 2.7 (x86, amd64)7Microsoft Windows SDK 6.1 (x86, x64, ia64)8Microsoft Windows SDK 7.0 (x86, x64, ia64)910Microsoft Visual C++ 10.0:11Microsoft Windows SDK 7.1 (x86, x64, ia64)1213Microsoft Visual C++ 14.X:14Microsoft Visual C++ Build Tools 2015 (x86, x64, arm)15Microsoft Visual Studio Build Tools 2017 (x86, x64, arm, arm64)16Microsoft Visual Studio Build Tools 2019 (x86, x64, arm, arm64)1718This may also support compilers shipped with compatible Visual Studio versions.19"""2021import json22from io import open23from os import listdir, pathsep24from os.path import join, isfile, isdir, dirname25import sys26import contextlib27import platform28import itertools29import subprocess30import distutils.errors31from setuptools.extern.packaging.version import LegacyVersion32from setuptools.extern.more_itertools import unique_everseen3334from .monkey import get_unpatched3536if platform.system() == 'Windows':37import winreg38from os import environ39else:40# Mock winreg and environ so the module can be imported on this platform.4142class winreg:43HKEY_USERS = None44HKEY_CURRENT_USER = None45HKEY_LOCAL_MACHINE = None46HKEY_CLASSES_ROOT = None4748environ = dict()4950_msvc9_suppress_errors = (51# msvc9compiler isn't available on some platforms52ImportError,5354# msvc9compiler raises DistutilsPlatformError in some55# environments. See #1118.56distutils.errors.DistutilsPlatformError,57)5859try:60from distutils.msvc9compiler import Reg61except _msvc9_suppress_errors:62pass636465def msvc9_find_vcvarsall(version):66"""67Patched "distutils.msvc9compiler.find_vcvarsall" to use the standalone68compiler build for Python69(VCForPython / Microsoft Visual C++ Compiler for Python 2.7).7071Fall back to original behavior when the standalone compiler is not72available.7374Redirect the path of "vcvarsall.bat".7576Parameters77----------78version: float79Required Microsoft Visual C++ version.8081Return82------83str84vcvarsall.bat path85"""86vc_base = r'Software\%sMicrosoft\DevDiv\VCForPython\%0.1f'87key = vc_base % ('', version)88try:89# Per-user installs register the compiler path here90productdir = Reg.get_value(key, "installdir")91except KeyError:92try:93# All-user installs on a 64-bit system register here94key = vc_base % ('Wow6432Node\\', version)95productdir = Reg.get_value(key, "installdir")96except KeyError:97productdir = None9899if productdir:100vcvarsall = join(productdir, "vcvarsall.bat")101if isfile(vcvarsall):102return vcvarsall103104return get_unpatched(msvc9_find_vcvarsall)(version)105106107def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs):108"""109Patched "distutils.msvc9compiler.query_vcvarsall" for support extra110Microsoft Visual C++ 9.0 and 10.0 compilers.111112Set environment without use of "vcvarsall.bat".113114Parameters115----------116ver: float117Required Microsoft Visual C++ version.118arch: str119Target architecture.120121Return122------123dict124environment125"""126# Try to get environment from vcvarsall.bat (Classical way)127try:128orig = get_unpatched(msvc9_query_vcvarsall)129return orig(ver, arch, *args, **kwargs)130except distutils.errors.DistutilsPlatformError:131# Pass error if Vcvarsall.bat is missing132pass133except ValueError:134# Pass error if environment not set after executing vcvarsall.bat135pass136137# If error, try to set environment directly138try:139return EnvironmentInfo(arch, ver).return_env()140except distutils.errors.DistutilsPlatformError as exc:141_augment_exception(exc, ver, arch)142raise143144145def _msvc14_find_vc2015():146"""Python 3.8 "distutils/_msvccompiler.py" backport"""147try:148key = winreg.OpenKey(149winreg.HKEY_LOCAL_MACHINE,150r"Software\Microsoft\VisualStudio\SxS\VC7",1510,152winreg.KEY_READ | winreg.KEY_WOW64_32KEY153)154except OSError:155return None, None156157best_version = 0158best_dir = None159with key:160for i in itertools.count():161try:162v, vc_dir, vt = winreg.EnumValue(key, i)163except OSError:164break165if v and vt == winreg.REG_SZ and isdir(vc_dir):166try:167version = int(float(v))168except (ValueError, TypeError):169continue170if version >= 14 and version > best_version:171best_version, best_dir = version, vc_dir172return best_version, best_dir173174175def _msvc14_find_vc2017():176"""Python 3.8 "distutils/_msvccompiler.py" backport177178Returns "15, path" based on the result of invoking vswhere.exe179If no install is found, returns "None, None"180181The version is returned to avoid unnecessarily changing the function182result. It may be ignored when the path is not None.183184If vswhere.exe is not available, by definition, VS 2017 is not185installed.186"""187root = environ.get("ProgramFiles(x86)") or environ.get("ProgramFiles")188if not root:189return None, None190191try:192path = subprocess.check_output([193join(root, "Microsoft Visual Studio", "Installer", "vswhere.exe"),194"-latest",195"-prerelease",196"-requiresAny",197"-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64",198"-requires", "Microsoft.VisualStudio.Workload.WDExpress",199"-property", "installationPath",200"-products", "*",201]).decode(encoding="mbcs", errors="strict").strip()202except (subprocess.CalledProcessError, OSError, UnicodeDecodeError):203return None, None204205path = join(path, "VC", "Auxiliary", "Build")206if isdir(path):207return 15, path208209return None, None210211212PLAT_SPEC_TO_RUNTIME = {213'x86': 'x86',214'x86_amd64': 'x64',215'x86_arm': 'arm',216'x86_arm64': 'arm64'217}218219220def _msvc14_find_vcvarsall(plat_spec):221"""Python 3.8 "distutils/_msvccompiler.py" backport"""222_, best_dir = _msvc14_find_vc2017()223vcruntime = None224225if plat_spec in PLAT_SPEC_TO_RUNTIME:226vcruntime_plat = PLAT_SPEC_TO_RUNTIME[plat_spec]227else:228vcruntime_plat = 'x64' if 'amd64' in plat_spec else 'x86'229230if best_dir:231vcredist = join(best_dir, "..", "..", "redist", "MSVC", "**",232vcruntime_plat, "Microsoft.VC14*.CRT",233"vcruntime140.dll")234try:235import glob236vcruntime = glob.glob(vcredist, recursive=True)[-1]237except (ImportError, OSError, LookupError):238vcruntime = None239240if not best_dir:241best_version, best_dir = _msvc14_find_vc2015()242if best_version:243vcruntime = join(best_dir, 'redist', vcruntime_plat,244"Microsoft.VC140.CRT", "vcruntime140.dll")245246if not best_dir:247return None, None248249vcvarsall = join(best_dir, "vcvarsall.bat")250if not isfile(vcvarsall):251return None, None252253if not vcruntime or not isfile(vcruntime):254vcruntime = None255256return vcvarsall, vcruntime257258259def _msvc14_get_vc_env(plat_spec):260"""Python 3.8 "distutils/_msvccompiler.py" backport"""261if "DISTUTILS_USE_SDK" in environ:262return {263key.lower(): value264for key, value in environ.items()265}266267vcvarsall, vcruntime = _msvc14_find_vcvarsall(plat_spec)268if not vcvarsall:269raise distutils.errors.DistutilsPlatformError(270"Unable to find vcvarsall.bat"271)272273try:274out = subprocess.check_output(275'cmd /u /c "{}" {} && set'.format(vcvarsall, plat_spec),276stderr=subprocess.STDOUT,277).decode('utf-16le', errors='replace')278except subprocess.CalledProcessError as exc:279raise distutils.errors.DistutilsPlatformError(280"Error executing {}".format(exc.cmd)281) from exc282283env = {284key.lower(): value285for key, _, value in286(line.partition('=') for line in out.splitlines())287if key and value288}289290if vcruntime:291env['py_vcruntime_redist'] = vcruntime292return env293294295def msvc14_get_vc_env(plat_spec):296"""297Patched "distutils._msvccompiler._get_vc_env" for support extra298Microsoft Visual C++ 14.X compilers.299300Set environment without use of "vcvarsall.bat".301302Parameters303----------304plat_spec: str305Target architecture.306307Return308------309dict310environment311"""312313# Always use backport from CPython 3.8314try:315return _msvc14_get_vc_env(plat_spec)316except distutils.errors.DistutilsPlatformError as exc:317_augment_exception(exc, 14.0)318raise319320321def msvc14_gen_lib_options(*args, **kwargs):322"""323Patched "distutils._msvccompiler.gen_lib_options" for fix324compatibility between "numpy.distutils" and "distutils._msvccompiler"325(for Numpy < 1.11.2)326"""327if "numpy.distutils" in sys.modules:328import numpy as np329if LegacyVersion(np.__version__) < LegacyVersion('1.11.2'):330return np.distutils.ccompiler.gen_lib_options(*args, **kwargs)331return get_unpatched(msvc14_gen_lib_options)(*args, **kwargs)332333334def _augment_exception(exc, version, arch=''):335"""336Add details to the exception message to help guide the user337as to what action will resolve it.338"""339# Error if MSVC++ directory not found or environment not set340message = exc.args[0]341342if "vcvarsall" in message.lower() or "visual c" in message.lower():343# Special error message if MSVC++ not installed344tmpl = 'Microsoft Visual C++ {version:0.1f} or greater is required.'345message = tmpl.format(**locals())346msdownload = 'www.microsoft.com/download/details.aspx?id=%d'347if version == 9.0:348if arch.lower().find('ia64') > -1:349# For VC++ 9.0, if IA64 support is needed, redirect user350# to Windows SDK 7.0.351# Note: No download link available from Microsoft.352message += ' Get it with "Microsoft Windows SDK 7.0"'353else:354# For VC++ 9.0 redirect user to Vc++ for Python 2.7 :355# This redirection link is maintained by Microsoft.356# Contact [email protected] if it needs updating.357message += ' Get it from http://aka.ms/vcpython27'358elif version == 10.0:359# For VC++ 10.0 Redirect user to Windows SDK 7.1360message += ' Get it with "Microsoft Windows SDK 7.1": '361message += msdownload % 8279362elif version >= 14.0:363# For VC++ 14.X Redirect user to latest Visual C++ Build Tools364message += (' Get it with "Microsoft C++ Build Tools": '365r'https://visualstudio.microsoft.com'366r'/visual-cpp-build-tools/')367368exc.args = (message, )369370371class PlatformInfo:372"""373Current and Target Architectures information.374375Parameters376----------377arch: str378Target architecture.379"""380current_cpu = environ.get('processor_architecture', '').lower()381382def __init__(self, arch):383self.arch = arch.lower().replace('x64', 'amd64')384385@property386def target_cpu(self):387"""388Return Target CPU architecture.389390Return391------392str393Target CPU394"""395return self.arch[self.arch.find('_') + 1:]396397def target_is_x86(self):398"""399Return True if target CPU is x86 32 bits..400401Return402------403bool404CPU is x86 32 bits405"""406return self.target_cpu == 'x86'407408def current_is_x86(self):409"""410Return True if current CPU is x86 32 bits..411412Return413------414bool415CPU is x86 32 bits416"""417return self.current_cpu == 'x86'418419def current_dir(self, hidex86=False, x64=False):420"""421Current platform specific subfolder.422423Parameters424----------425hidex86: bool426return '' and not '\x86' if architecture is x86.427x64: bool428return '\x64' and not '\amd64' if architecture is amd64.429430Return431------432str433subfolder: '\target', or '' (see hidex86 parameter)434"""435return (436'' if (self.current_cpu == 'x86' and hidex86) else437r'\x64' if (self.current_cpu == 'amd64' and x64) else438r'\%s' % self.current_cpu439)440441def target_dir(self, hidex86=False, x64=False):442r"""443Target platform specific subfolder.444445Parameters446----------447hidex86: bool448return '' and not '\x86' if architecture is x86.449x64: bool450return '\x64' and not '\amd64' if architecture is amd64.451452Return453------454str455subfolder: '\current', or '' (see hidex86 parameter)456"""457return (458'' if (self.target_cpu == 'x86' and hidex86) else459r'\x64' if (self.target_cpu == 'amd64' and x64) else460r'\%s' % self.target_cpu461)462463def cross_dir(self, forcex86=False):464r"""465Cross platform specific subfolder.466467Parameters468----------469forcex86: bool470Use 'x86' as current architecture even if current architecture is471not x86.472473Return474------475str476subfolder: '' if target architecture is current architecture,477'\current_target' if not.478"""479current = 'x86' if forcex86 else self.current_cpu480return (481'' if self.target_cpu == current else482self.target_dir().replace('\\', '\\%s_' % current)483)484485486class RegistryInfo:487"""488Microsoft Visual Studio related registry information.489490Parameters491----------492platform_info: PlatformInfo493"PlatformInfo" instance.494"""495HKEYS = (winreg.HKEY_USERS,496winreg.HKEY_CURRENT_USER,497winreg.HKEY_LOCAL_MACHINE,498winreg.HKEY_CLASSES_ROOT)499500def __init__(self, platform_info):501self.pi = platform_info502503@property504def visualstudio(self):505"""506Microsoft Visual Studio root registry key.507508Return509------510str511Registry key512"""513return 'VisualStudio'514515@property516def sxs(self):517"""518Microsoft Visual Studio SxS registry key.519520Return521------522str523Registry key524"""525return join(self.visualstudio, 'SxS')526527@property528def vc(self):529"""530Microsoft Visual C++ VC7 registry key.531532Return533------534str535Registry key536"""537return join(self.sxs, 'VC7')538539@property540def vs(self):541"""542Microsoft Visual Studio VS7 registry key.543544Return545------546str547Registry key548"""549return join(self.sxs, 'VS7')550551@property552def vc_for_python(self):553"""554Microsoft Visual C++ for Python registry key.555556Return557------558str559Registry key560"""561return r'DevDiv\VCForPython'562563@property564def microsoft_sdk(self):565"""566Microsoft SDK registry key.567568Return569------570str571Registry key572"""573return 'Microsoft SDKs'574575@property576def windows_sdk(self):577"""578Microsoft Windows/Platform SDK registry key.579580Return581------582str583Registry key584"""585return join(self.microsoft_sdk, 'Windows')586587@property588def netfx_sdk(self):589"""590Microsoft .NET Framework SDK registry key.591592Return593------594str595Registry key596"""597return join(self.microsoft_sdk, 'NETFXSDK')598599@property600def windows_kits_roots(self):601"""602Microsoft Windows Kits Roots registry key.603604Return605------606str607Registry key608"""609return r'Windows Kits\Installed Roots'610611def microsoft(self, key, x86=False):612"""613Return key in Microsoft software registry.614615Parameters616----------617key: str618Registry key path where look.619x86: str620Force x86 software registry.621622Return623------624str625Registry key626"""627node64 = '' if self.pi.current_is_x86() or x86 else 'Wow6432Node'628return join('Software', node64, 'Microsoft', key)629630def lookup(self, key, name):631"""632Look for values in registry in Microsoft software registry.633634Parameters635----------636key: str637Registry key path where look.638name: str639Value name to find.640641Return642------643str644value645"""646key_read = winreg.KEY_READ647openkey = winreg.OpenKey648closekey = winreg.CloseKey649ms = self.microsoft650for hkey in self.HKEYS:651bkey = None652try:653bkey = openkey(hkey, ms(key), 0, key_read)654except (OSError, IOError):655if not self.pi.current_is_x86():656try:657bkey = openkey(hkey, ms(key, True), 0, key_read)658except (OSError, IOError):659continue660else:661continue662try:663return winreg.QueryValueEx(bkey, name)[0]664except (OSError, IOError):665pass666finally:667if bkey:668closekey(bkey)669670671class SystemInfo:672"""673Microsoft Windows and Visual Studio related system information.674675Parameters676----------677registry_info: RegistryInfo678"RegistryInfo" instance.679vc_ver: float680Required Microsoft Visual C++ version.681"""682683# Variables and properties in this class use originals CamelCase variables684# names from Microsoft source files for more easy comparison.685WinDir = environ.get('WinDir', '')686ProgramFiles = environ.get('ProgramFiles', '')687ProgramFilesx86 = environ.get('ProgramFiles(x86)', ProgramFiles)688689def __init__(self, registry_info, vc_ver=None):690self.ri = registry_info691self.pi = self.ri.pi692693self.known_vs_paths = self.find_programdata_vs_vers()694695# Except for VS15+, VC version is aligned with VS version696self.vs_ver = self.vc_ver = (697vc_ver or self._find_latest_available_vs_ver())698699def _find_latest_available_vs_ver(self):700"""701Find the latest VC version702703Return704------705float706version707"""708reg_vc_vers = self.find_reg_vs_vers()709710if not (reg_vc_vers or self.known_vs_paths):711raise distutils.errors.DistutilsPlatformError(712'No Microsoft Visual C++ version found')713714vc_vers = set(reg_vc_vers)715vc_vers.update(self.known_vs_paths)716return sorted(vc_vers)[-1]717718def find_reg_vs_vers(self):719"""720Find Microsoft Visual Studio versions available in registry.721722Return723------724list of float725Versions726"""727ms = self.ri.microsoft728vckeys = (self.ri.vc, self.ri.vc_for_python, self.ri.vs)729vs_vers = []730for hkey, key in itertools.product(self.ri.HKEYS, vckeys):731try:732bkey = winreg.OpenKey(hkey, ms(key), 0, winreg.KEY_READ)733except (OSError, IOError):734continue735with bkey:736subkeys, values, _ = winreg.QueryInfoKey(bkey)737for i in range(values):738with contextlib.suppress(ValueError):739ver = float(winreg.EnumValue(bkey, i)[0])740if ver not in vs_vers:741vs_vers.append(ver)742for i in range(subkeys):743with contextlib.suppress(ValueError):744ver = float(winreg.EnumKey(bkey, i))745if ver not in vs_vers:746vs_vers.append(ver)747return sorted(vs_vers)748749def find_programdata_vs_vers(self):750r"""751Find Visual studio 2017+ versions from information in752"C:\ProgramData\Microsoft\VisualStudio\Packages\_Instances".753754Return755------756dict757float version as key, path as value.758"""759vs_versions = {}760instances_dir = \761r'C:\ProgramData\Microsoft\VisualStudio\Packages\_Instances'762763try:764hashed_names = listdir(instances_dir)765766except (OSError, IOError):767# Directory not exists with all Visual Studio versions768return vs_versions769770for name in hashed_names:771try:772# Get VS installation path from "state.json" file773state_path = join(instances_dir, name, 'state.json')774with open(state_path, 'rt', encoding='utf-8') as state_file:775state = json.load(state_file)776vs_path = state['installationPath']777778# Raises OSError if this VS installation does not contain VC779listdir(join(vs_path, r'VC\Tools\MSVC'))780781# Store version and path782vs_versions[self._as_float_version(783state['installationVersion'])] = vs_path784785except (OSError, IOError, KeyError):786# Skip if "state.json" file is missing or bad format787continue788789return vs_versions790791@staticmethod792def _as_float_version(version):793"""794Return a string version as a simplified float version (major.minor)795796Parameters797----------798version: str799Version.800801Return802------803float804version805"""806return float('.'.join(version.split('.')[:2]))807808@property809def VSInstallDir(self):810"""811Microsoft Visual Studio directory.812813Return814------815str816path817"""818# Default path819default = join(self.ProgramFilesx86,820'Microsoft Visual Studio %0.1f' % self.vs_ver)821822# Try to get path from registry, if fail use default path823return self.ri.lookup(self.ri.vs, '%0.1f' % self.vs_ver) or default824825@property826def VCInstallDir(self):827"""828Microsoft Visual C++ directory.829830Return831------832str833path834"""835path = self._guess_vc() or self._guess_vc_legacy()836837if not isdir(path):838msg = 'Microsoft Visual C++ directory not found'839raise distutils.errors.DistutilsPlatformError(msg)840841return path842843def _guess_vc(self):844"""845Locate Visual C++ for VS2017+.846847Return848------849str850path851"""852if self.vs_ver <= 14.0:853return ''854855try:856# First search in known VS paths857vs_dir = self.known_vs_paths[self.vs_ver]858except KeyError:859# Else, search with path from registry860vs_dir = self.VSInstallDir861862guess_vc = join(vs_dir, r'VC\Tools\MSVC')863864# Subdir with VC exact version as name865try:866# Update the VC version with real one instead of VS version867vc_ver = listdir(guess_vc)[-1]868self.vc_ver = self._as_float_version(vc_ver)869return join(guess_vc, vc_ver)870except (OSError, IOError, IndexError):871return ''872873def _guess_vc_legacy(self):874"""875Locate Visual C++ for versions prior to 2017.876877Return878------879str880path881"""882default = join(self.ProgramFilesx86,883r'Microsoft Visual Studio %0.1f\VC' % self.vs_ver)884885# Try to get "VC++ for Python" path from registry as default path886reg_path = join(self.ri.vc_for_python, '%0.1f' % self.vs_ver)887python_vc = self.ri.lookup(reg_path, 'installdir')888default_vc = join(python_vc, 'VC') if python_vc else default889890# Try to get path from registry, if fail use default path891return self.ri.lookup(self.ri.vc, '%0.1f' % self.vs_ver) or default_vc892893@property894def WindowsSdkVersion(self):895"""896Microsoft Windows SDK versions for specified MSVC++ version.897898Return899------900tuple of str901versions902"""903if self.vs_ver <= 9.0:904return '7.0', '6.1', '6.0a'905elif self.vs_ver == 10.0:906return '7.1', '7.0a'907elif self.vs_ver == 11.0:908return '8.0', '8.0a'909elif self.vs_ver == 12.0:910return '8.1', '8.1a'911elif self.vs_ver >= 14.0:912return '10.0', '8.1'913914@property915def WindowsSdkLastVersion(self):916"""917Microsoft Windows SDK last version.918919Return920------921str922version923"""924return self._use_last_dir_name(join(self.WindowsSdkDir, 'lib'))925926@property # noqa: C901927def WindowsSdkDir(self): # noqa: C901 # is too complex (12) # FIXME928"""929Microsoft Windows SDK directory.930931Return932------933str934path935"""936sdkdir = ''937for ver in self.WindowsSdkVersion:938# Try to get it from registry939loc = join(self.ri.windows_sdk, 'v%s' % ver)940sdkdir = self.ri.lookup(loc, 'installationfolder')941if sdkdir:942break943if not sdkdir or not isdir(sdkdir):944# Try to get "VC++ for Python" version from registry945path = join(self.ri.vc_for_python, '%0.1f' % self.vc_ver)946install_base = self.ri.lookup(path, 'installdir')947if install_base:948sdkdir = join(install_base, 'WinSDK')949if not sdkdir or not isdir(sdkdir):950# If fail, use default new path951for ver in self.WindowsSdkVersion:952intver = ver[:ver.rfind('.')]953path = r'Microsoft SDKs\Windows Kits\%s' % intver954d = join(self.ProgramFiles, path)955if isdir(d):956sdkdir = d957if not sdkdir or not isdir(sdkdir):958# If fail, use default old path959for ver in self.WindowsSdkVersion:960path = r'Microsoft SDKs\Windows\v%s' % ver961d = join(self.ProgramFiles, path)962if isdir(d):963sdkdir = d964if not sdkdir:965# If fail, use Platform SDK966sdkdir = join(self.VCInstallDir, 'PlatformSDK')967return sdkdir968969@property970def WindowsSDKExecutablePath(self):971"""972Microsoft Windows SDK executable directory.973974Return975------976str977path978"""979# Find WinSDK NetFx Tools registry dir name980if self.vs_ver <= 11.0:981netfxver = 35982arch = ''983else:984netfxver = 40985hidex86 = True if self.vs_ver <= 12.0 else False986arch = self.pi.current_dir(x64=True, hidex86=hidex86)987fx = 'WinSDK-NetFx%dTools%s' % (netfxver, arch.replace('\\', '-'))988989# list all possibles registry paths990regpaths = []991if self.vs_ver >= 14.0:992for ver in self.NetFxSdkVersion:993regpaths += [join(self.ri.netfx_sdk, ver, fx)]994995for ver in self.WindowsSdkVersion:996regpaths += [join(self.ri.windows_sdk, 'v%sA' % ver, fx)]997998# Return installation folder from the more recent path999for path in regpaths:1000execpath = self.ri.lookup(path, 'installationfolder')1001if execpath:1002return execpath10031004@property1005def FSharpInstallDir(self):1006"""1007Microsoft Visual F# directory.10081009Return1010------1011str1012path1013"""1014path = join(self.ri.visualstudio, r'%0.1f\Setup\F#' % self.vs_ver)1015return self.ri.lookup(path, 'productdir') or ''10161017@property1018def UniversalCRTSdkDir(self):1019"""1020Microsoft Universal CRT SDK directory.10211022Return1023------1024str1025path1026"""1027# Set Kit Roots versions for specified MSVC++ version1028vers = ('10', '81') if self.vs_ver >= 14.0 else ()10291030# Find path of the more recent Kit1031for ver in vers:1032sdkdir = self.ri.lookup(self.ri.windows_kits_roots,1033'kitsroot%s' % ver)1034if sdkdir:1035return sdkdir or ''10361037@property1038def UniversalCRTSdkLastVersion(self):1039"""1040Microsoft Universal C Runtime SDK last version.10411042Return1043------1044str1045version1046"""1047return self._use_last_dir_name(join(self.UniversalCRTSdkDir, 'lib'))10481049@property1050def NetFxSdkVersion(self):1051"""1052Microsoft .NET Framework SDK versions.10531054Return1055------1056tuple of str1057versions1058"""1059# Set FxSdk versions for specified VS version1060return (('4.7.2', '4.7.1', '4.7',1061'4.6.2', '4.6.1', '4.6',1062'4.5.2', '4.5.1', '4.5')1063if self.vs_ver >= 14.0 else ())10641065@property1066def NetFxSdkDir(self):1067"""1068Microsoft .NET Framework SDK directory.10691070Return1071------1072str1073path1074"""1075sdkdir = ''1076for ver in self.NetFxSdkVersion:1077loc = join(self.ri.netfx_sdk, ver)1078sdkdir = self.ri.lookup(loc, 'kitsinstallationfolder')1079if sdkdir:1080break1081return sdkdir10821083@property1084def FrameworkDir32(self):1085"""1086Microsoft .NET Framework 32bit directory.10871088Return1089------1090str1091path1092"""1093# Default path1094guess_fw = join(self.WinDir, r'Microsoft.NET\Framework')10951096# Try to get path from registry, if fail use default path1097return self.ri.lookup(self.ri.vc, 'frameworkdir32') or guess_fw10981099@property1100def FrameworkDir64(self):1101"""1102Microsoft .NET Framework 64bit directory.11031104Return1105------1106str1107path1108"""1109# Default path1110guess_fw = join(self.WinDir, r'Microsoft.NET\Framework64')11111112# Try to get path from registry, if fail use default path1113return self.ri.lookup(self.ri.vc, 'frameworkdir64') or guess_fw11141115@property1116def FrameworkVersion32(self):1117"""1118Microsoft .NET Framework 32bit versions.11191120Return1121------1122tuple of str1123versions1124"""1125return self._find_dot_net_versions(32)11261127@property1128def FrameworkVersion64(self):1129"""1130Microsoft .NET Framework 64bit versions.11311132Return1133------1134tuple of str1135versions1136"""1137return self._find_dot_net_versions(64)11381139def _find_dot_net_versions(self, bits):1140"""1141Find Microsoft .NET Framework versions.11421143Parameters1144----------1145bits: int1146Platform number of bits: 32 or 64.11471148Return1149------1150tuple of str1151versions1152"""1153# Find actual .NET version in registry1154reg_ver = self.ri.lookup(self.ri.vc, 'frameworkver%d' % bits)1155dot_net_dir = getattr(self, 'FrameworkDir%d' % bits)1156ver = reg_ver or self._use_last_dir_name(dot_net_dir, 'v') or ''11571158# Set .NET versions for specified MSVC++ version1159if self.vs_ver >= 12.0:1160return ver, 'v4.0'1161elif self.vs_ver >= 10.0:1162return 'v4.0.30319' if ver.lower()[:2] != 'v4' else ver, 'v3.5'1163elif self.vs_ver == 9.0:1164return 'v3.5', 'v2.0.50727'1165elif self.vs_ver == 8.0:1166return 'v3.0', 'v2.0.50727'11671168@staticmethod1169def _use_last_dir_name(path, prefix=''):1170"""1171Return name of the last dir in path or '' if no dir found.11721173Parameters1174----------1175path: str1176Use dirs in this path1177prefix: str1178Use only dirs starting by this prefix11791180Return1181------1182str1183name1184"""1185matching_dirs = (1186dir_name1187for dir_name in reversed(listdir(path))1188if isdir(join(path, dir_name)) and1189dir_name.startswith(prefix)1190)1191return next(matching_dirs, None) or ''119211931194class EnvironmentInfo:1195"""1196Return environment variables for specified Microsoft Visual C++ version1197and platform : Lib, Include, Path and libpath.11981199This function is compatible with Microsoft Visual C++ 9.0 to 14.X.12001201Script created by analysing Microsoft environment configuration files like1202"vcvars[...].bat", "SetEnv.Cmd", "vcbuildtools.bat", ...12031204Parameters1205----------1206arch: str1207Target architecture.1208vc_ver: float1209Required Microsoft Visual C++ version. If not set, autodetect the last1210version.1211vc_min_ver: float1212Minimum Microsoft Visual C++ version.1213"""12141215# Variables and properties in this class use originals CamelCase variables1216# names from Microsoft source files for more easy comparison.12171218def __init__(self, arch, vc_ver=None, vc_min_ver=0):1219self.pi = PlatformInfo(arch)1220self.ri = RegistryInfo(self.pi)1221self.si = SystemInfo(self.ri, vc_ver)12221223if self.vc_ver < vc_min_ver:1224err = 'No suitable Microsoft Visual C++ version found'1225raise distutils.errors.DistutilsPlatformError(err)12261227@property1228def vs_ver(self):1229"""1230Microsoft Visual Studio.12311232Return1233------1234float1235version1236"""1237return self.si.vs_ver12381239@property1240def vc_ver(self):1241"""1242Microsoft Visual C++ version.12431244Return1245------1246float1247version1248"""1249return self.si.vc_ver12501251@property1252def VSTools(self):1253"""1254Microsoft Visual Studio Tools.12551256Return1257------1258list of str1259paths1260"""1261paths = [r'Common7\IDE', r'Common7\Tools']12621263if self.vs_ver >= 14.0:1264arch_subdir = self.pi.current_dir(hidex86=True, x64=True)1265paths += [r'Common7\IDE\CommonExtensions\Microsoft\TestWindow']1266paths += [r'Team Tools\Performance Tools']1267paths += [r'Team Tools\Performance Tools%s' % arch_subdir]12681269return [join(self.si.VSInstallDir, path) for path in paths]12701271@property1272def VCIncludes(self):1273"""1274Microsoft Visual C++ & Microsoft Foundation Class Includes.12751276Return1277------1278list of str1279paths1280"""1281return [join(self.si.VCInstallDir, 'Include'),1282join(self.si.VCInstallDir, r'ATLMFC\Include')]12831284@property1285def VCLibraries(self):1286"""1287Microsoft Visual C++ & Microsoft Foundation Class Libraries.12881289Return1290------1291list of str1292paths1293"""1294if self.vs_ver >= 15.0:1295arch_subdir = self.pi.target_dir(x64=True)1296else:1297arch_subdir = self.pi.target_dir(hidex86=True)1298paths = ['Lib%s' % arch_subdir, r'ATLMFC\Lib%s' % arch_subdir]12991300if self.vs_ver >= 14.0:1301paths += [r'Lib\store%s' % arch_subdir]13021303return [join(self.si.VCInstallDir, path) for path in paths]13041305@property1306def VCStoreRefs(self):1307"""1308Microsoft Visual C++ store references Libraries.13091310Return1311------1312list of str1313paths1314"""1315if self.vs_ver < 14.0:1316return []1317return [join(self.si.VCInstallDir, r'Lib\store\references')]13181319@property1320def VCTools(self):1321"""1322Microsoft Visual C++ Tools.13231324Return1325------1326list of str1327paths1328"""1329si = self.si1330tools = [join(si.VCInstallDir, 'VCPackages')]13311332forcex86 = True if self.vs_ver <= 10.0 else False1333arch_subdir = self.pi.cross_dir(forcex86)1334if arch_subdir:1335tools += [join(si.VCInstallDir, 'Bin%s' % arch_subdir)]13361337if self.vs_ver == 14.0:1338path = 'Bin%s' % self.pi.current_dir(hidex86=True)1339tools += [join(si.VCInstallDir, path)]13401341elif self.vs_ver >= 15.0:1342host_dir = (r'bin\HostX86%s' if self.pi.current_is_x86() else1343r'bin\HostX64%s')1344tools += [join(1345si.VCInstallDir, host_dir % self.pi.target_dir(x64=True))]13461347if self.pi.current_cpu != self.pi.target_cpu:1348tools += [join(1349si.VCInstallDir, host_dir % self.pi.current_dir(x64=True))]13501351else:1352tools += [join(si.VCInstallDir, 'Bin')]13531354return tools13551356@property1357def OSLibraries(self):1358"""1359Microsoft Windows SDK Libraries.13601361Return1362------1363list of str1364paths1365"""1366if self.vs_ver <= 10.0:1367arch_subdir = self.pi.target_dir(hidex86=True, x64=True)1368return [join(self.si.WindowsSdkDir, 'Lib%s' % arch_subdir)]13691370else:1371arch_subdir = self.pi.target_dir(x64=True)1372lib = join(self.si.WindowsSdkDir, 'lib')1373libver = self._sdk_subdir1374return [join(lib, '%sum%s' % (libver, arch_subdir))]13751376@property1377def OSIncludes(self):1378"""1379Microsoft Windows SDK Include.13801381Return1382------1383list of str1384paths1385"""1386include = join(self.si.WindowsSdkDir, 'include')13871388if self.vs_ver <= 10.0:1389return [include, join(include, 'gl')]13901391else:1392if self.vs_ver >= 14.0:1393sdkver = self._sdk_subdir1394else:1395sdkver = ''1396return [join(include, '%sshared' % sdkver),1397join(include, '%sum' % sdkver),1398join(include, '%swinrt' % sdkver)]13991400@property1401def OSLibpath(self):1402"""1403Microsoft Windows SDK Libraries Paths.14041405Return1406------1407list of str1408paths1409"""1410ref = join(self.si.WindowsSdkDir, 'References')1411libpath = []14121413if self.vs_ver <= 9.0:1414libpath += self.OSLibraries14151416if self.vs_ver >= 11.0:1417libpath += [join(ref, r'CommonConfiguration\Neutral')]14181419if self.vs_ver >= 14.0:1420libpath += [1421ref,1422join(self.si.WindowsSdkDir, 'UnionMetadata'),1423join(1424ref, 'Windows.Foundation.UniversalApiContract', '1.0.0.0'),1425join(ref, 'Windows.Foundation.FoundationContract', '1.0.0.0'),1426join(1427ref, 'Windows.Networking.Connectivity.WwanContract',1428'1.0.0.0'),1429join(1430self.si.WindowsSdkDir, 'ExtensionSDKs', 'Microsoft.VCLibs',1431'%0.1f' % self.vs_ver, 'References', 'CommonConfiguration',1432'neutral'),1433]1434return libpath14351436@property1437def SdkTools(self):1438"""1439Microsoft Windows SDK Tools.14401441Return1442------1443list of str1444paths1445"""1446return list(self._sdk_tools())14471448def _sdk_tools(self):1449"""1450Microsoft Windows SDK Tools paths generator.14511452Return1453------1454generator of str1455paths1456"""1457if self.vs_ver < 15.0:1458bin_dir = 'Bin' if self.vs_ver <= 11.0 else r'Bin\x86'1459yield join(self.si.WindowsSdkDir, bin_dir)14601461if not self.pi.current_is_x86():1462arch_subdir = self.pi.current_dir(x64=True)1463path = 'Bin%s' % arch_subdir1464yield join(self.si.WindowsSdkDir, path)14651466if self.vs_ver in (10.0, 11.0):1467if self.pi.target_is_x86():1468arch_subdir = ''1469else:1470arch_subdir = self.pi.current_dir(hidex86=True, x64=True)1471path = r'Bin\NETFX 4.0 Tools%s' % arch_subdir1472yield join(self.si.WindowsSdkDir, path)14731474elif self.vs_ver >= 15.0:1475path = join(self.si.WindowsSdkDir, 'Bin')1476arch_subdir = self.pi.current_dir(x64=True)1477sdkver = self.si.WindowsSdkLastVersion1478yield join(path, '%s%s' % (sdkver, arch_subdir))14791480if self.si.WindowsSDKExecutablePath:1481yield self.si.WindowsSDKExecutablePath14821483@property1484def _sdk_subdir(self):1485"""1486Microsoft Windows SDK version subdir.14871488Return1489------1490str1491subdir1492"""1493ucrtver = self.si.WindowsSdkLastVersion1494return ('%s\\' % ucrtver) if ucrtver else ''14951496@property1497def SdkSetup(self):1498"""1499Microsoft Windows SDK Setup.15001501Return1502------1503list of str1504paths1505"""1506if self.vs_ver > 9.0:1507return []15081509return [join(self.si.WindowsSdkDir, 'Setup')]15101511@property1512def FxTools(self):1513"""1514Microsoft .NET Framework Tools.15151516Return1517------1518list of str1519paths1520"""1521pi = self.pi1522si = self.si15231524if self.vs_ver <= 10.0:1525include32 = True1526include64 = not pi.target_is_x86() and not pi.current_is_x86()1527else:1528include32 = pi.target_is_x86() or pi.current_is_x86()1529include64 = pi.current_cpu == 'amd64' or pi.target_cpu == 'amd64'15301531tools = []1532if include32:1533tools += [join(si.FrameworkDir32, ver)1534for ver in si.FrameworkVersion32]1535if include64:1536tools += [join(si.FrameworkDir64, ver)1537for ver in si.FrameworkVersion64]1538return tools15391540@property1541def NetFxSDKLibraries(self):1542"""1543Microsoft .Net Framework SDK Libraries.15441545Return1546------1547list of str1548paths1549"""1550if self.vs_ver < 14.0 or not self.si.NetFxSdkDir:1551return []15521553arch_subdir = self.pi.target_dir(x64=True)1554return [join(self.si.NetFxSdkDir, r'lib\um%s' % arch_subdir)]15551556@property1557def NetFxSDKIncludes(self):1558"""1559Microsoft .Net Framework SDK Includes.15601561Return1562------1563list of str1564paths1565"""1566if self.vs_ver < 14.0 or not self.si.NetFxSdkDir:1567return []15681569return [join(self.si.NetFxSdkDir, r'include\um')]15701571@property1572def VsTDb(self):1573"""1574Microsoft Visual Studio Team System Database.15751576Return1577------1578list of str1579paths1580"""1581return [join(self.si.VSInstallDir, r'VSTSDB\Deploy')]15821583@property1584def MSBuild(self):1585"""1586Microsoft Build Engine.15871588Return1589------1590list of str1591paths1592"""1593if self.vs_ver < 12.0:1594return []1595elif self.vs_ver < 15.0:1596base_path = self.si.ProgramFilesx861597arch_subdir = self.pi.current_dir(hidex86=True)1598else:1599base_path = self.si.VSInstallDir1600arch_subdir = ''16011602path = r'MSBuild\%0.1f\bin%s' % (self.vs_ver, arch_subdir)1603build = [join(base_path, path)]16041605if self.vs_ver >= 15.0:1606# Add Roslyn C# & Visual Basic Compiler1607build += [join(base_path, path, 'Roslyn')]16081609return build16101611@property1612def HTMLHelpWorkshop(self):1613"""1614Microsoft HTML Help Workshop.16151616Return1617------1618list of str1619paths1620"""1621if self.vs_ver < 11.0:1622return []16231624return [join(self.si.ProgramFilesx86, 'HTML Help Workshop')]16251626@property1627def UCRTLibraries(self):1628"""1629Microsoft Universal C Runtime SDK Libraries.16301631Return1632------1633list of str1634paths1635"""1636if self.vs_ver < 14.0:1637return []16381639arch_subdir = self.pi.target_dir(x64=True)1640lib = join(self.si.UniversalCRTSdkDir, 'lib')1641ucrtver = self._ucrt_subdir1642return [join(lib, '%sucrt%s' % (ucrtver, arch_subdir))]16431644@property1645def UCRTIncludes(self):1646"""1647Microsoft Universal C Runtime SDK Include.16481649Return1650------1651list of str1652paths1653"""1654if self.vs_ver < 14.0:1655return []16561657include = join(self.si.UniversalCRTSdkDir, 'include')1658return [join(include, '%sucrt' % self._ucrt_subdir)]16591660@property1661def _ucrt_subdir(self):1662"""1663Microsoft Universal C Runtime SDK version subdir.16641665Return1666------1667str1668subdir1669"""1670ucrtver = self.si.UniversalCRTSdkLastVersion1671return ('%s\\' % ucrtver) if ucrtver else ''16721673@property1674def FSharp(self):1675"""1676Microsoft Visual F#.16771678Return1679------1680list of str1681paths1682"""1683if 11.0 > self.vs_ver > 12.0:1684return []16851686return [self.si.FSharpInstallDir]16871688@property1689def VCRuntimeRedist(self):1690"""1691Microsoft Visual C++ runtime redistributable dll.16921693Return1694------1695str1696path1697"""1698vcruntime = 'vcruntime%d0.dll' % self.vc_ver1699arch_subdir = self.pi.target_dir(x64=True).strip('\\')17001701# Installation prefixes candidates1702prefixes = []1703tools_path = self.si.VCInstallDir1704redist_path = dirname(tools_path.replace(r'\Tools', r'\Redist'))1705if isdir(redist_path):1706# Redist version may not be exactly the same as tools1707redist_path = join(redist_path, listdir(redist_path)[-1])1708prefixes += [redist_path, join(redist_path, 'onecore')]17091710prefixes += [join(tools_path, 'redist')] # VS14 legacy path17111712# CRT directory1713crt_dirs = ('Microsoft.VC%d.CRT' % (self.vc_ver * 10),1714# Sometime store in directory with VS version instead of VC1715'Microsoft.VC%d.CRT' % (int(self.vs_ver) * 10))17161717# vcruntime path1718for prefix, crt_dir in itertools.product(prefixes, crt_dirs):1719path = join(prefix, arch_subdir, crt_dir, vcruntime)1720if isfile(path):1721return path17221723def return_env(self, exists=True):1724"""1725Return environment dict.17261727Parameters1728----------1729exists: bool1730It True, only return existing paths.17311732Return1733------1734dict1735environment1736"""1737env = dict(1738include=self._build_paths('include',1739[self.VCIncludes,1740self.OSIncludes,1741self.UCRTIncludes,1742self.NetFxSDKIncludes],1743exists),1744lib=self._build_paths('lib',1745[self.VCLibraries,1746self.OSLibraries,1747self.FxTools,1748self.UCRTLibraries,1749self.NetFxSDKLibraries],1750exists),1751libpath=self._build_paths('libpath',1752[self.VCLibraries,1753self.FxTools,1754self.VCStoreRefs,1755self.OSLibpath],1756exists),1757path=self._build_paths('path',1758[self.VCTools,1759self.VSTools,1760self.VsTDb,1761self.SdkTools,1762self.SdkSetup,1763self.FxTools,1764self.MSBuild,1765self.HTMLHelpWorkshop,1766self.FSharp],1767exists),1768)1769if self.vs_ver >= 14 and isfile(self.VCRuntimeRedist):1770env['py_vcruntime_redist'] = self.VCRuntimeRedist1771return env17721773def _build_paths(self, name, spec_path_lists, exists):1774"""1775Given an environment variable name and specified paths,1776return a pathsep-separated string of paths containing1777unique, extant, directories from those paths and from1778the environment variable. Raise an error if no paths1779are resolved.17801781Parameters1782----------1783name: str1784Environment variable name1785spec_path_lists: list of str1786Paths1787exists: bool1788It True, only return existing paths.17891790Return1791------1792str1793Pathsep-separated paths1794"""1795# flatten spec_path_lists1796spec_paths = itertools.chain.from_iterable(spec_path_lists)1797env_paths = environ.get(name, '').split(pathsep)1798paths = itertools.chain(spec_paths, env_paths)1799extant_paths = list(filter(isdir, paths)) if exists else paths1800if not extant_paths:1801msg = "%s environment variable is empty" % name.upper()1802raise distutils.errors.DistutilsPlatformError(msg)1803unique_paths = unique_everseen(extant_paths)1804return pathsep.join(unique_paths)180518061807