Index: third_party/google-endpoints/setuptools/msvc.py |
diff --git a/third_party/google-endpoints/setuptools/msvc.py b/third_party/google-endpoints/setuptools/msvc.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..97e27303f84e33625500f0676b5ddaa3c6e9cc4e |
--- /dev/null |
+++ b/third_party/google-endpoints/setuptools/msvc.py |
@@ -0,0 +1,1193 @@ |
+""" |
+Improved support for Microsoft Visual C++ compilers. |
+ |
+Known supported compilers: |
+-------------------------- |
+Microsoft Visual C++ 9.0: |
+ Microsoft Visual C++ Compiler for Python 2.7 (x86, amd64); |
+ Microsoft Windows SDK 7.0 (x86, x64, ia64); |
+ Microsoft Windows SDK 6.1 (x86, x64, ia64) |
+ |
+Microsoft Visual C++ 10.0: |
+ Microsoft Windows SDK 7.1 (x86, x64, ia64) |
+ |
+Microsoft Visual C++ 14.0: |
+ Microsoft Visual C++ Build Tools 2015 (x86, x64, arm) |
+""" |
+ |
+import os |
+import sys |
+import platform |
+import itertools |
+import distutils.errors |
+from packaging.version import LegacyVersion |
+ |
+from six.moves import filterfalse |
+ |
+from .monkey import get_unpatched |
+ |
+if platform.system() == 'Windows': |
+ from six.moves import winreg |
+ safe_env = os.environ |
+else: |
+ """ |
+ Mock winreg and environ so the module can be imported |
+ on this platform. |
+ """ |
+ |
+ class winreg: |
+ HKEY_USERS = None |
+ HKEY_CURRENT_USER = None |
+ HKEY_LOCAL_MACHINE = None |
+ HKEY_CLASSES_ROOT = None |
+ |
+ safe_env = dict() |
+ |
+try: |
+ from distutils.msvc9compiler import Reg |
+except ImportError: |
+ pass |
+ |
+ |
+def msvc9_find_vcvarsall(version): |
+ """ |
+ Patched "distutils.msvc9compiler.find_vcvarsall" to use the standalone |
+ compiler build for Python (VCForPython). Fall back to original behavior |
+ when the standalone compiler is not available. |
+ |
+ Redirect the path of "vcvarsall.bat". |
+ |
+ Known supported compilers |
+ ------------------------- |
+ Microsoft Visual C++ 9.0: |
+ Microsoft Visual C++ Compiler for Python 2.7 (x86, amd64) |
+ |
+ Parameters |
+ ---------- |
+ version: float |
+ Required Microsoft Visual C++ version. |
+ |
+ Return |
+ ------ |
+ vcvarsall.bat path: str |
+ """ |
+ VC_BASE = r'Software\%sMicrosoft\DevDiv\VCForPython\%0.1f' |
+ key = VC_BASE % ('', version) |
+ try: |
+ # Per-user installs register the compiler path here |
+ productdir = Reg.get_value(key, "installdir") |
+ except KeyError: |
+ try: |
+ # All-user installs on a 64-bit system register here |
+ key = VC_BASE % ('Wow6432Node\\', version) |
+ productdir = Reg.get_value(key, "installdir") |
+ except KeyError: |
+ productdir = None |
+ |
+ if productdir: |
+ vcvarsall = os.path.os.path.join(productdir, "vcvarsall.bat") |
+ if os.path.isfile(vcvarsall): |
+ return vcvarsall |
+ |
+ return get_unpatched(msvc9_find_vcvarsall)(version) |
+ |
+ |
+def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs): |
+ """ |
+ Patched "distutils.msvc9compiler.query_vcvarsall" for support standalones |
+ compilers. |
+ |
+ Set environment without use of "vcvarsall.bat". |
+ |
+ Known supported compilers |
+ ------------------------- |
+ Microsoft Visual C++ 9.0: |
+ Microsoft Visual C++ Compiler for Python 2.7 (x86, amd64); |
+ Microsoft Windows SDK 7.0 (x86, x64, ia64); |
+ Microsoft Windows SDK 6.1 (x86, x64, ia64) |
+ |
+ Microsoft Visual C++ 10.0: |
+ Microsoft Windows SDK 7.1 (x86, x64, ia64) |
+ |
+ Parameters |
+ ---------- |
+ ver: float |
+ Required Microsoft Visual C++ version. |
+ arch: str |
+ Target architecture. |
+ |
+ Return |
+ ------ |
+ environment: dict |
+ """ |
+ # Try to get environement from vcvarsall.bat (Classical way) |
+ try: |
+ orig = get_unpatched(msvc9_query_vcvarsall) |
+ return orig(ver, arch, *args, **kwargs) |
+ except distutils.errors.DistutilsPlatformError: |
+ # Pass error if Vcvarsall.bat is missing |
+ pass |
+ except ValueError: |
+ # Pass error if environment not set after executing vcvarsall.bat |
+ pass |
+ |
+ # If error, try to set environment directly |
+ try: |
+ return EnvironmentInfo(arch, ver).return_env() |
+ except distutils.errors.DistutilsPlatformError as exc: |
+ _augment_exception(exc, ver, arch) |
+ raise |
+ |
+ |
+def msvc14_get_vc_env(plat_spec): |
+ """ |
+ Patched "distutils._msvccompiler._get_vc_env" for support standalones |
+ compilers. |
+ |
+ Set environment without use of "vcvarsall.bat". |
+ |
+ Known supported compilers |
+ ------------------------- |
+ Microsoft Visual C++ 14.0: |
+ Microsoft Visual C++ Build Tools 2015 (x86, x64, arm) |
+ |
+ Parameters |
+ ---------- |
+ plat_spec: str |
+ Target architecture. |
+ |
+ Return |
+ ------ |
+ environment: dict |
+ """ |
+ # Try to get environment from vcvarsall.bat (Classical way) |
+ try: |
+ return get_unpatched(msvc14_get_vc_env)(plat_spec) |
+ except distutils.errors.DistutilsPlatformError: |
+ # Pass error Vcvarsall.bat is missing |
+ pass |
+ |
+ # If error, try to set environment directly |
+ try: |
+ return EnvironmentInfo(plat_spec, vc_min_ver=14.0).return_env() |
+ except distutils.errors.DistutilsPlatformError as exc: |
+ _augment_exception(exc, 14.0) |
+ raise |
+ |
+ |
+def msvc14_gen_lib_options(*args, **kwargs): |
+ """ |
+ Patched "distutils._msvccompiler.gen_lib_options" for fix |
+ compatibility between "numpy.distutils" and "distutils._msvccompiler" |
+ (for Numpy < 1.11.2) |
+ """ |
+ if "numpy.distutils" in sys.modules: |
+ import numpy as np |
+ if LegacyVersion(np.__version__) < LegacyVersion('1.11.2'): |
+ return np.distutils.ccompiler.gen_lib_options(*args, **kwargs) |
+ return get_unpatched(msvc14_gen_lib_options)(*args, **kwargs) |
+ |
+ |
+def _augment_exception(exc, version, arch=''): |
+ """ |
+ Add details to the exception message to help guide the user |
+ as to what action will resolve it. |
+ """ |
+ # Error if MSVC++ directory not found or environment not set |
+ message = exc.args[0] |
+ |
+ if "vcvarsall" in message.lower() or "visual c" in message.lower(): |
+ # Special error message if MSVC++ not installed |
+ tmpl = 'Microsoft Visual C++ {version:0.1f} is required.' |
+ message = tmpl.format(**locals()) |
+ msdownload = 'www.microsoft.com/download/details.aspx?id=%d' |
+ if version == 9.0: |
+ if arch.lower().find('ia64') > -1: |
+ # For VC++ 9.0, if IA64 support is needed, redirect user |
+ # to Windows SDK 7.0 |
+ message += ' Get it with "Microsoft Windows SDK 7.0": ' |
+ message += msdownload % 3138 |
+ else: |
+ # For VC++ 9.0 redirect user to Vc++ for Python 2.7 : |
+ # This redirection link is maintained by Microsoft. |
+ # Contact vspython@microsoft.com if it needs updating. |
+ message += ' Get it from http://aka.ms/vcpython27' |
+ elif version == 10.0: |
+ # For VC++ 10.0 Redirect user to Windows SDK 7.1 |
+ message += ' Get it with "Microsoft Windows SDK 7.1": ' |
+ message += msdownload % 8279 |
+ elif version >= 14.0: |
+ # For VC++ 14.0 Redirect user to Visual C++ Build Tools |
+ message += (' Get it with "Microsoft Visual C++ Build Tools": ' |
+ r'http://landinghub.visualstudio.com/' |
+ 'visual-cpp-build-tools') |
+ |
+ exc.args = (message, ) |
+ |
+ |
+class PlatformInfo: |
+ """ |
+ Current and Target Architectures informations. |
+ |
+ Parameters |
+ ---------- |
+ arch: str |
+ Target architecture. |
+ """ |
+ current_cpu = safe_env.get('processor_architecture', '').lower() |
+ |
+ def __init__(self, arch): |
+ self.arch = arch.lower().replace('x64', 'amd64') |
+ |
+ @property |
+ def target_cpu(self): |
+ return self.arch[self.arch.find('_') + 1:] |
+ |
+ def target_is_x86(self): |
+ return self.target_cpu == 'x86' |
+ |
+ def current_is_x86(self): |
+ return self.current_cpu == 'x86' |
+ |
+ def current_dir(self, hidex86=False, x64=False): |
+ """ |
+ Current platform specific subfolder. |
+ |
+ Parameters |
+ ---------- |
+ hidex86: bool |
+ return '' and not '\x86' if architecture is x86. |
+ x64: bool |
+ return '\x64' and not '\amd64' if architecture is amd64. |
+ |
+ Return |
+ ------ |
+ subfolder: str |
+ '\target', or '' (see hidex86 parameter) |
+ """ |
+ return ( |
+ '' if (self.current_cpu == 'x86' and hidex86) else |
+ r'\x64' if (self.current_cpu == 'amd64' and x64) else |
+ r'\%s' % self.current_cpu |
+ ) |
+ |
+ def target_dir(self, hidex86=False, x64=False): |
+ """ |
+ Target platform specific subfolder. |
+ |
+ Parameters |
+ ---------- |
+ hidex86: bool |
+ return '' and not '\x86' if architecture is x86. |
+ x64: bool |
+ return '\x64' and not '\amd64' if architecture is amd64. |
+ |
+ Return |
+ ------ |
+ subfolder: str |
+ '\current', or '' (see hidex86 parameter) |
+ """ |
+ return ( |
+ '' if (self.target_cpu == 'x86' and hidex86) else |
+ r'\x64' if (self.target_cpu == 'amd64' and x64) else |
+ r'\%s' % self.target_cpu |
+ ) |
+ |
+ def cross_dir(self, forcex86=False): |
+ """ |
+ Cross platform specific subfolder. |
+ |
+ Parameters |
+ ---------- |
+ forcex86: bool |
+ Use 'x86' as current architecture even if current acritecture is |
+ not x86. |
+ |
+ Return |
+ ------ |
+ subfolder: str |
+ '' if target architecture is current architecture, |
+ '\current_target' if not. |
+ """ |
+ current = 'x86' if forcex86 else self.current_cpu |
+ return ( |
+ '' if self.target_cpu == current else |
+ self.target_dir().replace('\\', '\\%s_' % current) |
+ ) |
+ |
+ |
+class RegistryInfo: |
+ """ |
+ Microsoft Visual Studio related registry informations. |
+ |
+ Parameters |
+ ---------- |
+ platform_info: PlatformInfo |
+ "PlatformInfo" instance. |
+ """ |
+ HKEYS = (winreg.HKEY_USERS, |
+ winreg.HKEY_CURRENT_USER, |
+ winreg.HKEY_LOCAL_MACHINE, |
+ winreg.HKEY_CLASSES_ROOT) |
+ |
+ def __init__(self, platform_info): |
+ self.pi = platform_info |
+ |
+ @property |
+ def visualstudio(self): |
+ """ |
+ Microsoft Visual Studio root registry key. |
+ """ |
+ return 'VisualStudio' |
+ |
+ @property |
+ def sxs(self): |
+ """ |
+ Microsoft Visual Studio SxS registry key. |
+ """ |
+ return os.path.join(self.visualstudio, 'SxS') |
+ |
+ @property |
+ def vc(self): |
+ """ |
+ Microsoft Visual C++ VC7 registry key. |
+ """ |
+ return os.path.join(self.sxs, 'VC7') |
+ |
+ @property |
+ def vs(self): |
+ """ |
+ Microsoft Visual Studio VS7 registry key. |
+ """ |
+ return os.path.join(self.sxs, 'VS7') |
+ |
+ @property |
+ def vc_for_python(self): |
+ """ |
+ Microsoft Visual C++ for Python registry key. |
+ """ |
+ return r'DevDiv\VCForPython' |
+ |
+ @property |
+ def microsoft_sdk(self): |
+ """ |
+ Microsoft SDK registry key. |
+ """ |
+ return 'Microsoft SDKs' |
+ |
+ @property |
+ def windows_sdk(self): |
+ """ |
+ Microsoft Windows/Platform SDK registry key. |
+ """ |
+ return os.path.join(self.microsoft_sdk, 'Windows') |
+ |
+ @property |
+ def netfx_sdk(self): |
+ """ |
+ Microsoft .NET Framework SDK registry key. |
+ """ |
+ return os.path.join(self.microsoft_sdk, 'NETFXSDK') |
+ |
+ @property |
+ def windows_kits_roots(self): |
+ """ |
+ Microsoft Windows Kits Roots registry key. |
+ """ |
+ return r'Windows Kits\Installed Roots' |
+ |
+ def microsoft(self, key, x86=False): |
+ """ |
+ Return key in Microsoft software registry. |
+ |
+ Parameters |
+ ---------- |
+ key: str |
+ Registry key path where look. |
+ x86: str |
+ Force x86 software registry. |
+ |
+ Return |
+ ------ |
+ str: value |
+ """ |
+ node64 = '' if self.pi.current_is_x86() or x86 else r'\Wow6432Node' |
+ return os.path.join('Software', node64, 'Microsoft', key) |
+ |
+ def lookup(self, key, name): |
+ """ |
+ Look for values in registry in Microsoft software registry. |
+ |
+ Parameters |
+ ---------- |
+ key: str |
+ Registry key path where look. |
+ name: str |
+ Value name to find. |
+ |
+ Return |
+ ------ |
+ str: value |
+ """ |
+ KEY_READ = winreg.KEY_READ |
+ openkey = winreg.OpenKey |
+ ms = self.microsoft |
+ for hkey in self.HKEYS: |
+ try: |
+ bkey = openkey(hkey, ms(key), 0, KEY_READ) |
+ except (OSError, IOError): |
+ if not self.pi.current_is_x86(): |
+ try: |
+ bkey = openkey(hkey, ms(key, True), 0, KEY_READ) |
+ except (OSError, IOError): |
+ continue |
+ else: |
+ continue |
+ try: |
+ return winreg.QueryValueEx(bkey, name)[0] |
+ except (OSError, IOError): |
+ pass |
+ |
+ |
+class SystemInfo: |
+ """ |
+ Microsoft Windows and Visual Studio related system inormations. |
+ |
+ Parameters |
+ ---------- |
+ registry_info: RegistryInfo |
+ "RegistryInfo" instance. |
+ vc_ver: float |
+ Required Microsoft Visual C++ version. |
+ """ |
+ |
+ # Variables and properties in this class use originals CamelCase variables |
+ # names from Microsoft source files for more easy comparaison. |
+ WinDir = safe_env.get('WinDir', '') |
+ ProgramFiles = safe_env.get('ProgramFiles', '') |
+ ProgramFilesx86 = safe_env.get('ProgramFiles(x86)', ProgramFiles) |
+ |
+ def __init__(self, registry_info, vc_ver=None): |
+ self.ri = registry_info |
+ self.pi = self.ri.pi |
+ if vc_ver: |
+ self.vc_ver = vc_ver |
+ else: |
+ try: |
+ self.vc_ver = self.find_available_vc_vers()[-1] |
+ except IndexError: |
+ err = 'No Microsoft Visual C++ version found' |
+ raise distutils.errors.DistutilsPlatformError(err) |
+ |
+ def find_available_vc_vers(self): |
+ """ |
+ Find all available Microsoft Visual C++ versions. |
+ """ |
+ vckeys = (self.ri.vc, self.ri.vc_for_python) |
+ vc_vers = [] |
+ for hkey in self.ri.HKEYS: |
+ for key in vckeys: |
+ try: |
+ bkey = winreg.OpenKey(hkey, key, 0, winreg.KEY_READ) |
+ except (OSError, IOError): |
+ continue |
+ subkeys, values, _ = winreg.QueryInfoKey(bkey) |
+ for i in range(values): |
+ try: |
+ ver = float(winreg.EnumValue(bkey, i)[0]) |
+ if ver not in vc_vers: |
+ vc_vers.append(ver) |
+ except ValueError: |
+ pass |
+ for i in range(subkeys): |
+ try: |
+ ver = float(winreg.EnumKey(bkey, i)) |
+ if ver not in vc_vers: |
+ vc_vers.append(ver) |
+ except ValueError: |
+ pass |
+ return sorted(vc_vers) |
+ |
+ @property |
+ def VSInstallDir(self): |
+ """ |
+ Microsoft Visual Studio directory. |
+ """ |
+ # Default path |
+ name = 'Microsoft Visual Studio %0.1f' % self.vc_ver |
+ default = os.path.join(self.ProgramFilesx86, name) |
+ |
+ # Try to get path from registry, if fail use default path |
+ return self.ri.lookup(self.ri.vs, '%0.1f' % self.vc_ver) or default |
+ |
+ @property |
+ def VCInstallDir(self): |
+ """ |
+ Microsoft Visual C++ directory. |
+ """ |
+ # Default path |
+ default = r'Microsoft Visual Studio %0.1f\VC' % self.vc_ver |
+ guess_vc = os.path.join(self.ProgramFilesx86, default) |
+ |
+ # Try to get "VC++ for Python" path from registry as default path |
+ reg_path = os.path.join(self.ri.vc_for_python, '%0.1f' % self.vc_ver) |
+ python_vc = self.ri.lookup(reg_path, 'installdir') |
+ default_vc = os.path.join(python_vc, 'VC') if python_vc else guess_vc |
+ |
+ # Try to get path from registry, if fail use default path |
+ path = self.ri.lookup(self.ri.vc, '%0.1f' % self.vc_ver) or default_vc |
+ |
+ if not os.path.isdir(path): |
+ msg = 'Microsoft Visual C++ directory not found' |
+ raise distutils.errors.DistutilsPlatformError(msg) |
+ |
+ return path |
+ |
+ @property |
+ def WindowsSdkVersion(self): |
+ """ |
+ Microsoft Windows SDK versions. |
+ """ |
+ # Set Windows SDK versions for specified MSVC++ version |
+ if self.vc_ver <= 9.0: |
+ return ('7.0', '6.1', '6.0a') |
+ elif self.vc_ver == 10.0: |
+ return ('7.1', '7.0a') |
+ elif self.vc_ver == 11.0: |
+ return ('8.0', '8.0a') |
+ elif self.vc_ver == 12.0: |
+ return ('8.1', '8.1a') |
+ elif self.vc_ver >= 14.0: |
+ return ('10.0', '8.1') |
+ |
+ @property |
+ def WindowsSdkDir(self): |
+ """ |
+ Microsoft Windows SDK directory. |
+ """ |
+ sdkdir = '' |
+ for ver in self.WindowsSdkVersion: |
+ # Try to get it from registry |
+ loc = os.path.join(self.ri.windows_sdk, 'v%s' % ver) |
+ sdkdir = self.ri.lookup(loc, 'installationfolder') |
+ if sdkdir: |
+ break |
+ if not sdkdir or not os.path.isdir(sdkdir): |
+ # Try to get "VC++ for Python" version from registry |
+ path = os.path.join(self.ri.vc_for_python, '%0.1f' % self.vc_ver) |
+ install_base = self.ri.lookup(path, 'installdir') |
+ if install_base: |
+ sdkdir = os.path.join(install_base, 'WinSDK') |
+ if not sdkdir or not os.path.isdir(sdkdir): |
+ # If fail, use default new path |
+ for ver in self.WindowsSdkVersion: |
+ intver = ver[:ver.rfind('.')] |
+ path = r'Microsoft SDKs\Windows Kits\%s' % (intver) |
+ d = os.path.join(self.ProgramFiles, path) |
+ if os.path.isdir(d): |
+ sdkdir = d |
+ if not sdkdir or not os.path.isdir(sdkdir): |
+ # If fail, use default old path |
+ for ver in self.WindowsSdkVersion: |
+ path = r'Microsoft SDKs\Windows\v%s' % ver |
+ d = os.path.join(self.ProgramFiles, path) |
+ if os.path.isdir(d): |
+ sdkdir = d |
+ if not sdkdir: |
+ # If fail, use Platform SDK |
+ sdkdir = os.path.join(self.VCInstallDir, 'PlatformSDK') |
+ return sdkdir |
+ |
+ @property |
+ def WindowsSDKExecutablePath(self): |
+ """ |
+ Microsoft Windows SDK executable directory. |
+ """ |
+ # Find WinSDK NetFx Tools registry dir name |
+ if self.vc_ver <= 11.0: |
+ netfxver = 35 |
+ arch = '' |
+ else: |
+ netfxver = 40 |
+ hidex86 = True if self.vc_ver <= 12.0 else False |
+ arch = self.pi.current_dir(x64=True, hidex86=hidex86) |
+ fx = 'WinSDK-NetFx%dTools%s' % (netfxver, arch.replace('\\', '-')) |
+ |
+ # liste all possibles registry paths |
+ regpaths = [] |
+ if self.vc_ver >= 14.0: |
+ for ver in self.NetFxSdkVersion: |
+ regpaths += [os.path.join(self.ri.netfx_sdk, ver, fx)] |
+ |
+ for ver in self.WindowsSdkVersion: |
+ regpaths += [os.path.join(self.ri.windows_sdk, 'v%sA' % ver, fx)] |
+ |
+ # Return installation folder from the more recent path |
+ for path in regpaths: |
+ execpath = self.ri.lookup(path, 'installationfolder') |
+ if execpath: |
+ break |
+ return execpath |
+ |
+ @property |
+ def FSharpInstallDir(self): |
+ """ |
+ Microsoft Visual F# directory. |
+ """ |
+ path = r'%0.1f\Setup\F#' % self.vc_ver |
+ path = os.path.join(self.ri.visualstudio, path) |
+ return self.ri.lookup(path, 'productdir') or '' |
+ |
+ @property |
+ def UniversalCRTSdkDir(self): |
+ """ |
+ Microsoft Universal CRT SDK directory. |
+ """ |
+ # Set Kit Roots versions for specified MSVC++ version |
+ if self.vc_ver >= 14.0: |
+ vers = ('10', '81') |
+ else: |
+ vers = () |
+ |
+ # Find path of the more recent Kit |
+ for ver in vers: |
+ sdkdir = self.ri.lookup(self.ri.windows_kits_roots, |
+ 'kitsroot%s' % ver) |
+ if sdkdir: |
+ break |
+ return sdkdir or '' |
+ |
+ @property |
+ def NetFxSdkVersion(self): |
+ """ |
+ Microsoft .NET Framework SDK versions. |
+ """ |
+ # Set FxSdk versions for specified MSVC++ version |
+ if self.vc_ver >= 14.0: |
+ return ('4.6.1', '4.6') |
+ else: |
+ return () |
+ |
+ @property |
+ def NetFxSdkDir(self): |
+ """ |
+ Microsoft .NET Framework SDK directory. |
+ """ |
+ for ver in self.NetFxSdkVersion: |
+ loc = os.path.join(self.ri.netfx_sdk, ver) |
+ sdkdir = self.ri.lookup(loc, 'kitsinstallationfolder') |
+ if sdkdir: |
+ break |
+ return sdkdir or '' |
+ |
+ @property |
+ def FrameworkDir32(self): |
+ """ |
+ Microsoft .NET Framework 32bit directory. |
+ """ |
+ # Default path |
+ guess_fw = os.path.join(self.WinDir, r'Microsoft.NET\Framework') |
+ |
+ # Try to get path from registry, if fail use default path |
+ return self.ri.lookup(self.ri.vc, 'frameworkdir32') or guess_fw |
+ |
+ @property |
+ def FrameworkDir64(self): |
+ """ |
+ Microsoft .NET Framework 64bit directory. |
+ """ |
+ # Default path |
+ guess_fw = os.path.join(self.WinDir, r'Microsoft.NET\Framework64') |
+ |
+ # Try to get path from registry, if fail use default path |
+ return self.ri.lookup(self.ri.vc, 'frameworkdir64') or guess_fw |
+ |
+ @property |
+ def FrameworkVersion32(self): |
+ """ |
+ Microsoft .NET Framework 32bit versions. |
+ """ |
+ return self._find_dot_net_versions(32) |
+ |
+ @property |
+ def FrameworkVersion64(self): |
+ """ |
+ Microsoft .NET Framework 64bit versions. |
+ """ |
+ return self._find_dot_net_versions(64) |
+ |
+ def _find_dot_net_versions(self, bits=32): |
+ """ |
+ Find Microsoft .NET Framework versions. |
+ |
+ Parameters |
+ ---------- |
+ bits: int |
+ Platform number of bits: 32 or 64. |
+ """ |
+ # Find actual .NET version |
+ ver = self.ri.lookup(self.ri.vc, 'frameworkver%d' % bits) or '' |
+ |
+ # Set .NET versions for specified MSVC++ version |
+ if self.vc_ver >= 12.0: |
+ frameworkver = (ver, 'v4.0') |
+ elif self.vc_ver >= 10.0: |
+ frameworkver = ('v4.0.30319' if ver.lower()[:2] != 'v4' else ver, |
+ 'v3.5') |
+ elif self.vc_ver == 9.0: |
+ frameworkver = ('v3.5', 'v2.0.50727') |
+ if self.vc_ver == 8.0: |
+ frameworkver = ('v3.0', 'v2.0.50727') |
+ return frameworkver |
+ |
+ |
+class EnvironmentInfo: |
+ """ |
+ Return environment variables for specified Microsoft Visual C++ version |
+ and platform : Lib, Include, Path and libpath. |
+ |
+ This function is compatible with Microsoft Visual C++ 9.0 to 14.0. |
+ |
+ Script created by analysing Microsoft environment configuration files like |
+ "vcvars[...].bat", "SetEnv.Cmd", "vcbuildtools.bat", ... |
+ |
+ Parameters |
+ ---------- |
+ arch: str |
+ Target architecture. |
+ vc_ver: float |
+ Required Microsoft Visual C++ version. If not set, autodetect the last |
+ version. |
+ vc_min_ver: float |
+ Minimum Microsoft Visual C++ version. |
+ """ |
+ |
+ # Variables and properties in this class use originals CamelCase variables |
+ # names from Microsoft source files for more easy comparaison. |
+ |
+ def __init__(self, arch, vc_ver=None, vc_min_ver=None): |
+ self.pi = PlatformInfo(arch) |
+ self.ri = RegistryInfo(self.pi) |
+ self.si = SystemInfo(self.ri, vc_ver) |
+ |
+ if vc_min_ver: |
+ if self.vc_ver < vc_min_ver: |
+ err = 'No suitable Microsoft Visual C++ version found' |
+ raise distutils.errors.DistutilsPlatformError(err) |
+ |
+ @property |
+ def vc_ver(self): |
+ """ |
+ Microsoft Visual C++ version. |
+ """ |
+ return self.si.vc_ver |
+ |
+ @property |
+ def VSTools(self): |
+ """ |
+ Microsoft Visual Studio Tools |
+ """ |
+ paths = [r'Common7\IDE', r'Common7\Tools'] |
+ |
+ if self.vc_ver >= 14.0: |
+ arch_subdir = self.pi.current_dir(hidex86=True, x64=True) |
+ paths += [r'Common7\IDE\CommonExtensions\Microsoft\TestWindow'] |
+ paths += [r'Team Tools\Performance Tools'] |
+ paths += [r'Team Tools\Performance Tools%s' % arch_subdir] |
+ |
+ return [os.path.join(self.si.VSInstallDir, path) for path in paths] |
+ |
+ @property |
+ def VCIncludes(self): |
+ """ |
+ Microsoft Visual C++ & Microsoft Foundation Class Includes |
+ """ |
+ return [os.path.join(self.si.VCInstallDir, 'Include'), |
+ os.path.join(self.si.VCInstallDir, r'ATLMFC\Include')] |
+ |
+ @property |
+ def VCLibraries(self): |
+ """ |
+ Microsoft Visual C++ & Microsoft Foundation Class Libraries |
+ """ |
+ arch_subdir = self.pi.target_dir(hidex86=True) |
+ paths = ['Lib%s' % arch_subdir, r'ATLMFC\Lib%s' % arch_subdir] |
+ |
+ if self.vc_ver >= 14.0: |
+ paths += [r'Lib\store%s' % arch_subdir] |
+ |
+ return [os.path.join(self.si.VCInstallDir, path) for path in paths] |
+ |
+ @property |
+ def VCStoreRefs(self): |
+ """ |
+ Microsoft Visual C++ store references Libraries |
+ """ |
+ if self.vc_ver < 14.0: |
+ return [] |
+ return [os.path.join(self.si.VCInstallDir, r'Lib\store\references')] |
+ |
+ @property |
+ def VCTools(self): |
+ """ |
+ Microsoft Visual C++ Tools |
+ """ |
+ si = self.si |
+ tools = [os.path.join(si.VCInstallDir, 'VCPackages')] |
+ |
+ forcex86 = True if self.vc_ver <= 10.0 else False |
+ arch_subdir = self.pi.cross_dir(forcex86) |
+ if arch_subdir: |
+ tools += [os.path.join(si.VCInstallDir, 'Bin%s' % arch_subdir)] |
+ |
+ if self.vc_ver >= 14.0: |
+ path = 'Bin%s' % self.pi.current_dir(hidex86=True) |
+ tools += [os.path.join(si.VCInstallDir, path)] |
+ |
+ else: |
+ tools += [os.path.join(si.VCInstallDir, 'Bin')] |
+ |
+ return tools |
+ |
+ @property |
+ def OSLibraries(self): |
+ """ |
+ Microsoft Windows SDK Libraries |
+ """ |
+ if self.vc_ver <= 10.0: |
+ arch_subdir = self.pi.target_dir(hidex86=True, x64=True) |
+ return [os.path.join(self.si.WindowsSdkDir, 'Lib%s' % arch_subdir)] |
+ |
+ else: |
+ arch_subdir = self.pi.target_dir(x64=True) |
+ lib = os.path.join(self.si.WindowsSdkDir, 'lib') |
+ libver = self._get_content_dirname(lib) |
+ return [os.path.join(lib, '%sum%s' % (libver, arch_subdir))] |
+ |
+ @property |
+ def OSIncludes(self): |
+ """ |
+ Microsoft Windows SDK Include |
+ """ |
+ include = os.path.join(self.si.WindowsSdkDir, 'include') |
+ |
+ if self.vc_ver <= 10.0: |
+ return [include, os.path.join(include, 'gl')] |
+ |
+ else: |
+ if self.vc_ver >= 14.0: |
+ sdkver = self._get_content_dirname(include) |
+ else: |
+ sdkver = '' |
+ return [os.path.join(include, '%sshared' % sdkver), |
+ os.path.join(include, '%sum' % sdkver), |
+ os.path.join(include, '%swinrt' % sdkver)] |
+ |
+ @property |
+ def OSLibpath(self): |
+ """ |
+ Microsoft Windows SDK Libraries Paths |
+ """ |
+ ref = os.path.join(self.si.WindowsSdkDir, 'References') |
+ libpath = [] |
+ |
+ if self.vc_ver <= 9.0: |
+ libpath += self.OSLibraries |
+ |
+ if self.vc_ver >= 11.0: |
+ libpath += [os.path.join(ref, r'CommonConfiguration\Neutral')] |
+ |
+ if self.vc_ver >= 14.0: |
+ libpath += [ |
+ ref, |
+ os.path.join(self.si.WindowsSdkDir, 'UnionMetadata'), |
+ os.path.join( |
+ ref, |
+ 'Windows.Foundation.UniversalApiContract', |
+ '1.0.0.0', |
+ ), |
+ os.path.join( |
+ ref, |
+ 'Windows.Foundation.FoundationContract', |
+ '1.0.0.0', |
+ ), |
+ os.path.join( |
+ ref, |
+ 'Windows.Networking.Connectivity.WwanContract', |
+ '1.0.0.0', |
+ ), |
+ os.path.join( |
+ self.si.WindowsSdkDir, |
+ 'ExtensionSDKs', |
+ 'Microsoft.VCLibs', |
+ '%0.1f' % self.vc_ver, |
+ 'References', |
+ 'CommonConfiguration', |
+ 'neutral', |
+ ), |
+ ] |
+ return libpath |
+ |
+ @property |
+ def SdkTools(self): |
+ """ |
+ Microsoft Windows SDK Tools |
+ """ |
+ bin_dir = 'Bin' if self.vc_ver <= 11.0 else r'Bin\x86' |
+ tools = [os.path.join(self.si.WindowsSdkDir, bin_dir)] |
+ |
+ if not self.pi.current_is_x86(): |
+ arch_subdir = self.pi.current_dir(x64=True) |
+ path = 'Bin%s' % arch_subdir |
+ tools += [os.path.join(self.si.WindowsSdkDir, path)] |
+ |
+ if self.vc_ver == 10.0 or self.vc_ver == 11.0: |
+ if self.pi.target_is_x86(): |
+ arch_subdir = '' |
+ else: |
+ arch_subdir = self.pi.current_dir(hidex86=True, x64=True) |
+ path = r'Bin\NETFX 4.0 Tools%s' % arch_subdir |
+ tools += [os.path.join(self.si.WindowsSdkDir, path)] |
+ |
+ if self.si.WindowsSDKExecutablePath: |
+ tools += [self.si.WindowsSDKExecutablePath] |
+ |
+ return tools |
+ |
+ @property |
+ def SdkSetup(self): |
+ """ |
+ Microsoft Windows SDK Setup |
+ """ |
+ if self.vc_ver > 9.0: |
+ return [] |
+ |
+ return [os.path.join(self.si.WindowsSdkDir, 'Setup')] |
+ |
+ @property |
+ def FxTools(self): |
+ """ |
+ Microsoft .NET Framework Tools |
+ """ |
+ pi = self.pi |
+ si = self.si |
+ |
+ if self.vc_ver <= 10.0: |
+ include32 = True |
+ include64 = not pi.target_is_x86() and not pi.current_is_x86() |
+ else: |
+ include32 = pi.target_is_x86() or pi.current_is_x86() |
+ include64 = pi.current_cpu == 'amd64' or pi.target_cpu == 'amd64' |
+ |
+ tools = [] |
+ if include32: |
+ tools += [os.path.join(si.FrameworkDir32, ver) |
+ for ver in si.FrameworkVersion32] |
+ if include64: |
+ tools += [os.path.join(si.FrameworkDir64, ver) |
+ for ver in si.FrameworkVersion64] |
+ return tools |
+ |
+ @property |
+ def NetFxSDKLibraries(self): |
+ """ |
+ Microsoft .Net Framework SDK Libraries |
+ """ |
+ if self.vc_ver < 14.0 or not self.si.NetFxSdkDir: |
+ return [] |
+ |
+ arch_subdir = self.pi.target_dir(x64=True) |
+ return [os.path.join(self.si.NetFxSdkDir, r'lib\um%s' % arch_subdir)] |
+ |
+ @property |
+ def NetFxSDKIncludes(self): |
+ """ |
+ Microsoft .Net Framework SDK Includes |
+ """ |
+ if self.vc_ver < 14.0 or not self.si.NetFxSdkDir: |
+ return [] |
+ |
+ return [os.path.join(self.si.NetFxSdkDir, r'include\um')] |
+ |
+ @property |
+ def VsTDb(self): |
+ """ |
+ Microsoft Visual Studio Team System Database |
+ """ |
+ return [os.path.join(self.si.VSInstallDir, r'VSTSDB\Deploy')] |
+ |
+ @property |
+ def MSBuild(self): |
+ """ |
+ Microsoft Build Engine |
+ """ |
+ if self.vc_ver < 12.0: |
+ return [] |
+ |
+ arch_subdir = self.pi.current_dir(hidex86=True) |
+ path = r'MSBuild\%0.1f\bin%s' % (self.vc_ver, arch_subdir) |
+ return [os.path.join(self.si.ProgramFilesx86, path)] |
+ |
+ @property |
+ def HTMLHelpWorkshop(self): |
+ """ |
+ Microsoft HTML Help Workshop |
+ """ |
+ if self.vc_ver < 11.0: |
+ return [] |
+ |
+ return [os.path.join(self.si.ProgramFilesx86, 'HTML Help Workshop')] |
+ |
+ @property |
+ def UCRTLibraries(self): |
+ """ |
+ Microsoft Universal CRT Libraries |
+ """ |
+ if self.vc_ver < 14.0: |
+ return [] |
+ |
+ arch_subdir = self.pi.target_dir(x64=True) |
+ lib = os.path.join(self.si.UniversalCRTSdkDir, 'lib') |
+ ucrtver = self._get_content_dirname(lib) |
+ return [os.path.join(lib, '%sucrt%s' % (ucrtver, arch_subdir))] |
+ |
+ @property |
+ def UCRTIncludes(self): |
+ """ |
+ Microsoft Universal CRT Include |
+ """ |
+ if self.vc_ver < 14.0: |
+ return [] |
+ |
+ include = os.path.join(self.si.UniversalCRTSdkDir, 'include') |
+ ucrtver = self._get_content_dirname(include) |
+ return [os.path.join(include, '%sucrt' % ucrtver)] |
+ |
+ @property |
+ def FSharp(self): |
+ """ |
+ Microsoft Visual F# |
+ """ |
+ if self.vc_ver < 11.0 and self.vc_ver > 12.0: |
+ return [] |
+ |
+ return self.si.FSharpInstallDir |
+ |
+ @property |
+ def VCRuntimeRedist(self): |
+ """ |
+ Microsoft Visual C++ runtime redistribuable dll |
+ """ |
+ arch_subdir = self.pi.target_dir(x64=True) |
+ vcruntime = 'redist%s\\Microsoft.VC%d0.CRT\\vcruntime%d0.dll' |
+ vcruntime = vcruntime % (arch_subdir, self.vc_ver, self.vc_ver) |
+ return os.path.join(self.si.VCInstallDir, vcruntime) |
+ |
+ def return_env(self, exists=True): |
+ """ |
+ Return environment dict. |
+ |
+ Parameters |
+ ---------- |
+ exists: bool |
+ It True, only return existing paths. |
+ """ |
+ env = dict( |
+ include=self._build_paths('include', |
+ [self.VCIncludes, |
+ self.OSIncludes, |
+ self.UCRTIncludes, |
+ self.NetFxSDKIncludes], |
+ exists), |
+ lib=self._build_paths('lib', |
+ [self.VCLibraries, |
+ self.OSLibraries, |
+ self.FxTools, |
+ self.UCRTLibraries, |
+ self.NetFxSDKLibraries], |
+ exists), |
+ libpath=self._build_paths('libpath', |
+ [self.VCLibraries, |
+ self.FxTools, |
+ self.VCStoreRefs, |
+ self.OSLibpath], |
+ exists), |
+ path=self._build_paths('path', |
+ [self.VCTools, |
+ self.VSTools, |
+ self.VsTDb, |
+ self.SdkTools, |
+ self.SdkSetup, |
+ self.FxTools, |
+ self.MSBuild, |
+ self.HTMLHelpWorkshop, |
+ self.FSharp], |
+ exists), |
+ ) |
+ if self.vc_ver >= 14 and os.path.isfile(self.VCRuntimeRedist): |
+ env['py_vcruntime_redist'] = self.VCRuntimeRedist |
+ return env |
+ |
+ def _build_paths(self, name, spec_path_lists, exists): |
+ """ |
+ Given an environment variable name and specified paths, |
+ return a pathsep-separated string of paths containing |
+ unique, extant, directories from those paths and from |
+ the environment variable. Raise an error if no paths |
+ are resolved. |
+ """ |
+ # flatten spec_path_lists |
+ spec_paths = itertools.chain.from_iterable(spec_path_lists) |
+ env_paths = safe_env.get(name, '').split(os.pathsep) |
+ paths = itertools.chain(spec_paths, env_paths) |
+ extant_paths = list(filter(os.path.isdir, paths)) if exists else paths |
+ if not extant_paths: |
+ msg = "%s environment variable is empty" % name.upper() |
+ raise distutils.errors.DistutilsPlatformError(msg) |
+ unique_paths = self._unique_everseen(extant_paths) |
+ return os.pathsep.join(unique_paths) |
+ |
+ # from Python docs |
+ def _unique_everseen(self, iterable, key=None): |
+ """ |
+ List unique elements, preserving order. |
+ Remember all elements ever seen. |
+ |
+ _unique_everseen('AAAABBBCCDAABBB') --> A B C D |
+ |
+ _unique_everseen('ABBCcAD', str.lower) --> A B C D |
+ """ |
+ seen = set() |
+ seen_add = seen.add |
+ if key is None: |
+ for element in filterfalse(seen.__contains__, iterable): |
+ seen_add(element) |
+ yield element |
+ else: |
+ for element in iterable: |
+ k = key(element) |
+ if k not in seen: |
+ seen_add(k) |
+ yield element |
+ |
+ def _get_content_dirname(self, path): |
+ """ |
+ Return name of the first dir in path or '' if no dir found. |
+ |
+ Parameters |
+ ---------- |
+ path: str |
+ Path where search dir. |
+ |
+ Return |
+ ------ |
+ foldername: str |
+ "name\" or "" |
+ """ |
+ try: |
+ name = os.listdir(path) |
+ if name: |
+ return '%s\\' % name[0] |
+ return '' |
+ except (OSError, IOError): |
+ return '' |