From 54325a753f688285c71a6db0a062116e6dc6976c Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 2 Jul 2016 12:06:19 -0400 Subject: Rename msvc9_support to simply msvc. --- setuptools/msvc.py | 1175 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1175 insertions(+) create mode 100644 setuptools/msvc.py (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py new file mode 100644 index 00000000..63031ac2 --- /dev/null +++ b/setuptools/msvc.py @@ -0,0 +1,1175 @@ +""" +This module adds improved support for Microsoft Visual C++ compilers. +""" + +import os +import collections +import itertools +import distutils.errors +from setuptools.extern.six.moves import filterfalse + +try: + from setuptools.extern.six.moves import winreg + safe_env = os.environ +except ImportError: + """ + 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 = collections.defaultdict(lambda: '') + + +try: + # Distutil file for MSVC++ 9.0 and upper (Python 2.7 to 3.4) + import distutils.msvc9compiler as msvc9compiler +except ImportError: + pass + +try: + # Distutil file for MSVC++ 14.0 and upper (Python 3.5+) + import distutils._msvccompiler as msvc14compiler +except ImportError: + pass + + +unpatched = dict() + + +def patch_for_specialized_compiler(): + """ + Patch functions in distutils to use standalone 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) + """ + if 'distutils' not in globals(): + # The module isn't available to be patched + return + + if unpatched: + # Already patched + return + + try: + # Patch distutils.msvc9compiler + unpatched['msvc9_find_vcvarsall'] = msvc9compiler.find_vcvarsall + msvc9compiler.find_vcvarsall = msvc9_find_vcvarsall + unpatched['msvc9_query_vcvarsall'] = msvc9compiler.query_vcvarsall + msvc9compiler.query_vcvarsall = msvc9_query_vcvarsall + except Exception: + pass + + try: + # Patch distutils._msvccompiler._get_vc_env + unpatched['msvc14_get_vc_env'] = msvc14compiler._get_vc_env + msvc14compiler._get_vc_env = msvc14_get_vc_env + except Exception: + 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 + """ + Reg = msvc9compiler.Reg + 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 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: + return unpatched['msvc9_query_vcvarsall'](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 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_ver_min=14.0).return_env() + except distutils.errors.DistutilsPlatformError as exc: + _augment_exception(exc, 14.0) + raise + + +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 + message = 'Microsoft Visual C++ %0.1f is required (%s).' %\ + (version, message) + msdownload = r'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 += r' 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 + + exc.args = (message, ) + + +class PlatformInfo: + """ + Current and Target Architectures informations. + + Parameters + ---------- + arch: str + Target architecture. + """ + current_cpu = safe_env['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 microsoft(self): + """ + Microsoft software registry key. + """ + return os.path.join( + 'Software', + '' if self.pi.current_is_x86() else 'Wow6432Node', + 'Microsoft', + ) + + @property + def visualstudio(self): + """ + Microsoft Visual Studio root registry key. + """ + return os.path.join(self.microsoft, r'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. + """ + path = r'DevDiv\VCForPython' + return os.path.join(self.microsoft, path) + + @property + def microsoft_sdk(self): + """ + Microsoft SDK registry key. + """ + return os.path.join(self.microsoft, '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 os.path.join(self.microsoft, r'Windows Kits\Installed Roots') + + def lookup(self, key, name): + """ + Look for values in registry. + + Parameters + ---------- + key: str + Registry key path where look. + name: str + Value name to find. + + Return + ------ + str: value + """ + for hkey in self.HKEYS: + try: + bkey = winreg.OpenKey(hkey, key, 0, winreg.KEY_READ) + except FileNotFoundError: + continue + try: + return winreg.QueryValueEx(bkey, name)[0] + except FileNotFoundError: + 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['WinDir'] + ProgramFiles = safe_env['ProgramFiles'] + ProgramFilesx86 = os.environ.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 FileNotFoundError: + 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, '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, r'%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, r'Windows.Foundation.' + r'UniversalApiContract\1.0.0.0'), + os.path.join(ref, r'Windows.Foundation.' + r'FoundationContract\1.0.0.0'), + os.path.join(ref, r'Windows.Networking.Connectivity.' + r'WwanContract\1.0.0.0'), + os.path.join(self.si.WindowsSdkDir, r'ExtensionSDKs' + r'\Microsoft.VCLibs\%0.1f\References' + r'\CommonConfiguration\neutral' % + self.vc_ver)] + return libpath + + @property + def SdkTools(self): + """ + Microsoft Windows SDK Tools + """ + tools = [os.path.join(self.si.WindowsSdkDir, + 'Bin' if self.vc_ver <= 11.0 else r'Bin\x86')] + + 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 = os.environ.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 FileNotFoundError: + return '' -- cgit v1.2.1 From f2a0b309367cfdade3c0c18d8c69612010351120 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 2 Jul 2016 12:38:21 -0400 Subject: Extract template as variable to avoid line continuation. --- setuptools/msvc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 63031ac2..500a00f9 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -219,8 +219,8 @@ def _augment_exception(exc, version, arch=''): if "vcvarsall" in message.lower() or "visual c" in message.lower(): # Special error message if MSVC++ not installed - message = 'Microsoft Visual C++ %0.1f is required (%s).' %\ - (version, message) + tmpl = 'Microsoft Visual C++ %0.1f is required (%s).' + message = tmpl % version, message msdownload = r'www.microsoft.com/download/details.aspx?id=%d' if version == 9.0: if arch.lower().find('ia64') > -1: -- cgit v1.2.1 From 0746957d513d74e6a9f5e2375a10d1d4a0a5108c Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 2 Jul 2016 12:41:20 -0400 Subject: Remove superfluous raw strings --- setuptools/msvc.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 500a00f9..27118ed9 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -219,9 +219,9 @@ def _augment_exception(exc, version, arch=''): if "vcvarsall" in message.lower() or "visual c" in message.lower(): # Special error message if MSVC++ not installed - tmpl = 'Microsoft Visual C++ %0.1f is required (%s).' - message = tmpl % version, message - msdownload = r'www.microsoft.com/download/details.aspx?id=%d' + tmpl = 'Microsoft Visual C++ {version:0.1f} is required {message}.' + 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 @@ -232,7 +232,7 @@ def _augment_exception(exc, version, arch=''): # 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 += r' Get it from http://aka.ms/vcpython27' + 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": ' @@ -365,7 +365,7 @@ class RegistryInfo: """ Microsoft Visual Studio root registry key. """ - return os.path.join(self.microsoft, r'VisualStudio') + return os.path.join(self.microsoft, 'VisualStudio') @property def sxs(self): @@ -860,7 +860,7 @@ class EnvironmentInfo: 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, r'%sum%s' % (libver, arch_subdir))] + return [os.path.join(lib, '%sum%s' % (libver, arch_subdir))] @property def OSIncludes(self): @@ -898,13 +898,13 @@ class EnvironmentInfo: if self.vc_ver >= 14.0: libpath += [ref, os.path.join(self.si.WindowsSdkDir, 'UnionMetadata'), - os.path.join(ref, r'Windows.Foundation.' + os.path.join(ref, 'Windows.Foundation.' r'UniversalApiContract\1.0.0.0'), - os.path.join(ref, r'Windows.Foundation.' + os.path.join(ref, 'Windows.Foundation.' r'FoundationContract\1.0.0.0'), - os.path.join(ref, r'Windows.Networking.Connectivity.' + os.path.join(ref, 'Windows.Networking.Connectivity.' r'WwanContract\1.0.0.0'), - os.path.join(self.si.WindowsSdkDir, r'ExtensionSDKs' + os.path.join(self.si.WindowsSdkDir, 'ExtensionSDKs' r'\Microsoft.VCLibs\%0.1f\References' r'\CommonConfiguration\neutral' % self.vc_ver)] -- cgit v1.2.1 From e404a4aa3b3aa62c5f2c956f3076ddb9155a6829 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 2 Jul 2016 12:47:53 -0400 Subject: Reindent to avoid raw strings and hanging indents. Let os.path.join provide the backslash characters. --- setuptools/msvc.py | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 27118ed9..0b483ea3 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -896,18 +896,34 @@ class EnvironmentInfo: 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.' - r'UniversalApiContract\1.0.0.0'), - os.path.join(ref, 'Windows.Foundation.' - r'FoundationContract\1.0.0.0'), - os.path.join(ref, 'Windows.Networking.Connectivity.' - r'WwanContract\1.0.0.0'), - os.path.join(self.si.WindowsSdkDir, 'ExtensionSDKs' - r'\Microsoft.VCLibs\%0.1f\References' - r'\CommonConfiguration\neutral' % - self.vc_ver)] + 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 -- cgit v1.2.1 From 4742d661ab7b6ca643610b2b1f5100cd582d75b9 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 2 Jul 2016 12:48:31 -0400 Subject: Extract variable for bin_dir --- setuptools/msvc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 0b483ea3..bbf66570 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -931,8 +931,8 @@ class EnvironmentInfo: """ Microsoft Windows SDK Tools """ - tools = [os.path.join(self.si.WindowsSdkDir, - 'Bin' if self.vc_ver <= 11.0 else r'Bin\x86')] + 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) -- cgit v1.2.1 From 79d1fc0d9f50af9f51a3c7a7188e4afc644a4aac Mon Sep 17 00:00:00 2001 From: "J. Goutin" Date: Sun, 3 Jul 2016 14:04:06 +0200 Subject: msvc fixe Fixes : - Bad argument name - Better Python 2 compatibility --- setuptools/msvc.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index bbf66570..a03f4fe3 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -203,7 +203,7 @@ def msvc14_get_vc_env(plat_spec): # If error, try to set environment directly try: - return EnvironmentInfo(plat_spec, vc_ver_min=14.0).return_env() + return EnvironmentInfo(plat_spec, vc_min_ver=14.0).return_env() except distutils.errors.DistutilsPlatformError as exc: _augment_exception(exc, 14.0) raise @@ -442,11 +442,11 @@ class RegistryInfo: for hkey in self.HKEYS: try: bkey = winreg.OpenKey(hkey, key, 0, winreg.KEY_READ) - except FileNotFoundError: + except IOError: continue try: return winreg.QueryValueEx(bkey, name)[0] - except FileNotFoundError: + except IOError: pass @@ -489,7 +489,7 @@ class SystemInfo: for key in vckeys: try: bkey = winreg.OpenKey(hkey, key, 0, winreg.KEY_READ) - except FileNotFoundError: + except IOError: continue subkeys, values, _ = winreg.QueryInfoKey(bkey) for i in range(values): @@ -1187,5 +1187,5 @@ class EnvironmentInfo: if name: return '%s\\' % name[0] return '' - except FileNotFoundError: + except IOError: return '' -- cgit v1.2.1 From b90df6ddf053d18c32c72502521eecb36bc454a6 Mon Sep 17 00:00:00 2001 From: "J. Goutin" Date: Sun, 3 Jul 2016 14:06:54 +0200 Subject: Update msvc.py --- setuptools/msvc.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index a03f4fe3..d5a48dce 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -237,6 +237,10 @@ def _augment_exception(exc, version, arch=''): # 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 "Visual C++ Build Tools": ' + r'http://landinghub.visualstudio.com/visual-cpp-build-tools' exc.args = (message, ) -- cgit v1.2.1 From 4751aeef452878881a2b0d81a2624c1c5e72b911 Mon Sep 17 00:00:00 2001 From: "J. Goutin" Date: Sun, 3 Jul 2016 14:33:36 +0200 Subject: Update msvc.py --- setuptools/msvc.py | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index d5a48dce..b85d66e0 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -3,7 +3,6 @@ This module adds improved support for Microsoft Visual C++ compilers. """ import os -import collections import itertools import distutils.errors from setuptools.extern.six.moves import filterfalse @@ -21,7 +20,7 @@ except ImportError: HKEY_CURRENT_USER = None HKEY_LOCAL_MACHINE = None HKEY_CLASSES_ROOT = None - safe_env = collections.defaultdict(lambda: '') + safe_env = dict() try: @@ -36,7 +35,7 @@ try: except ImportError: pass - + unpatched = dict() @@ -237,10 +236,6 @@ def _augment_exception(exc, version, arch=''): # 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 "Visual C++ Build Tools": ' - r'http://landinghub.visualstudio.com/visual-cpp-build-tools' exc.args = (message, ) @@ -254,7 +249,7 @@ class PlatformInfo: arch: str Target architecture. """ - current_cpu = safe_env['processor_architecture'].lower() + current_cpu = safe_env.get('processor_architecture', '').lower() def __init__(self, arch): self.arch = arch.lower().replace('x64', 'amd64') @@ -467,9 +462,9 @@ class SystemInfo: """ # Variables and properties in this class use originals CamelCase variables # names from Microsoft source files for more easy comparaison. - WinDir = safe_env['WinDir'] - ProgramFiles = safe_env['ProgramFiles'] - ProgramFilesx86 = os.environ.get('ProgramFiles(x86)', ProgramFiles) + 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 -- cgit v1.2.1 From 7b9290771ec850cf7f5e21e168048b12e1e59cf4 Mon Sep 17 00:00:00 2001 From: "J. Goutin" Date: Sun, 3 Jul 2016 15:17:08 +0200 Subject: Update msvc.py --- setuptools/msvc.py | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index b85d66e0..8216e94a 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -1,27 +1,16 @@ """ This module adds improved support for Microsoft Visual C++ compilers. """ - import os +import platform import itertools import distutils.errors from setuptools.extern.six.moves import filterfalse try: from setuptools.extern.six.moves import winreg - safe_env = os.environ except ImportError: - """ - 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() - + pass try: # Distutil file for MSVC++ 9.0 and upper (Python 2.7 to 3.4) @@ -35,7 +24,7 @@ try: except ImportError: pass - + unpatched = dict() @@ -57,6 +46,10 @@ def patch_for_specialized_compiler(): Microsoft Visual C++ 14.0: Microsoft Visual C++ Build Tools 2015 (x86, x64, arm) """ + if platform.system() != Windows: + # Compilers only availables on Microsoft Windows + return + if 'distutils' not in globals(): # The module isn't available to be patched return @@ -249,7 +242,7 @@ class PlatformInfo: arch: str Target architecture. """ - current_cpu = safe_env.get('processor_architecture', '').lower() + current_cpu = os.environ.get('processor_architecture', '').lower() def __init__(self, arch): self.arch = arch.lower().replace('x64', 'amd64') @@ -462,9 +455,9 @@ class SystemInfo: """ # 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) + WinDir = os.environ.get('WinDir', '') + ProgramFiles = os.environ.get('ProgramFiles', '') + ProgramFilesx86 = os.environ.get('ProgramFiles(x86)', ProgramFiles) def __init__(self, registry_info, vc_ver=None): self.ri = registry_info -- cgit v1.2.1 From b4b913b18c07a9d2bce8ae57da7e8c45bf17c28b Mon Sep 17 00:00:00 2001 From: "J. Goutin" Date: Sun, 3 Jul 2016 15:22:40 +0200 Subject: Update msvc.py --- setuptools/msvc.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 8216e94a..5e6c1c25 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -9,8 +9,18 @@ from setuptools.extern.six.moves import filterfalse try: from setuptools.extern.six.moves import winreg + safe_env = os.environ except ImportError: - pass + """ + 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 = collections.defaultdict(lambda: '') try: # Distutil file for MSVC++ 9.0 and upper (Python 2.7 to 3.4) @@ -242,7 +252,7 @@ class PlatformInfo: arch: str Target architecture. """ - current_cpu = os.environ.get('processor_architecture', '').lower() + current_cpu = safe_env.get('processor_architecture', '').lower() def __init__(self, arch): self.arch = arch.lower().replace('x64', 'amd64') @@ -455,9 +465,9 @@ class SystemInfo: """ # Variables and properties in this class use originals CamelCase variables # names from Microsoft source files for more easy comparaison. - WinDir = os.environ.get('WinDir', '') - ProgramFiles = os.environ.get('ProgramFiles', '') - ProgramFilesx86 = os.environ.get('ProgramFiles(x86)', ProgramFiles) + 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 @@ -1128,7 +1138,7 @@ class EnvironmentInfo: """ # flatten spec_path_lists spec_paths = itertools.chain.from_iterable(spec_path_lists) - env_paths = os.environ.get(name, '').split(os.pathsep) + 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: -- cgit v1.2.1 From 2aa04076e57845abdf9e0cc5238bdcc23ae5e58e Mon Sep 17 00:00:00 2001 From: "J. Goutin" Date: Sun, 3 Jul 2016 15:26:20 +0200 Subject: Update msvc.py --- setuptools/msvc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 5e6c1c25..0851b193 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -7,10 +7,10 @@ import itertools import distutils.errors from setuptools.extern.six.moves import filterfalse -try: +if platform.system() == Windows: from setuptools.extern.six.moves import winreg safe_env = os.environ -except ImportError: +else: """ Mock winreg and environ so the module can be imported on this platform. -- cgit v1.2.1 From a0bc231f8fee1f2df0c04b92eb070e66536d622e Mon Sep 17 00:00:00 2001 From: "J. Goutin" Date: Sun, 3 Jul 2016 15:28:12 +0200 Subject: Update msvc.py --- setuptools/msvc.py | 1 + 1 file changed, 1 insertion(+) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 0851b193..f1213f32 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -4,6 +4,7 @@ This module adds improved support for Microsoft Visual C++ compilers. import os import platform import itertools +import collections import distutils.errors from setuptools.extern.six.moves import filterfalse -- cgit v1.2.1 From c12e784cce4104244353e18e73dedbb588061de7 Mon Sep 17 00:00:00 2001 From: "J. Goutin" Date: Sun, 3 Jul 2016 15:31:18 +0200 Subject: Update msvc.py --- setuptools/msvc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index f1213f32..990382c0 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -8,7 +8,7 @@ import collections import distutils.errors from setuptools.extern.six.moves import filterfalse -if platform.system() == Windows: +if platform.system() == 'Windows': from setuptools.extern.six.moves import winreg safe_env = os.environ else: @@ -57,7 +57,7 @@ def patch_for_specialized_compiler(): Microsoft Visual C++ 14.0: Microsoft Visual C++ Build Tools 2015 (x86, x64, arm) """ - if platform.system() != Windows: + if platform.system() != 'Windows': # Compilers only availables on Microsoft Windows return -- cgit v1.2.1 From fb2673566eb04bcf315a5dc28193a59c1dce902b Mon Sep 17 00:00:00 2001 From: "J. Goutin" Date: Sun, 3 Jul 2016 15:42:45 +0200 Subject: Update msvc.py --- setuptools/msvc.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 990382c0..8c612129 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -4,7 +4,6 @@ This module adds improved support for Microsoft Visual C++ compilers. import os import platform import itertools -import collections import distutils.errors from setuptools.extern.six.moves import filterfalse @@ -21,7 +20,7 @@ else: HKEY_CURRENT_USER = None HKEY_LOCAL_MACHINE = None HKEY_CLASSES_ROOT = None - safe_env = collections.defaultdict(lambda: '') + safe_env = dict() try: # Distutil file for MSVC++ 9.0 and upper (Python 2.7 to 3.4) -- cgit v1.2.1 From 7b303ef300faad048b21005e17d1ca83e4ad3a18 Mon Sep 17 00:00:00 2001 From: "J. Goutin" Date: Sun, 3 Jul 2016 19:04:03 +0200 Subject: Minor change : Link to MSVC14 Standalone Add the new link to "Microsoft Visual C++ Build Tools" if MSVC14 is not installed. --- setuptools/msvc.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 8c612129..b543c568 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -221,7 +221,7 @@ def _augment_exception(exc, version, arch=''): 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 = '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: @@ -239,6 +239,10 @@ def _augment_exception(exc, version, arch=''): # 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, ) -- cgit v1.2.1 From 6d11e88f938f09ef16db4c6064b6e74acba4db1d Mon Sep 17 00:00:00 2001 From: stepshal Date: Tue, 12 Jul 2016 22:00:43 +0700 Subject: Fix quantity of blank lines after code object. --- setuptools/msvc.py | 1 + 1 file changed, 1 insertion(+) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index b543c568..012ab32c 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -769,6 +769,7 @@ class EnvironmentInfo: """ # 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) -- cgit v1.2.1 From 789462de79c5f51ba24256d80ad2dac2e4fe2888 Mon Sep 17 00:00:00 2001 From: stepshal Date: Thu, 21 Jul 2016 10:23:29 +0700 Subject: Add missing blank line. --- setuptools/msvc.py | 1 + 1 file changed, 1 insertion(+) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 012ab32c..2a665c92 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -5,6 +5,7 @@ import os import platform import itertools import distutils.errors + from setuptools.extern.six.moves import filterfalse if platform.system() == 'Windows': -- cgit v1.2.1 From d506d3d7411e890028092b72f1005d487a5398f1 Mon Sep 17 00:00:00 2001 From: "J. Goutin" Date: Wed, 27 Jul 2016 19:13:51 +0200 Subject: Fix regression in commit #e404a4a Missing `,` --- setuptools/msvc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 2a665c92..c762c28f 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -909,7 +909,7 @@ class EnvironmentInfo: os.path.join(self.si.WindowsSdkDir, 'UnionMetadata'), os.path.join( ref, - 'Windows.Foundation.UniversalApiContract' + 'Windows.Foundation.UniversalApiContract', '1.0.0.0', ), os.path.join( @@ -919,7 +919,7 @@ class EnvironmentInfo: ), os.path.join( ref, - 'Windows.Networking.Connectivity.WwanContract' + 'Windows.Networking.Connectivity.WwanContract', '1.0.0.0', ), os.path.join( -- cgit v1.2.1 From ba535ea4958e17a2cb2e79df093f50d057c07562 Mon Sep 17 00:00:00 2001 From: "J. Goutin" Date: Thu, 28 Jul 2016 23:03:45 +0200 Subject: Fix for #646 --- setuptools/msvc.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index c762c28f..6fb3300b 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -449,10 +449,14 @@ class RegistryInfo: for hkey in self.HKEYS: try: bkey = winreg.OpenKey(hkey, key, 0, winreg.KEY_READ) + except OSError: + continue except IOError: continue try: return winreg.QueryValueEx(bkey, name)[0] + except OSError: + pass except IOError: pass -- cgit v1.2.1 From 3f54d45ad832984b0601efe6ff62f6d16a4de2a5 Mon Sep 17 00:00:00 2001 From: "J. Goutin" Date: Tue, 2 Aug 2016 18:26:02 +0200 Subject: Patch distutils._msvccompiler.library_dir_option Try to fix #694. --- setuptools/msvc.py | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 6fb3300b..419b2292 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -85,6 +85,11 @@ def patch_for_specialized_compiler(): except Exception: pass + try: + # Patch distutils._msvccompiler.library_dir_option + unpatched['msvc14_library_dir_option'] = msvc14compiler.library_dir_option + msvc14compiler.library_dir_option = msvc14_library_dir_option + def msvc9_find_vcvarsall(version): """ @@ -212,6 +217,12 @@ def msvc14_get_vc_env(plat_spec): raise +def msvc14_library_dir_option(dir): + if ' ' in dir: + dir = '"%s"' % dir + return unpatched['msvc14_library_dir_option'](dir) + + def _augment_exception(exc, version, arch=''): """ Add details to the exception message to help guide the user -- cgit v1.2.1 From 2214dbbd6fb407cf2313dba44558557072cf0974 Mon Sep 17 00:00:00 2001 From: "J. Goutin" Date: Tue, 2 Aug 2016 18:29:53 +0200 Subject: Update msvc.py --- setuptools/msvc.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 419b2292..2a746332 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -89,6 +89,8 @@ def patch_for_specialized_compiler(): # Patch distutils._msvccompiler.library_dir_option unpatched['msvc14_library_dir_option'] = msvc14compiler.library_dir_option msvc14compiler.library_dir_option = msvc14_library_dir_option + except Exception: + pass def msvc9_find_vcvarsall(version): -- cgit v1.2.1 From 2c4346bcc47ec1fd6fc77bd5bb4f760ed7c6667c Mon Sep 17 00:00:00 2001 From: "J. Goutin" Date: Tue, 2 Aug 2016 18:42:24 +0200 Subject: Update msvc.py --- setuptools/msvc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 2a746332..785d879b 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -220,7 +220,7 @@ def msvc14_get_vc_env(plat_spec): def msvc14_library_dir_option(dir): - if ' ' in dir: + if ' ' in dir and '"' not in dir: dir = '"%s"' % dir return unpatched['msvc14_library_dir_option'](dir) -- cgit v1.2.1 From 4732c1eb7830b7970ad545f3a4630a824650331b Mon Sep 17 00:00:00 2001 From: "J. Goutin" Date: Tue, 2 Aug 2016 20:09:53 +0200 Subject: Fix #707 MSVC patch and Python 2 #707 Fix Python 2 Compatibility, and improve registry lookup (Key may not always be in 64bit registry node). --- setuptools/msvc.py | 67 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 28 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 6fb3300b..4616d4be 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -356,23 +356,12 @@ class RegistryInfo: def __init__(self, platform_info): self.pi = platform_info - @property - def microsoft(self): - """ - Microsoft software registry key. - """ - return os.path.join( - 'Software', - '' if self.pi.current_is_x86() else 'Wow6432Node', - 'Microsoft', - ) - @property def visualstudio(self): """ Microsoft Visual Studio root registry key. """ - return os.path.join(self.microsoft, 'VisualStudio') + return 'VisualStudio' @property def sxs(self): @@ -400,15 +389,14 @@ class RegistryInfo: """ Microsoft Visual C++ for Python registry key. """ - path = r'DevDiv\VCForPython' - return os.path.join(self.microsoft, path) + return r'DevDiv\VCForPython' @property def microsoft_sdk(self): """ Microsoft SDK registry key. """ - return os.path.join(self.microsoft, 'Microsoft SDKs') + return 'Microsoft SDKs' @property def windows_sdk(self): @@ -429,11 +417,29 @@ class RegistryInfo: """ Microsoft Windows Kits Roots registry key. """ - return os.path.join(self.microsoft, r'Windows Kits\Installed Roots') + 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. + Look for values in registry in Microsoft software registry. Parameters ---------- @@ -446,18 +452,23 @@ class RegistryInfo: ------ str: value """ + KEY_READ = winreg.KEY_READ + openkey = winreg.OpenKey + ms = self.microsoft for hkey in self.HKEYS: try: - bkey = winreg.OpenKey(hkey, key, 0, winreg.KEY_READ) - except OSError: - continue - except IOError: - continue + 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: - pass - except IOError: + except (OSError, IOError): pass @@ -500,7 +511,7 @@ class SystemInfo: for key in vckeys: try: bkey = winreg.OpenKey(hkey, key, 0, winreg.KEY_READ) - except IOError: + except (OSError, IOError): continue subkeys, values, _ = winreg.QueryInfoKey(bkey) for i in range(values): @@ -813,7 +824,7 @@ class EnvironmentInfo: Microsoft Visual C++ & Microsoft Foundation Class Includes """ return [os.path.join(self.si.VCInstallDir, 'Include'), - os.path.join(self.si.VCInstallDir, 'ATLMFC\Include')] + os.path.join(self.si.VCInstallDir, r'ATLMFC\Include')] @property def VCLibraries(self): @@ -1199,5 +1210,5 @@ class EnvironmentInfo: if name: return '%s\\' % name[0] return '' - except IOError: + except (OSError, IOError): return '' -- cgit v1.2.1 From 651e3ffacb4208469e97a4eeaba623f5413daa7d Mon Sep 17 00:00:00 2001 From: "J. Goutin" Date: Wed, 3 Aug 2016 20:15:55 +0200 Subject: Fix from @vallsv Fix from @vallsv --- setuptools/msvc.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 785d879b..3e2472a2 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -87,8 +87,8 @@ def patch_for_specialized_compiler(): try: # Patch distutils._msvccompiler.library_dir_option - unpatched['msvc14_library_dir_option'] = msvc14compiler.library_dir_option - msvc14compiler.library_dir_option = msvc14_library_dir_option + unpatched['msvc14_library_dir_option'] = msvc14compiler.MSVCCompiler.library_dir_option + msvc14compiler.MSVCCompiler.library_dir_option = msvc14_library_dir_option except Exception: pass @@ -219,10 +219,10 @@ def msvc14_get_vc_env(plat_spec): raise -def msvc14_library_dir_option(dir): +def msvc14_library_dir_option(self, dir): if ' ' in dir and '"' not in dir: dir = '"%s"' % dir - return unpatched['msvc14_library_dir_option'](dir) + return unpatched['msvc14_library_dir_option'](self, dir) def _augment_exception(exc, version, arch=''): -- cgit v1.2.1 From 7b1fa7643e2599f24956323a2066a6e26dc57b82 Mon Sep 17 00:00:00 2001 From: "J. Goutin" Date: Thu, 4 Aug 2016 12:22:54 +0200 Subject: doc for msvc14_library_dir_option --- setuptools/msvc.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 3e2472a2..da26371c 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -86,7 +86,7 @@ def patch_for_specialized_compiler(): pass try: - # Patch distutils._msvccompiler.library_dir_option + # Patch distutils._msvccompiler.MSVCCompiler.library_dir_option unpatched['msvc14_library_dir_option'] = msvc14compiler.MSVCCompiler.library_dir_option msvc14compiler.MSVCCompiler.library_dir_option = msvc14_library_dir_option except Exception: @@ -220,7 +220,21 @@ def msvc14_get_vc_env(plat_spec): def msvc14_library_dir_option(self, dir): + """ + Patched "distutils._msvccompiler.MSVCCompiler.library_dir_option" + to fix unquoted path in "\LIBPATH" argument when a space is on path. + + Parameters + ---------- + dir: str + Path to convert in "\LIBPATH" argument. + + Return + ------ + "\LIBPATH" argument: str + """ if ' ' in dir and '"' not in dir: + # Quote if space and not already quoted dir = '"%s"' % dir return unpatched['msvc14_library_dir_option'](self, dir) -- cgit v1.2.1 From e3805614a5ed770d3ba86acd339a24947c19a65b Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 5 Aug 2016 12:58:47 +0200 Subject: quote library_dir_option after calling unpatched version avoids double-quotes if the calling function does the quoting correctly. --- setuptools/msvc.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 2700a2b0..97dd441c 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -233,10 +233,11 @@ def msvc14_library_dir_option(self, dir): ------ "\LIBPATH" argument: str """ - if ' ' in dir and '"' not in dir: + opt = unpatched['msvc14_library_dir_option'](self, dir) + if ' ' in opt and '"' not in opt: # Quote if space and not already quoted - dir = '"%s"' % dir - return unpatched['msvc14_library_dir_option'](self, dir) + opt = '"%s"' % opt + return opt def _augment_exception(exc, version, arch=''): -- cgit v1.2.1 From a5791ac002d9d00759b63727f9c930a2acba7d9f Mon Sep 17 00:00:00 2001 From: "J. Goutin" Date: Fri, 5 Aug 2016 17:44:26 +0200 Subject: revert `library_dir_option` patch. Revert patch on `distutils._msvccompiler.MSVCCompiler.library_dir_option` See comments on #694. --- setuptools/msvc.py | 28 ---------------------------- 1 file changed, 28 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 97dd441c..4616d4be 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -85,13 +85,6 @@ def patch_for_specialized_compiler(): except Exception: pass - try: - # Patch distutils._msvccompiler.MSVCCompiler.library_dir_option - unpatched['msvc14_library_dir_option'] = msvc14compiler.MSVCCompiler.library_dir_option - msvc14compiler.MSVCCompiler.library_dir_option = msvc14_library_dir_option - except Exception: - pass - def msvc9_find_vcvarsall(version): """ @@ -219,27 +212,6 @@ def msvc14_get_vc_env(plat_spec): raise -def msvc14_library_dir_option(self, dir): - """ - Patched "distutils._msvccompiler.MSVCCompiler.library_dir_option" - to fix unquoted path in "\LIBPATH" argument when a space is on path. - - Parameters - ---------- - dir: str - Path to convert in "\LIBPATH" argument. - - Return - ------ - "\LIBPATH" argument: str - """ - opt = unpatched['msvc14_library_dir_option'](self, dir) - if ' ' in opt and '"' not in opt: - # Quote if space and not already quoted - opt = '"%s"' % opt - return opt - - def _augment_exception(exc, version, arch=''): """ Add details to the exception message to help guide the user -- cgit v1.2.1 From 5e1693d225b2416712e11da591f60c085ce62957 Mon Sep 17 00:00:00 2001 From: "J. Goutin" Date: Tue, 16 Aug 2016 12:43:16 +0200 Subject: numpy.distutils and distutils._msvccompiler compatibility - Fix compatibility between `numpy.distutils` and `distutils._msvccompiler`. See #728 : Setuptools 24 `msvc.py` improvement import `distutils._msvccompiler` (New Python 3.5 C compiler for MSVC >= 14), but this one is not compatible with `numpy.distutils` (because not patched with `numpy.distutils.ccompiler.gen_lib_options`) and return unquoted libpaths when linking. The problem was patched in Numpy, but need to be patched also in Setuptools for compatibility between older versions of Numpy and `distutils._msvccompiler` (and indirectly Setuptools > 24). - Replace some residuals `except Exception`. --- setuptools/msvc.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 4616d4be..bd486fa1 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -75,14 +75,23 @@ def patch_for_specialized_compiler(): msvc9compiler.find_vcvarsall = msvc9_find_vcvarsall unpatched['msvc9_query_vcvarsall'] = msvc9compiler.query_vcvarsall msvc9compiler.query_vcvarsall = msvc9_query_vcvarsall - except Exception: + except NameError: pass try: # Patch distutils._msvccompiler._get_vc_env unpatched['msvc14_get_vc_env'] = msvc14compiler._get_vc_env msvc14compiler._get_vc_env = msvc14_get_vc_env - except Exception: + except NameError: + pass + + try: + # Apply "gen_lib_options" patch from Numpy to "distutils._msvccompiler" + # to fix compatibility between "numpy.distutils" and + # "distutils._msvccompiler" (for Numpy < 1.11.2) + import numpy.distutils as np_distutils + msvc14compiler.gen_lib_options = np_distutils.ccompiler.gen_lib_options + except (ImportError, NameError): pass @@ -243,7 +252,8 @@ def _augment_exception(exc, version, arch=''): 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') + r'http://landinghub.visualstudio.com/' + 'visual-cpp-build-tools') exc.args = (message, ) -- cgit v1.2.1 From 38d6743427f0aa31eaf2eb07df5cd11b6526d036 Mon Sep 17 00:00:00 2001 From: "J. Goutin" Date: Tue, 16 Aug 2016 19:12:42 +0200 Subject: Patch with numpy at execution time and not at import time --- setuptools/msvc.py | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index bd486fa1..4646d83f 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -79,19 +79,17 @@ def patch_for_specialized_compiler(): pass try: - # Patch distutils._msvccompiler._get_vc_env + # Patch distutils._msvccompiler._get_vc_env for numpy compatibility unpatched['msvc14_get_vc_env'] = msvc14compiler._get_vc_env msvc14compiler._get_vc_env = msvc14_get_vc_env except NameError: pass try: - # Apply "gen_lib_options" patch from Numpy to "distutils._msvccompiler" - # to fix compatibility between "numpy.distutils" and - # "distutils._msvccompiler" (for Numpy < 1.11.2) - import numpy.distutils as np_distutils - msvc14compiler.gen_lib_options = np_distutils.ccompiler.gen_lib_options - except (ImportError, NameError): + # Patch distutils._msvccompiler.gen_lib_options + unpatched['msvc14_gen_lib_options'] = msvc14compiler.gen_lib_options + msvc14compiler.gen_lib_options = msvc14_gen_lib_options + except NameError: pass @@ -221,6 +219,19 @@ def msvc14_get_vc_env(plat_spec): 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" in distutils.ccompiler.CCompiler.spawn.__module__: + import numpy as np + return np.distutils.ccompiler.gen_lib_options(*args, **kwargs) + else: + return unpatched['msvc14_gen_lib_options'](*args, **kwargs) + + def _augment_exception(exc, version, arch=''): """ Add details to the exception message to help guide the user -- cgit v1.2.1 From f5802f369d5b7b76a7feb4c49e2e49840058bf3b Mon Sep 17 00:00:00 2001 From: "J. Goutin" Date: Tue, 16 Aug 2016 19:33:07 +0200 Subject: Improve numpy.distutils detection Agree with @pitrou comment. --- setuptools/msvc.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 4646d83f..57153d8a 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -2,6 +2,7 @@ This module adds improved support for Microsoft Visual C++ compilers. """ import os +import sys import platform import itertools import distutils.errors @@ -225,7 +226,7 @@ def msvc14_gen_lib_options(*args, **kwargs): compatibility between "numpy.distutils" and "distutils._msvccompiler" (for Numpy < 1.11.2) """ - if "numpy" in distutils.ccompiler.CCompiler.spawn.__module__: + if "numpy.distutils" in sys.modules: import numpy as np return np.distutils.ccompiler.gen_lib_options(*args, **kwargs) else: -- cgit v1.2.1 From 21be70b60cfea8da91df4687a21f262a59809073 Mon Sep 17 00:00:00 2001 From: "J. Goutin" Date: Tue, 16 Aug 2016 19:34:48 +0200 Subject: Wrong line for comment --- setuptools/msvc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 57153d8a..360c1a68 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -80,14 +80,14 @@ def patch_for_specialized_compiler(): pass try: - # Patch distutils._msvccompiler._get_vc_env for numpy compatibility + # Patch distutils._msvccompiler._get_vc_env unpatched['msvc14_get_vc_env'] = msvc14compiler._get_vc_env msvc14compiler._get_vc_env = msvc14_get_vc_env except NameError: pass try: - # Patch distutils._msvccompiler.gen_lib_options + # Patch distutils._msvccompiler.gen_lib_options for Numpy unpatched['msvc14_gen_lib_options'] = msvc14compiler.gen_lib_options msvc14compiler.gen_lib_options = msvc14_gen_lib_options except NameError: -- cgit v1.2.1 From 8d1eecaef52a1baf2b9fc6c772880d8c537b562f Mon Sep 17 00:00:00 2001 From: "J. Goutin" Date: Thu, 18 Aug 2016 13:42:07 +0200 Subject: Add numpy version check --- setuptools/msvc.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 360c1a68..bffaa6aa 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -6,6 +6,7 @@ import sys import platform import itertools import distutils.errors +from distutils.version import StrictVersion from setuptools.extern.six.moves import filterfalse @@ -228,9 +229,9 @@ def msvc14_gen_lib_options(*args, **kwargs): """ if "numpy.distutils" in sys.modules: import numpy as np - return np.distutils.ccompiler.gen_lib_options(*args, **kwargs) - else: - return unpatched['msvc14_gen_lib_options'](*args, **kwargs) + if StrictVersion(np.__version__) < StrictVersion('1.11.2'): + return np.distutils.ccompiler.gen_lib_options(*args, **kwargs) + return unpatched['msvc14_gen_lib_options'](*args, **kwargs) def _augment_exception(exc, version, arch=''): -- cgit v1.2.1 From e3ffde678c36ca778476574194cdc6d436d82263 Mon Sep 17 00:00:00 2001 From: stepshal Date: Sat, 20 Aug 2016 08:15:52 +0700 Subject: Remove trailing whitespace. (#751) --- setuptools/msvc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index bffaa6aa..26e399cc 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -223,7 +223,7 @@ def msvc14_get_vc_env(plat_spec): def msvc14_gen_lib_options(*args, **kwargs): """ - Patched "distutils._msvccompiler.gen_lib_options" for fix + Patched "distutils._msvccompiler.gen_lib_options" for fix compatibility between "numpy.distutils" and "distutils._msvccompiler" (for Numpy < 1.11.2) """ -- cgit v1.2.1 From 6a74dc955603fb6dcdaa2877b332c7ff1c55dfad Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 4 Sep 2016 20:05:03 -0400 Subject: distutils will always be in globals --- setuptools/msvc.py | 4 ---- 1 file changed, 4 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 26e399cc..d7c88955 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -63,10 +63,6 @@ def patch_for_specialized_compiler(): # Compilers only availables on Microsoft Windows return - if 'distutils' not in globals(): - # The module isn't available to be patched - return - if unpatched: # Already patched return -- cgit v1.2.1 From 3c5cf653dbc0ab10d08738ee4e4db26710903466 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 4 Sep 2016 20:29:14 -0400 Subject: Move msvc patch logic into monkey module. --- setuptools/msvc.py | 90 ++++++++++++++---------------------------------------- 1 file changed, 23 insertions(+), 67 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index d7c88955..10507ab2 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -1,6 +1,20 @@ """ -This module adds improved support for Microsoft Visual C++ compilers. +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 @@ -10,6 +24,8 @@ from distutils.version import StrictVersion from setuptools.extern.six.moves import filterfalse +from . import monkey + if platform.system() == 'Windows': from setuptools.extern.six.moves import winreg safe_env = os.environ @@ -26,70 +42,10 @@ else: safe_env = dict() try: - # Distutil file for MSVC++ 9.0 and upper (Python 2.7 to 3.4) - import distutils.msvc9compiler as msvc9compiler + from distutils.msvc9compiler import Reg except ImportError: pass -try: - # Distutil file for MSVC++ 14.0 and upper (Python 3.5+) - import distutils._msvccompiler as msvc14compiler -except ImportError: - pass - - -unpatched = dict() - - -def patch_for_specialized_compiler(): - """ - Patch functions in distutils to use standalone 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) - """ - if platform.system() != 'Windows': - # Compilers only availables on Microsoft Windows - return - - if unpatched: - # Already patched - return - - try: - # Patch distutils.msvc9compiler - unpatched['msvc9_find_vcvarsall'] = msvc9compiler.find_vcvarsall - msvc9compiler.find_vcvarsall = msvc9_find_vcvarsall - unpatched['msvc9_query_vcvarsall'] = msvc9compiler.query_vcvarsall - msvc9compiler.query_vcvarsall = msvc9_query_vcvarsall - except NameError: - pass - - try: - # Patch distutils._msvccompiler._get_vc_env - unpatched['msvc14_get_vc_env'] = msvc14compiler._get_vc_env - msvc14compiler._get_vc_env = msvc14_get_vc_env - except NameError: - pass - - try: - # Patch distutils._msvccompiler.gen_lib_options for Numpy - unpatched['msvc14_gen_lib_options'] = msvc14compiler.gen_lib_options - msvc14compiler.gen_lib_options = msvc14_gen_lib_options - except NameError: - pass - def msvc9_find_vcvarsall(version): """ @@ -113,7 +69,6 @@ def msvc9_find_vcvarsall(version): ------ vcvarsall.bat path: str """ - Reg = msvc9compiler.Reg VC_BASE = r'Software\%sMicrosoft\DevDiv\VCForPython\%0.1f' key = VC_BASE % ('', version) try: @@ -132,7 +87,7 @@ def msvc9_find_vcvarsall(version): if os.path.isfile(vcvarsall): return vcvarsall - return unpatched['msvc9_find_vcvarsall'](version) + return monkey.unpatched['msvc9_find_vcvarsall'](version) def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs): @@ -165,7 +120,8 @@ def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs): """ # Try to get environement from vcvarsall.bat (Classical way) try: - return unpatched['msvc9_query_vcvarsall'](ver, arch, *args, **kwargs) + orig = monkey.unpatched['msvc9_query_vcvarsall'] + return orig(ver, arch, *args, **kwargs) except distutils.errors.DistutilsPlatformError: # Pass error if Vcvarsall.bat is missing pass @@ -204,7 +160,7 @@ def msvc14_get_vc_env(plat_spec): """ # Try to get environment from vcvarsall.bat (Classical way) try: - return unpatched['msvc14_get_vc_env'](plat_spec) + return monkey.unpatched['msvc14_get_vc_env'](plat_spec) except distutils.errors.DistutilsPlatformError: # Pass error Vcvarsall.bat is missing pass @@ -227,7 +183,7 @@ def msvc14_gen_lib_options(*args, **kwargs): import numpy as np if StrictVersion(np.__version__) < StrictVersion('1.11.2'): return np.distutils.ccompiler.gen_lib_options(*args, **kwargs) - return unpatched['msvc14_gen_lib_options'](*args, **kwargs) + return monkey.unpatched['msvc14_gen_lib_options'](*args, **kwargs) def _augment_exception(exc, version, arch=''): -- cgit v1.2.1 From fa187c39baf5fa0fee1feb3568177afb244ac30b Mon Sep 17 00:00:00 2001 From: Valentin Valls Date: Mon, 5 Sep 2016 09:34:22 +0200 Subject: Use LooseVersion instread of StrictVersion --- setuptools/msvc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 26e399cc..c7dd7976 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -6,7 +6,7 @@ import sys import platform import itertools import distutils.errors -from distutils.version import StrictVersion +from distutils.version import LooseVersion from setuptools.extern.six.moves import filterfalse @@ -229,7 +229,7 @@ def msvc14_gen_lib_options(*args, **kwargs): """ if "numpy.distutils" in sys.modules: import numpy as np - if StrictVersion(np.__version__) < StrictVersion('1.11.2'): + if LooseVersion(np.__version__) < LooseVersion('1.11.2'): return np.distutils.ccompiler.gen_lib_options(*args, **kwargs) return unpatched['msvc14_gen_lib_options'](*args, **kwargs) -- cgit v1.2.1 From 54343cdaee7de324b15f3ace93657f34a53c5e34 Mon Sep 17 00:00:00 2001 From: Valentin Valls Date: Tue, 6 Sep 2016 11:10:34 +0200 Subject: Use LegacyVersion instead of LooseVersion - Also apply the patch for numpy 1.11.2 pre release --- setuptools/msvc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index c7dd7976..ecbea818 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -6,7 +6,7 @@ import sys import platform import itertools import distutils.errors -from distutils.version import LooseVersion +from pkg_resources.extern.packaging.version import LegacyVersion from setuptools.extern.six.moves import filterfalse @@ -229,7 +229,7 @@ def msvc14_gen_lib_options(*args, **kwargs): """ if "numpy.distutils" in sys.modules: import numpy as np - if LooseVersion(np.__version__) < LooseVersion('1.11.2'): + if LegacyVersion(np.__version__) < LegacyVersion('1.11.2'): return np.distutils.ccompiler.gen_lib_options(*args, **kwargs) return unpatched['msvc14_gen_lib_options'](*args, **kwargs) -- cgit v1.2.1 From b6f2fee975c570d2beadb9007e6302411f91ab4b Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Fri, 9 Sep 2016 12:39:43 -0400 Subject: Consolidate function patching and resolution of unpatched function, aligning pattern with the patched classes. --- setuptools/msvc.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index a902a4a7..ae5a2b6a 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -24,7 +24,7 @@ from pkg_resources.extern.packaging.version import LegacyVersion from setuptools.extern.six.moves import filterfalse -from . import monkey +from .monkey import get_unpatched_func if platform.system() == 'Windows': from setuptools.extern.six.moves import winreg @@ -87,7 +87,7 @@ def msvc9_find_vcvarsall(version): if os.path.isfile(vcvarsall): return vcvarsall - return monkey.unpatched['msvc9_find_vcvarsall'](version) + return get_unpatched_func(msvc9_find_vcvarsall)(version) def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs): @@ -120,7 +120,7 @@ def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs): """ # Try to get environement from vcvarsall.bat (Classical way) try: - orig = monkey.unpatched['msvc9_query_vcvarsall'] + orig = get_unpatched_func(msvc9_query_vcvarsall) return orig(ver, arch, *args, **kwargs) except distutils.errors.DistutilsPlatformError: # Pass error if Vcvarsall.bat is missing @@ -160,7 +160,7 @@ def msvc14_get_vc_env(plat_spec): """ # Try to get environment from vcvarsall.bat (Classical way) try: - return monkey.unpatched['msvc14_get_vc_env'](plat_spec) + return get_unpatched_func(msvc14_get_vc_env)(plat_spec) except distutils.errors.DistutilsPlatformError: # Pass error Vcvarsall.bat is missing pass @@ -183,7 +183,7 @@ def msvc14_gen_lib_options(*args, **kwargs): import numpy as np if LegacyVersion(np.__version__) < LegacyVersion('1.11.2'): return np.distutils.ccompiler.gen_lib_options(*args, **kwargs) - return monkey.unpatched['msvc14_gen_lib_options'](*args, **kwargs) + return get_unpatched_func(msvc14_gen_lib_options)(*args, **kwargs) def _augment_exception(exc, version, arch=''): -- cgit v1.2.1 From 7756f651df47dc870e886c1b13c5b48068c2dd5b Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Fri, 9 Sep 2016 12:54:34 -0400 Subject: Allow get_unpatched to be called to get unpatched version of a class or function, further harmonizing the interfaces. --- setuptools/msvc.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index ae5a2b6a..e9665e10 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -24,7 +24,7 @@ from pkg_resources.extern.packaging.version import LegacyVersion from setuptools.extern.six.moves import filterfalse -from .monkey import get_unpatched_func +from .monkey import get_unpatched if platform.system() == 'Windows': from setuptools.extern.six.moves import winreg @@ -87,7 +87,7 @@ def msvc9_find_vcvarsall(version): if os.path.isfile(vcvarsall): return vcvarsall - return get_unpatched_func(msvc9_find_vcvarsall)(version) + return get_unpatched(msvc9_find_vcvarsall)(version) def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs): @@ -120,7 +120,7 @@ def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs): """ # Try to get environement from vcvarsall.bat (Classical way) try: - orig = get_unpatched_func(msvc9_query_vcvarsall) + orig = get_unpatched(msvc9_query_vcvarsall) return orig(ver, arch, *args, **kwargs) except distutils.errors.DistutilsPlatformError: # Pass error if Vcvarsall.bat is missing @@ -160,7 +160,7 @@ def msvc14_get_vc_env(plat_spec): """ # Try to get environment from vcvarsall.bat (Classical way) try: - return get_unpatched_func(msvc14_get_vc_env)(plat_spec) + return get_unpatched(msvc14_get_vc_env)(plat_spec) except distutils.errors.DistutilsPlatformError: # Pass error Vcvarsall.bat is missing pass @@ -183,7 +183,7 @@ def msvc14_gen_lib_options(*args, **kwargs): import numpy as np if LegacyVersion(np.__version__) < LegacyVersion('1.11.2'): return np.distutils.ccompiler.gen_lib_options(*args, **kwargs) - return get_unpatched_func(msvc14_gen_lib_options)(*args, **kwargs) + return get_unpatched(msvc14_gen_lib_options)(*args, **kwargs) def _augment_exception(exc, version, arch=''): -- cgit v1.2.1 From 31bd37c6ac8de9e8c1bacebc2d8e1215df91eb96 Mon Sep 17 00:00:00 2001 From: stepshal Date: Tue, 18 Oct 2016 20:24:35 +0700 Subject: Fix quantity of blank lines. --- setuptools/msvc.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index e9665e10..ef85f64a 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -34,11 +34,13 @@ 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: @@ -458,6 +460,7 @@ class SystemInfo: 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', '') -- cgit v1.2.1 From ed3fac3741f01ce05c139216e5af58c238c63f29 Mon Sep 17 00:00:00 2001 From: stepshal Date: Wed, 19 Oct 2016 00:23:56 +0700 Subject: Fix quantity of blank lines. --- setuptools/msvc.py | 1 + 1 file changed, 1 insertion(+) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index ef85f64a..447ddb38 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -761,6 +761,7 @@ class EnvironmentInfo: 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. -- cgit v1.2.1 From ff371f18f0076bc63da05334f7e551c1cc29e10d Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 1 Jan 2017 22:34:28 -0500 Subject: Strip out vendored packages and require them instead. Ref #581. --- setuptools/msvc.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 447ddb38..97e27303 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -20,14 +20,14 @@ import sys import platform import itertools import distutils.errors -from pkg_resources.extern.packaging.version import LegacyVersion +from packaging.version import LegacyVersion -from setuptools.extern.six.moves import filterfalse +from six.moves import filterfalse from .monkey import get_unpatched if platform.system() == 'Windows': - from setuptools.extern.six.moves import winreg + from six.moves import winreg safe_env = os.environ else: """ -- cgit v1.2.1 From 3d0cc355fb5e8012cb8c72f0e25042a5a44f31d6 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Fri, 24 Feb 2017 11:49:51 -0500 Subject: Revert "Merge pull request #933 from pypa/feature/581-depend-not-bundle" This reverts commit 089cdeb489a0fa94d11b7307b54210ef9aa40511, reversing changes made to aaec654d804cb78dbb6391afff721a63f26a71cd. --- setuptools/msvc.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 97e27303..447ddb38 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -20,14 +20,14 @@ import sys import platform import itertools import distutils.errors -from packaging.version import LegacyVersion +from pkg_resources.extern.packaging.version import LegacyVersion -from six.moves import filterfalse +from setuptools.extern.six.moves import filterfalse from .monkey import get_unpatched if platform.system() == 'Windows': - from six.moves import winreg + from setuptools.extern.six.moves import winreg safe_env = os.environ else: """ -- cgit v1.2.1 From e753cb42481783ac858ceb518aaac1472075063c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Skytt=C3=A4?= Date: Fri, 24 Feb 2017 10:55:44 +0200 Subject: Python 3.6 invalid escape sequence deprecation fixes --- setuptools/msvc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 97e27303..d41daec4 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -272,7 +272,7 @@ class PlatformInfo: ) def target_dir(self, hidex86=False, x64=False): - """ + r""" Target platform specific subfolder. Parameters @@ -294,7 +294,7 @@ class PlatformInfo: ) def cross_dir(self, forcex86=False): - """ + r""" Cross platform specific subfolder. Parameters -- cgit v1.2.1 From 20b3b3eaa74935d4854b63f75d893def27a4248e Mon Sep 17 00:00:00 2001 From: JGoutin Date: Mon, 20 Mar 2017 17:45:57 +0100 Subject: Update for MS BuildTools 2017 --- setuptools/msvc.py | 96 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 81 insertions(+), 15 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index d41daec4..71fe24cd 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -13,6 +13,7 @@ Microsoft Visual C++ 10.0: Microsoft Visual C++ 14.0: Microsoft Visual C++ Build Tools 2015 (x86, x64, arm) + Microsoft Visual Studio Build Tools 2017 (x86, x64, arm, arm64) """ import os @@ -150,6 +151,7 @@ def msvc14_get_vc_env(plat_spec): ------------------------- Microsoft Visual C++ 14.0: Microsoft Visual C++ Build Tools 2015 (x86, x64, arm) + Microsoft Visual Studio Build Tools 2017 (x86, x64, arm, arm64) Parameters ---------- @@ -411,7 +413,7 @@ class RegistryInfo: ------ str: value """ - node64 = '' if self.pi.current_is_x86() or x86 else r'\Wow6432Node' + node64 = '' if self.pi.current_is_x86() or x86 else 'Wow6432Node' return os.path.join('Software', node64, 'Microsoft', key) def lookup(self, key, name): @@ -483,12 +485,13 @@ class SystemInfo: """ Find all available Microsoft Visual C++ versions. """ - vckeys = (self.ri.vc, self.ri.vc_for_python) + ms = self.ri.microsoft + vckeys = (self.ri.vc, self.ri.vc_for_python, self.ri.vs) vc_vers = [] for hkey in self.ri.HKEYS: for key in vckeys: try: - bkey = winreg.OpenKey(hkey, key, 0, winreg.KEY_READ) + bkey = winreg.OpenKey(hkey, ms(key), 0, winreg.KEY_READ) except (OSError, IOError): continue subkeys, values, _ = winreg.QueryInfoKey(bkey) @@ -525,9 +528,24 @@ class SystemInfo: """ 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) + self.VSInstallDir + + # Default path starting VS2017 + guess_vc = '' + if self.vc_ver > 14.0: + default = r'VC\Tools\MSVC' + guess_vc = os.path.join(self.VSInstallDir, default) + # Subdir with VC exact version as name + try: + vc_exact_ver = os.listdir(guess_vc)[-1] + guess_vc = os.path.join(guess_vc, vc_exact_ver) + except (OSError, IOError, IndexError): + guess_vc = '' + + # Legacy default path + if not guess_vc: + 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) @@ -725,9 +743,19 @@ class SystemInfo: bits: int Platform number of bits: 32 or 64. """ - # Find actual .NET version + # Find actual .NET version in registry ver = self.ri.lookup(self.ri.vc, 'frameworkver%d' % bits) or '' + # If nothing in registry, look in Framework folder + if not ver: + dot_net_dir = (self.FrameworkDir32 if bits == 32 else + self.FrameworkDir64) + for dir_name in reversed(os.listdir(dot_net_dir)): + if (os.path.isdir(os.path.join(dot_net_dir, dir_name)) and + dir_name.startswith('v')): + ver = dir_name + break + # Set .NET versions for specified MSVC++ version if self.vc_ver >= 12.0: frameworkver = (ver, 'v4.0') @@ -810,7 +838,10 @@ class EnvironmentInfo: """ Microsoft Visual C++ & Microsoft Foundation Class Libraries """ - arch_subdir = self.pi.target_dir(hidex86=True) + if self.vc_ver >= 15.0: + arch_subdir = self.pi.target_dir(x64=True) + else: + 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: @@ -840,10 +871,20 @@ class EnvironmentInfo: if arch_subdir: tools += [os.path.join(si.VCInstallDir, 'Bin%s' % arch_subdir)] - if self.vc_ver >= 14.0: + if self.vc_ver == 14.0: path = 'Bin%s' % self.pi.current_dir(hidex86=True) tools += [os.path.join(si.VCInstallDir, path)] + elif self.vc_ver >= 15.0: + host_dir = (r'bin\HostX86%s' if self.pi.current_is_x86() else + r'bin\HostX64%s') + tools += [os.path.join( + si.VCInstallDir, host_dir % self.pi.target_dir(x64=True))] + + if self.pi.current_cpu != self.pi.target_cpu: + tools += [os.path.join( + si.VCInstallDir, host_dir % self.pi.current_dir(x64=True))] + else: tools += [os.path.join(si.VCInstallDir, 'Bin')] @@ -933,8 +974,11 @@ class EnvironmentInfo: """ 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 self.vc_ver < 15.0: + bin_dir = 'Bin' if self.vc_ver <= 11.0 else r'Bin\x86' + tools = [os.path.join(self.si.WindowsSdkDir, bin_dir)] + else: + tools = [] if not self.pi.current_is_x86(): arch_subdir = self.pi.current_dir(x64=True) @@ -949,6 +993,12 @@ class EnvironmentInfo: path = r'Bin\NETFX 4.0 Tools%s' % arch_subdir tools += [os.path.join(self.si.WindowsSdkDir, path)] + elif self.vc_ver >= 15.0: + path = os.path.join(self.si.WindowsSdkDir, 'Bin') + arch_subdir = self.pi.current_dir(x64=True) + sdkver = self._get_content_dirname(path, slash=False) + tools += [os.path.join(path, r'%s%s' % (sdkver, arch_subdir))] + if self.si.WindowsSDKExecutablePath: tools += [self.si.WindowsSDKExecutablePath] @@ -1023,10 +1073,21 @@ class EnvironmentInfo: """ if self.vc_ver < 12.0: return [] + elif self.vc_ver < 15.0: + base_path = self.si.ProgramFilesx86 + arch_subdir = self.pi.current_dir(hidex86=True) + else: + base_path = self.si.VSInstallDir + arch_subdir = '' - 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)] + build = [os.path.join(base_path, path)] + + if self.vc_ver >= 15.0: + # Add Roslyn C# & Visual Basic Compiler + build += [os.path.join(base_path, path, 'Roslyn')] + + return build @property def HTMLHelpWorkshop(self): @@ -1170,7 +1231,7 @@ class EnvironmentInfo: seen_add(k) yield element - def _get_content_dirname(self, path): + def _get_content_dirname(self, path, slash=True): """ Return name of the first dir in path or '' if no dir found. @@ -1178,6 +1239,8 @@ class EnvironmentInfo: ---------- path: str Path where search dir. + slash: bool + If not True, only return "name" not "name\" Return ------ @@ -1187,7 +1250,10 @@ class EnvironmentInfo: try: name = os.listdir(path) if name: - return '%s\\' % name[0] + name = name[0] + if slash: + return '%s\\' % name + return name return '' except (OSError, IOError): return '' -- cgit v1.2.1 From ac59ef12d16c13533ead6401bdb4727016be77e3 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Fri, 7 Apr 2017 21:52:18 -0400 Subject: extract two functions for guessing the VC version; ref #995 --- setuptools/msvc.py | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 71fe24cd..cf556ad3 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -530,22 +530,7 @@ class SystemInfo: """ self.VSInstallDir - # Default path starting VS2017 - guess_vc = '' - if self.vc_ver > 14.0: - default = r'VC\Tools\MSVC' - guess_vc = os.path.join(self.VSInstallDir, default) - # Subdir with VC exact version as name - try: - vc_exact_ver = os.listdir(guess_vc)[-1] - guess_vc = os.path.join(guess_vc, vc_exact_ver) - except (OSError, IOError, IndexError): - guess_vc = '' - - # Legacy default path - if not guess_vc: - default = r'Microsoft Visual Studio %0.1f\VC' % self.vc_ver - guess_vc = os.path.join(self.ProgramFilesx86, default) + guess_vc = self._guess_vc() or self._guess_vc_legacy() # 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) @@ -561,6 +546,30 @@ class SystemInfo: return path + def _guess_vc(self): + """ + Locate Visual C for 2017 + """ + + if self.vc_ver <= 14.0: + return + + default = r'VC\Tools\MSVC' + guess_vc = os.path.join(self.VSInstallDir, default) + # Subdir with VC exact version as name + try: + vc_exact_ver = os.listdir(guess_vc)[-1] + return os.path.join(guess_vc, vc_exact_ver) + except (OSError, IOError, IndexError): + pass + + def _guess_vc_legacy(self): + """ + Locate Visual C for versions prior to 2017 + """ + default = r'Microsoft Visual Studio %0.1f\VC' % self.vc_ver + return os.path.join(self.ProgramFilesx86, default) + @property def WindowsSdkVersion(self): """ -- cgit v1.2.1 From 934d6707b1d8c55c930d458e39b11038e9276a4d Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Fri, 7 Apr 2017 22:07:30 -0400 Subject: Extract method for finding .Net in the framework folder. Ref #995. --- setuptools/msvc.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index cf556ad3..1588cd2e 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -753,17 +753,9 @@ class SystemInfo: Platform number of bits: 32 or 64. """ # Find actual .NET version in registry - ver = self.ri.lookup(self.ri.vc, 'frameworkver%d' % bits) or '' - - # If nothing in registry, look in Framework folder - if not ver: - dot_net_dir = (self.FrameworkDir32 if bits == 32 else - self.FrameworkDir64) - for dir_name in reversed(os.listdir(dot_net_dir)): - if (os.path.isdir(os.path.join(dot_net_dir, dir_name)) and - dir_name.startswith('v')): - ver = dir_name - break + reg_ver = self.ri.lookup(self.ri.vc, 'frameworkver%d' % bits) + dot_net_dir = getattr(self, 'FrameworkDir%d' % bits) + ver = reg_ver or self._find_dot_net_in(dot_net_dir) or '' # Set .NET versions for specified MSVC++ version if self.vc_ver >= 12.0: @@ -777,6 +769,18 @@ class SystemInfo: frameworkver = ('v3.0', 'v2.0.50727') return frameworkver + def _find_dot_net_in(self, dot_net_dir): + """ + Find .Net in the Framework folder + """ + matching_dirs = ( + dir_name + for dir_name in reversed(os.listdir(dot_net_dir)) + if os.path.isdir(os.path.join(dot_net_dir, dir_name)) + and dir_name.startswith('v') + ) + return next(matching_dirs, None) + class EnvironmentInfo: """ -- cgit v1.2.1 From 9430e92f888a7c41f295373bd8a6ef8af967e2e1 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Fri, 7 Apr 2017 22:19:06 -0400 Subject: Move initialization into a single location. Ref #995. --- setuptools/msvc.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 1588cd2e..baf2021e 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -987,11 +987,11 @@ class EnvironmentInfo: """ Microsoft Windows SDK Tools """ + tools = [] + if self.vc_ver < 15.0: bin_dir = 'Bin' if self.vc_ver <= 11.0 else r'Bin\x86' - tools = [os.path.join(self.si.WindowsSdkDir, bin_dir)] - else: - tools = [] + tools += [os.path.join(self.si.WindowsSdkDir, bin_dir)] if not self.pi.current_is_x86(): arch_subdir = self.pi.current_dir(x64=True) -- cgit v1.2.1 From 3fa9efcbb390b87304ddc64551e9fca823694773 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Fri, 7 Apr 2017 22:23:18 -0400 Subject: Extract generator for simpler syntax. Ref #995. --- setuptools/msvc.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index baf2021e..c5a8aea0 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -987,16 +987,17 @@ class EnvironmentInfo: """ Microsoft Windows SDK Tools """ - tools = [] + return list(self._sdk_tools()) + def _sdk_tools(self): if self.vc_ver < 15.0: bin_dir = 'Bin' if self.vc_ver <= 11.0 else r'Bin\x86' - tools += [os.path.join(self.si.WindowsSdkDir, bin_dir)] + yield 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)] + yield 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(): @@ -1004,18 +1005,16 @@ class EnvironmentInfo: 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)] + yield os.path.join(self.si.WindowsSdkDir, path) elif self.vc_ver >= 15.0: path = os.path.join(self.si.WindowsSdkDir, 'Bin') arch_subdir = self.pi.current_dir(x64=True) sdkver = self._get_content_dirname(path, slash=False) - tools += [os.path.join(path, r'%s%s' % (sdkver, arch_subdir))] + yield os.path.join(path, r'%s%s' % (sdkver, arch_subdir)) if self.si.WindowsSDKExecutablePath: - tools += [self.si.WindowsSDKExecutablePath] - - return tools + yield self.si.WindowsSDKExecutablePath @property def SdkSetup(self): -- cgit v1.2.1 From f357a32fdc9ce8e6a862efcbb9a0229f6f0a685c Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Fri, 7 Apr 2017 22:30:49 -0400 Subject: Simplify _get_content_dirname by simply removing the trailing backslash. Ref #995. --- setuptools/msvc.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index c5a8aea0..9a911834 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -1010,7 +1010,7 @@ class EnvironmentInfo: elif self.vc_ver >= 15.0: path = os.path.join(self.si.WindowsSdkDir, 'Bin') arch_subdir = self.pi.current_dir(x64=True) - sdkver = self._get_content_dirname(path, slash=False) + sdkver = self._get_content_dirname(path).rstrip('\\') yield os.path.join(path, r'%s%s' % (sdkver, arch_subdir)) if self.si.WindowsSDKExecutablePath: @@ -1243,7 +1243,7 @@ class EnvironmentInfo: seen_add(k) yield element - def _get_content_dirname(self, path, slash=True): + def _get_content_dirname(self, path): """ Return name of the first dir in path or '' if no dir found. @@ -1251,8 +1251,6 @@ class EnvironmentInfo: ---------- path: str Path where search dir. - slash: bool - If not True, only return "name" not "name\" Return ------ @@ -1262,10 +1260,7 @@ class EnvironmentInfo: try: name = os.listdir(path) if name: - name = name[0] - if slash: - return '%s\\' % name - return name + return '%s\\' % name[0] return '' except (OSError, IOError): return '' -- cgit v1.2.1 From cd13a8c0c4ee765a8bd083863338dec4ba618d08 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Fri, 7 Apr 2017 22:33:28 -0400 Subject: Remove unnecessary raw string. Ref #995. --- setuptools/msvc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 9a911834..35c02129 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -1011,7 +1011,7 @@ class EnvironmentInfo: path = os.path.join(self.si.WindowsSdkDir, 'Bin') arch_subdir = self.pi.current_dir(x64=True) sdkver = self._get_content_dirname(path).rstrip('\\') - yield os.path.join(path, r'%s%s' % (sdkver, arch_subdir)) + yield os.path.join(path, '%s%s' % (sdkver, arch_subdir)) if self.si.WindowsSDKExecutablePath: yield self.si.WindowsSDKExecutablePath -- cgit v1.2.1 From f420bb2093f85d3aa34e732c42133b0e2e06ecd9 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 8 Apr 2017 10:18:31 -0400 Subject: Let the default vc_min_ver represent the most lenient, degenerate limit. --- setuptools/msvc.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 35c02129..75745e67 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -806,15 +806,14 @@ class EnvironmentInfo: # 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): + def __init__(self, arch, vc_ver=None, vc_min_ver=0): 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) + 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): -- cgit v1.2.1 From 66177c944536aab86994f6df7172c0d9d6acb5cf Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 8 Apr 2017 10:20:47 -0400 Subject: Extract private method for locating latest available vc ver. --- setuptools/msvc.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 75745e67..d739178b 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -472,14 +472,14 @@ class SystemInfo: 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) + self.vc_ver = vc_ver or self._find_latest_available_vc_ver() + + def _find_latest_available_vc_ver(self): + try: + return 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): """ -- cgit v1.2.1 From b50fdf497d6970002a2f7156650d7da21e2e39f5 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 8 Apr 2017 10:44:34 -0400 Subject: In msvc9_query_vcvarsall, ensure dict values are not unicode. Fixes #992. --- setuptools/msvc.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index d739178b..1e7a3277 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -26,6 +26,7 @@ from packaging.version import LegacyVersion from six.moves import filterfalse from .monkey import get_unpatched +from . import py27compat if platform.system() == 'Windows': from six.moves import winreg @@ -134,11 +135,13 @@ def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs): # If error, try to set environment directly try: - return EnvironmentInfo(arch, ver).return_env() + env = EnvironmentInfo(arch, ver).return_env() except distutils.errors.DistutilsPlatformError as exc: _augment_exception(exc, ver, arch) raise + return py27compat.make_dict_values_strings(env) + def msvc14_get_vc_env(plat_spec): """ -- cgit v1.2.1 From 6ab912d1f676604d71e8e2090d262002f78929d4 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 8 Apr 2017 11:23:32 -0400 Subject: Correct typo. Ref #992. --- setuptools/msvc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 1e7a3277..3970bfaf 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -140,7 +140,7 @@ def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs): _augment_exception(exc, ver, arch) raise - return py27compat.make_dict_values_strings(env) + return py27compat.dict_values_strings(env) def msvc14_get_vc_env(plat_spec): -- cgit v1.2.1 From a1aa1be06bdef8824c8954bb74dc9a57f324f826 Mon Sep 17 00:00:00 2001 From: JGoutin Date: Mon, 10 Apr 2017 17:56:48 +0200 Subject: Fixes for Visual Studio 2017 - VCRuntimeRedist new path since VS2017. - Use always last Windows SDK and UCRT SDK when more than one version are available. - Minors docstrings changes. Tested with "Visual Studio 2017 Community" and "Visual Studio Build Tools 2017". --- setuptools/msvc.py | 130 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 79 insertions(+), 51 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 3970bfaf..3110eaff 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -4,15 +4,16 @@ 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 Visual C++ Compiler for Python 2.7 (x86, amd64) Microsoft Windows SDK 6.1 (x86, x64, ia64) + Microsoft Windows SDK 7.0 (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) + Microsoft Visual Studio 2017 (x86, x64, arm, arm64) Microsoft Visual Studio Build Tools 2017 (x86, x64, arm, arm64) """ @@ -96,7 +97,7 @@ def msvc9_find_vcvarsall(version): def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs): """ - Patched "distutils.msvc9compiler.query_vcvarsall" for support standalones + Patched "distutils.msvc9compiler.query_vcvarsall" for support extra compilers. Set environment without use of "vcvarsall.bat". @@ -104,9 +105,9 @@ def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs): 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 Visual C++ Compiler for Python 2.7 (x86, amd64) Microsoft Windows SDK 6.1 (x86, x64, ia64) + Microsoft Windows SDK 7.0 (x86, x64, ia64) Microsoft Visual C++ 10.0: Microsoft Windows SDK 7.1 (x86, x64, ia64) @@ -145,7 +146,7 @@ def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs): def msvc14_get_vc_env(plat_spec): """ - Patched "distutils._msvccompiler._get_vc_env" for support standalones + Patched "distutils._msvccompiler._get_vc_env" for support extra compilers. Set environment without use of "vcvarsall.bat". @@ -154,6 +155,7 @@ def msvc14_get_vc_env(plat_spec): ------------------------- Microsoft Visual C++ 14.0: Microsoft Visual C++ Build Tools 2015 (x86, x64, arm) + Microsoft Visual Studio 2017 (x86, x64, arm, arm64) Microsoft Visual Studio Build Tools 2017 (x86, x64, arm, arm64) Parameters @@ -553,7 +555,6 @@ class SystemInfo: """ Locate Visual C for 2017 """ - if self.vc_ver <= 14.0: return @@ -576,9 +577,8 @@ class SystemInfo: @property def WindowsSdkVersion(self): """ - Microsoft Windows SDK versions. + Microsoft Windows SDK versions for specified MSVC++ version. """ - # 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: @@ -590,6 +590,14 @@ class SystemInfo: elif self.vc_ver >= 14.0: return ('10.0', '8.1') + @property + def WindowsSdkLastVersion(self): + """ + Microsoft Windows SDK last version + """ + return self._use_last_dir_name(os.path.join( + self.WindowsSdkDir, 'lib')) + @property def WindowsSdkDir(self): """ @@ -687,6 +695,14 @@ class SystemInfo: break return sdkdir or '' + @property + def UniversalCRTSdkLastVersion(self): + """ + Microsoft Universal C Runtime SDK last version + """ + return self._use_last_dir_name(os.path.join( + self.UniversalCRTSdkDir, 'lib')) + @property def NetFxSdkVersion(self): """ @@ -746,7 +762,7 @@ class SystemInfo: """ return self._find_dot_net_versions(64) - def _find_dot_net_versions(self, bits=32): + def _find_dot_net_versions(self, bits): """ Find Microsoft .NET Framework versions. @@ -758,7 +774,7 @@ class SystemInfo: # Find actual .NET version in registry reg_ver = self.ri.lookup(self.ri.vc, 'frameworkver%d' % bits) dot_net_dir = getattr(self, 'FrameworkDir%d' % bits) - ver = reg_ver or self._find_dot_net_in(dot_net_dir) or '' + ver = reg_ver or self._use_last_dir_name(dot_net_dir, 'v') or '' # Set .NET versions for specified MSVC++ version if self.vc_ver >= 12.0: @@ -772,17 +788,24 @@ class SystemInfo: frameworkver = ('v3.0', 'v2.0.50727') return frameworkver - def _find_dot_net_in(self, dot_net_dir): + def _use_last_dir_name(self, path, prefix=''): """ - Find .Net in the Framework folder + Return name of the last dir in path or '' if no dir found. + + Parameters + ---------- + path: str + Use dirs in this path + prefix: str + Use only dirs startings by this prefix """ matching_dirs = ( dir_name - for dir_name in reversed(os.listdir(dot_net_dir)) - if os.path.isdir(os.path.join(dot_net_dir, dir_name)) - and dir_name.startswith('v') + for dir_name in reversed(os.listdir(path)) + if os.path.isdir(os.path.join(path, dir_name)) and + dir_name.startswith(prefix) ) - return next(matching_dirs, None) + return next(matching_dirs, None) or '' class EnvironmentInfo: @@ -917,8 +940,8 @@ class EnvironmentInfo: 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))] + libver = self._sdk_subdir + return [os.path.join(lib, '%sum%s' % (libver , arch_subdir))] @property def OSIncludes(self): @@ -932,7 +955,7 @@ class EnvironmentInfo: else: if self.vc_ver >= 14.0: - sdkver = self._get_content_dirname(include) + sdkver = self._sdk_subdir else: sdkver = '' return [os.path.join(include, '%sshared' % sdkver), @@ -992,6 +1015,9 @@ class EnvironmentInfo: return list(self._sdk_tools()) def _sdk_tools(self): + """ + Microsoft Windows SDK Tools paths generator + """ if self.vc_ver < 15.0: bin_dir = 'Bin' if self.vc_ver <= 11.0 else r'Bin\x86' yield os.path.join(self.si.WindowsSdkDir, bin_dir) @@ -1012,12 +1038,20 @@ class EnvironmentInfo: elif self.vc_ver >= 15.0: path = os.path.join(self.si.WindowsSdkDir, 'Bin') arch_subdir = self.pi.current_dir(x64=True) - sdkver = self._get_content_dirname(path).rstrip('\\') + sdkver = self.si.WindowsSdkLastVersion yield os.path.join(path, '%s%s' % (sdkver, arch_subdir)) if self.si.WindowsSDKExecutablePath: yield self.si.WindowsSDKExecutablePath + @property + def _sdk_subdir(self): + """ + Microsoft Windows SDK version subdir + """ + ucrtver = self.si.WindowsSdkLastVersion + return ('%s\\' % ucrtver) if ucrtver else '' + @property def SdkSetup(self): """ @@ -1116,27 +1150,34 @@ class EnvironmentInfo: @property def UCRTLibraries(self): """ - Microsoft Universal CRT Libraries + Microsoft Universal C Runtime SDK 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) + ucrtver = self._ucrt_subdir return [os.path.join(lib, '%sucrt%s' % (ucrtver, arch_subdir))] @property def UCRTIncludes(self): """ - Microsoft Universal CRT Include + Microsoft Universal C Runtime SDK 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)] + return [os.path.join(include, '%sucrt' % self._ucrt_subdir)] + + @property + def _ucrt_subdir(self): + """ + Microsoft Universal C Runtime SDK version subdir + """ + ucrtver = self.si.UniversalCRTSdkLastVersion + return ('%s\\' % ucrtver) if ucrtver else '' @property def FSharp(self): @@ -1154,9 +1195,18 @@ class EnvironmentInfo: 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) + if self.vc_ver < 15: + redist_path = self.si.VCInstallDir + vcruntime = 'redist%s\\Microsoft.VC%d0.CRT\\vcruntime%d0.dll' + else: + redist_path = self.si.VCInstallDir.replace('\\Tools', '\\Redist') + vcruntime = 'onecore%s\\Microsoft.VC%d0.CRT\\vcruntime%d0.dll' + + # Visual Studio 2017 is still Visual C++ 14.0 + dll_ver = 14.0 if self.vc_ver == 15 else self.vc_ver + + vcruntime = vcruntime % (arch_subdir, self.vc_ver, dll_ver) + return os.path.join(redist_path, vcruntime) def return_env(self, exists=True): """ @@ -1244,25 +1294,3 @@ class EnvironmentInfo: 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 '' -- cgit v1.2.1 From 74b46ceaf9affd65da0ba0d2d56e58a85955a652 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 16 Apr 2017 09:00:53 -0500 Subject: Revert "In msvc9_query_vcvarsall, ensure dict values are not unicode. Fixes #992." This reverts commit b50fdf497d6970002a2f7156650d7da21e2e39f5. --- setuptools/msvc.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 3110eaff..84dcb2a7 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -27,7 +27,6 @@ from packaging.version import LegacyVersion from six.moves import filterfalse from .monkey import get_unpatched -from . import py27compat if platform.system() == 'Windows': from six.moves import winreg @@ -136,13 +135,11 @@ def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs): # If error, try to set environment directly try: - env = EnvironmentInfo(arch, ver).return_env() + return EnvironmentInfo(arch, ver).return_env() except distutils.errors.DistutilsPlatformError as exc: _augment_exception(exc, ver, arch) raise - return py27compat.dict_values_strings(env) - def msvc14_get_vc_env(plat_spec): """ -- cgit v1.2.1 From 300c8802ef4d13d9433af3bce9d22936ff3c610f Mon Sep 17 00:00:00 2001 From: Segev Finer Date: Thu, 3 Aug 2017 21:39:59 +0300 Subject: Fix exception on mingw built Python 2 msvc9compiler doesn't like being imported on mingw built Python. It throws DistutilsPlatformError, so catch it. Fixes #1118 --- setuptools/msvc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 729021ac..f3917815 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -47,7 +47,7 @@ else: try: from distutils.msvc9compiler import Reg -except ImportError: +except (ImportError, distutils.errors.DistutilsPlatformError): pass -- cgit v1.2.1 From 20d6c6c22d88260669a1aec573d62aabc4052abf Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Thu, 3 Aug 2017 14:52:36 -0400 Subject: Extract variable for exceptions to provide explanation --- setuptools/msvc.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index f3917815..8e3b638f 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -45,9 +45,18 @@ else: safe_env = dict() +_msvc9_suppress_errors = ( + # msvc9compiler isn't available on some platforms + ImportError, + + # msvc9compiler raises DistutilsPlatformError in some + # environments. See #1118. + distutils.errors.DistutilsPlatformError, +) + try: from distutils.msvc9compiler import Reg -except (ImportError, distutils.errors.DistutilsPlatformError): +except _msvc9_suppress_errors: pass -- cgit v1.2.1 From 929acc4e551448a68411968fb50336ad51ed4d3c Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 17 Mar 2018 14:10:32 -0400 Subject: Setuptools now vendors its own direct dependencies (packaging, six, pyparsing). Ref #1296. --- setuptools/msvc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 8e3b638f..5e20b3f1 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -22,7 +22,7 @@ import sys import platform import itertools import distutils.errors -from pkg_resources.extern.packaging.version import LegacyVersion +from setuptools.extern.packaging.version import LegacyVersion from setuptools.extern.six.moves import filterfalse @@ -48,7 +48,7 @@ else: _msvc9_suppress_errors = ( # msvc9compiler isn't available on some platforms ImportError, - + # msvc9compiler raises DistutilsPlatformError in some # environments. See #1118. distutils.errors.DistutilsPlatformError, -- cgit v1.2.1 From 209e3ac20fa69c7352e28b2aeeb2898fbbbf87d4 Mon Sep 17 00:00:00 2001 From: JGoutin Date: Tue, 12 Jun 2018 20:39:32 +0200 Subject: Fix "Microsoft Visual C++ Build Tools" link --- setuptools/msvc.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 5e20b3f1..b9c472f1 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -232,8 +232,7 @@ def _augment_exception(exc, version, arch=''): 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') + r'https://visualstudio.microsoft.com/downloads/') exc.args = (message, ) -- cgit v1.2.1 From 7e1b1934c7e0dcd400ff17a701601d912aa603bc Mon Sep 17 00:00:00 2001 From: jgoutin Date: Sat, 3 Aug 2019 10:41:34 +0200 Subject: Improve Visual C++ 14.X support Improve VC++14 support for VS 2017 and 2019. Separate VC from VS version (Miss match starting VS15). Improve docstrings args and returns information + fixe typos. Fix coding style and minor coding issues. Remove Microsoft "Windows SDK 7.0" dead link. --- setuptools/msvc.py | 1021 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 699 insertions(+), 322 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index b9c472f1..ffa7053b 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -11,13 +11,17 @@ Microsoft Visual C++ 9.0: Microsoft Visual C++ 10.0: Microsoft Windows SDK 7.1 (x86, x64, ia64) -Microsoft Visual C++ 14.0: +Microsoft Visual C++ 14.X: Microsoft Visual C++ Build Tools 2015 (x86, x64, arm) - Microsoft Visual Studio 2017 (x86, x64, arm, arm64) Microsoft Visual Studio Build Tools 2017 (x86, x64, arm, arm64) + Microsoft Visual Studio Build Tools 2019 (x86, x64, arm, arm64) + +This may also support compilers shipped with compatible Visual Studio versions. """ -import os +import json +from os import listdir, pathsep +from os.path import join, isfile, isdir, dirname import sys import platform import itertools @@ -30,12 +34,9 @@ from .monkey import get_unpatched if platform.system() == 'Windows': from setuptools.extern.six.moves import winreg - safe_env = os.environ + from os import environ else: - """ - Mock winreg and environ so the module can be imported - on this platform. - """ + # Mock winreg and environ so the module can be imported on this platform. class winreg: HKEY_USERS = None @@ -43,7 +44,7 @@ else: HKEY_LOCAL_MACHINE = None HKEY_CLASSES_ROOT = None - safe_env = dict() + environ = dict() _msvc9_suppress_errors = ( # msvc9compiler isn't available on some platforms @@ -63,15 +64,13 @@ except _msvc9_suppress_errors: 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. + compiler build for Python + (VCForPython / Microsoft Visual C++ Compiler for Python 2.7). - Redirect the path of "vcvarsall.bat". + Fall back to original behavior when the standalone compiler is not + available. - Known supported compilers - ------------------------- - Microsoft Visual C++ 9.0: - Microsoft Visual C++ Compiler for Python 2.7 (x86, amd64) + Redirect the path of "vcvarsall.bat". Parameters ---------- @@ -80,24 +79,25 @@ def msvc9_find_vcvarsall(version): Return ------ - vcvarsall.bat path: str + str + vcvarsall.bat path """ - VC_BASE = r'Software\%sMicrosoft\DevDiv\VCForPython\%0.1f' - key = VC_BASE % ('', version) + 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) + 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): + vcvarsall = join(productdir, "vcvarsall.bat") + if isfile(vcvarsall): return vcvarsall return get_unpatched(msvc9_find_vcvarsall)(version) @@ -106,20 +106,10 @@ def msvc9_find_vcvarsall(version): def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs): """ Patched "distutils.msvc9compiler.query_vcvarsall" for support extra - compilers. + Microsoft Visual C++ 9.0 and 10.0 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 6.1 (x86, x64, ia64) - Microsoft Windows SDK 7.0 (x86, x64, ia64) - - Microsoft Visual C++ 10.0: - Microsoft Windows SDK 7.1 (x86, x64, ia64) - Parameters ---------- ver: float @@ -129,9 +119,10 @@ def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs): Return ------ - environment: dict + dict + environment """ - # Try to get environement from vcvarsall.bat (Classical way) + # Try to get environment from vcvarsall.bat (Classical way) try: orig = get_unpatched(msvc9_query_vcvarsall) return orig(ver, arch, *args, **kwargs) @@ -153,17 +144,10 @@ def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs): def msvc14_get_vc_env(plat_spec): """ Patched "distutils._msvccompiler._get_vc_env" for support extra - compilers. + Microsoft Visual C++ 14.X 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) - Microsoft Visual Studio 2017 (x86, x64, arm, arm64) - Microsoft Visual Studio Build Tools 2017 (x86, x64, arm, arm64) - Parameters ---------- plat_spec: str @@ -171,7 +155,8 @@ def msvc14_get_vc_env(plat_spec): Return ------ - environment: dict + dict + environment """ # Try to get environment from vcvarsall.bat (Classical way) try: @@ -217,9 +202,9 @@ def _augment_exception(exc, version, arch=''): 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 + # to Windows SDK 7.0. + # Note: No download link available from Microsoft. + message += ' Get it with "Microsoft Windows SDK 7.0"' else: # For VC++ 9.0 redirect user to Vc++ for Python 2.7 : # This redirection link is maintained by Microsoft. @@ -230,8 +215,8 @@ def _augment_exception(exc, version, arch=''): 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": ' + # For VC++ 14.X Redirect user to latest Visual C++ Build Tools + message += (' Get it with "Build Tools for Visual Studio": ' r'https://visualstudio.microsoft.com/downloads/') exc.args = (message, ) @@ -239,26 +224,50 @@ def _augment_exception(exc, version, arch=''): class PlatformInfo: """ - Current and Target Architectures informations. + Current and Target Architectures information. Parameters ---------- arch: str Target architecture. """ - current_cpu = safe_env.get('processor_architecture', '').lower() + current_cpu = environ.get('processor_architecture', '').lower() def __init__(self, arch): self.arch = arch.lower().replace('x64', 'amd64') @property def target_cpu(self): + """ + Return Target CPU architecture. + + Return + ------ + str + Target CPU + """ return self.arch[self.arch.find('_') + 1:] def target_is_x86(self): + """ + Return True if target CPU is x86 32 bits.. + + Return + ------ + bool + CPU is x86 32 bits + """ return self.target_cpu == 'x86' def current_is_x86(self): + """ + Return True if current CPU is x86 32 bits.. + + Return + ------ + bool + CPU is x86 32 bits + """ return self.current_cpu == 'x86' def current_dir(self, hidex86=False, x64=False): @@ -274,8 +283,8 @@ class PlatformInfo: Return ------ - subfolder: str - '\target', or '' (see hidex86 parameter) + str + subfolder: '\target', or '' (see hidex86 parameter) """ return ( '' if (self.current_cpu == 'x86' and hidex86) else @@ -296,8 +305,8 @@ class PlatformInfo: Return ------ - subfolder: str - '\current', or '' (see hidex86 parameter) + str + subfolder: '\current', or '' (see hidex86 parameter) """ return ( '' if (self.target_cpu == 'x86' and hidex86) else @@ -312,13 +321,13 @@ class PlatformInfo: Parameters ---------- forcex86: bool - Use 'x86' as current architecture even if current acritecture is + Use 'x86' as current architecture even if current architecture is not x86. Return ------ - subfolder: str - '' if target architecture is current architecture, + str + subfolder: '' if target architecture is current architecture, '\current_target' if not. """ current = 'x86' if forcex86 else self.current_cpu @@ -330,7 +339,7 @@ class PlatformInfo: class RegistryInfo: """ - Microsoft Visual Studio related registry informations. + Microsoft Visual Studio related registry information. Parameters ---------- @@ -349,6 +358,11 @@ class RegistryInfo: def visualstudio(self): """ Microsoft Visual Studio root registry key. + + Return + ------ + str + Registry key """ return 'VisualStudio' @@ -356,27 +370,47 @@ class RegistryInfo: def sxs(self): """ Microsoft Visual Studio SxS registry key. + + Return + ------ + str + Registry key """ - return os.path.join(self.visualstudio, 'SxS') + return join(self.visualstudio, 'SxS') @property def vc(self): """ Microsoft Visual C++ VC7 registry key. + + Return + ------ + str + Registry key """ - return os.path.join(self.sxs, 'VC7') + return join(self.sxs, 'VC7') @property def vs(self): """ Microsoft Visual Studio VS7 registry key. + + Return + ------ + str + Registry key """ - return os.path.join(self.sxs, 'VS7') + return join(self.sxs, 'VS7') @property def vc_for_python(self): """ Microsoft Visual C++ for Python registry key. + + Return + ------ + str + Registry key """ return r'DevDiv\VCForPython' @@ -384,6 +418,11 @@ class RegistryInfo: def microsoft_sdk(self): """ Microsoft SDK registry key. + + Return + ------ + str + Registry key """ return 'Microsoft SDKs' @@ -391,20 +430,35 @@ class RegistryInfo: def windows_sdk(self): """ Microsoft Windows/Platform SDK registry key. + + Return + ------ + str + Registry key """ - return os.path.join(self.microsoft_sdk, 'Windows') + return join(self.microsoft_sdk, 'Windows') @property def netfx_sdk(self): """ Microsoft .NET Framework SDK registry key. + + Return + ------ + str + Registry key """ - return os.path.join(self.microsoft_sdk, 'NETFXSDK') + return join(self.microsoft_sdk, 'NETFXSDK') @property def windows_kits_roots(self): """ Microsoft Windows Kits Roots registry key. + + Return + ------ + str + Registry key """ return r'Windows Kits\Installed Roots' @@ -421,10 +475,11 @@ class RegistryInfo: Return ------ - str: value + str + Registry key """ node64 = '' if self.pi.current_is_x86() or x86 else 'Wow6432Node' - return os.path.join('Software', node64, 'Microsoft', key) + return join('Software', node64, 'Microsoft', key) def lookup(self, key, name): """ @@ -439,18 +494,19 @@ class RegistryInfo: Return ------ - str: value + str + value """ - KEY_READ = winreg.KEY_READ + 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) + 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) + bkey = openkey(hkey, ms(key, True), 0, key_read) except (OSError, IOError): continue else: @@ -463,7 +519,7 @@ class RegistryInfo: class SystemInfo: """ - Microsoft Windows and Visual Studio related system inormations. + Microsoft Windows and Visual Studio related system information. Parameters ---------- @@ -474,30 +530,52 @@ class SystemInfo: """ # 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) + # names from Microsoft source files for more easy comparison. + WinDir = environ.get('WinDir', '') + ProgramFiles = environ.get('ProgramFiles', '') + ProgramFilesx86 = environ.get('ProgramFiles(x86)', ProgramFiles) def __init__(self, registry_info, vc_ver=None): self.ri = registry_info self.pi = self.ri.pi - self.vc_ver = vc_ver or self._find_latest_available_vc_ver() - def _find_latest_available_vc_ver(self): - try: - return self.find_available_vc_vers()[-1] - except IndexError: - err = 'No Microsoft Visual C++ version found' - raise distutils.errors.DistutilsPlatformError(err) + self.known_vs_paths = self.find_programdata_vs_vers() + + # Except for VS15+, VC version is aligned with VS version + self.vs_ver = self.vc_ver = ( + vc_ver or self._find_latest_available_vs_ver()) + + def _find_latest_available_vs_ver(self): + """ + Find the latest VC version + + Return + ------ + float + version + """ + reg_vc_vers = self.find_reg_vs_vers() + + if not (reg_vc_vers or self.known_vs_paths): + raise distutils.errors.DistutilsPlatformError( + 'No Microsoft Visual C++ version found') + + vc_vers = set(reg_vc_vers) + vc_vers.update(self.known_vs_paths) + return sorted(vc_vers)[-1] - def find_available_vc_vers(self): + def find_reg_vs_vers(self): """ - Find all available Microsoft Visual C++ versions. + Find Microsoft Visual Studio versions available in registry. + + Return + ------ + list of float + Versions """ ms = self.ri.microsoft vckeys = (self.ri.vc, self.ri.vc_for_python, self.ri.vs) - vc_vers = [] + vs_vers = [] for hkey in self.ri.HKEYS: for key in vckeys: try: @@ -508,49 +586,108 @@ class SystemInfo: for i in range(values): try: ver = float(winreg.EnumValue(bkey, i)[0]) - if ver not in vc_vers: - vc_vers.append(ver) + if ver not in vs_vers: + vs_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) + if ver not in vs_vers: + vs_vers.append(ver) except ValueError: pass - return sorted(vc_vers) + return sorted(vs_vers) + + def find_programdata_vs_vers(self): + r""" + Find Visual studio 2017+ versions from information in + "C:\ProgramData\Microsoft\VisualStudio\Packages\_Instances". + + Return + ------ + dict + float version as key, path as value. + """ + vs_versions = {} + instances_dir = \ + r'C:\ProgramData\Microsoft\VisualStudio\Packages\_Instances' + + try: + hashed_names = listdir(instances_dir) + + except (OSError, IOError): + # Directory not exists with all Visual Studio versions + return vs_versions + + for name in hashed_names: + try: + # Get VS installation path from "state.json" file + state_path = join(instances_dir, name, 'state.json') + with open(state_path, 'rt', encoding='utf-8') as state_file: + state = json.load(state_file) + vs_path = state['installationPath'] + + # Raises OSError if this VS installation does not contain VC + listdir(join(vs_path, r'VC\Tools\MSVC')) + + # Store version and path + vs_versions[self._as_float_version( + state['installationVersion'])] = vs_path + + except (OSError, IOError, KeyError): + # Skip if "state.json" file is missing or bad format + continue + + return vs_versions + + @staticmethod + def _as_float_version(version): + """ + Return a string version as a simplified float version (major.minor) + + Parameters + ---------- + version: str + Version. + + Return + ------ + float + version + """ + return float('.'.join(version.split('.')[:2])) @property def VSInstallDir(self): """ Microsoft Visual Studio directory. + + Return + ------ + str + path """ # Default path - name = 'Microsoft Visual Studio %0.1f' % self.vc_ver - default = os.path.join(self.ProgramFilesx86, name) + default = join(self.ProgramFilesx86, + 'Microsoft Visual Studio %0.1f' % self.vs_ver) # 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 + return self.ri.lookup(self.ri.vs, '%0.1f' % self.vs_ver) or default @property def VCInstallDir(self): """ Microsoft Visual C++ directory. - """ - self.VSInstallDir - - guess_vc = self._guess_vc() or self._guess_vc_legacy() - - # 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 + Return + ------ + str + path + """ + path = self._guess_vc() or self._guess_vc_legacy() - if not os.path.isdir(path): + if not isdir(path): msg = 'Microsoft Visual C++ directory not found' raise distutils.errors.DistutilsPlatformError(msg) @@ -558,186 +695,256 @@ class SystemInfo: def _guess_vc(self): """ - Locate Visual C for 2017 + Locate Visual C++ for VS2017+. + + Return + ------ + str + path """ - if self.vc_ver <= 14.0: - return + if self.vs_ver <= 14.0: + return '' + + try: + # First search in known VS paths + vs_dir = self.known_vs_paths[self.vs_ver] + except KeyError: + # Else, search with path from registry + vs_dir = self.VSInstallDir + + guess_vc = join(vs_dir, r'VC\Tools\MSVC') - default = r'VC\Tools\MSVC' - guess_vc = os.path.join(self.VSInstallDir, default) # Subdir with VC exact version as name try: - vc_exact_ver = os.listdir(guess_vc)[-1] - return os.path.join(guess_vc, vc_exact_ver) + # Update the VC version with real one instead of VS version + vc_ver = listdir(guess_vc)[-1] + self.vc_ver = self._as_float_version(vc_ver) + return join(guess_vc, vc_ver) except (OSError, IOError, IndexError): - pass + return '' def _guess_vc_legacy(self): """ - Locate Visual C for versions prior to 2017 + Locate Visual C++ for versions prior to 2017. + + Return + ------ + str + path """ - default = r'Microsoft Visual Studio %0.1f\VC' % self.vc_ver - return os.path.join(self.ProgramFilesx86, default) + default = join(self.ProgramFilesx86, + r'Microsoft Visual Studio %0.1f\VC' % self.vs_ver) + + # Try to get "VC++ for Python" path from registry as default path + reg_path = join(self.ri.vc_for_python, '%0.1f' % self.vs_ver) + python_vc = self.ri.lookup(reg_path, 'installdir') + default_vc = join(python_vc, 'VC') if python_vc else default + + # Try to get path from registry, if fail use default path + return self.ri.lookup(self.ri.vc, '%0.1f' % self.vs_ver) or default_vc @property def WindowsSdkVersion(self): """ Microsoft 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') + + Return + ------ + tuple of str + versions + """ + if self.vs_ver <= 9.0: + return '7.0', '6.1', '6.0a' + elif self.vs_ver == 10.0: + return '7.1', '7.0a' + elif self.vs_ver == 11.0: + return '8.0', '8.0a' + elif self.vs_ver == 12.0: + return '8.1', '8.1a' + elif self.vs_ver >= 14.0: + return '10.0', '8.1' @property def WindowsSdkLastVersion(self): """ - Microsoft Windows SDK last version + Microsoft Windows SDK last version. + + Return + ------ + str + version """ - return self._use_last_dir_name(os.path.join( - self.WindowsSdkDir, 'lib')) + return self._use_last_dir_name(join(self.WindowsSdkDir, 'lib')) @property def WindowsSdkDir(self): """ Microsoft Windows SDK directory. + + Return + ------ + str + path """ sdkdir = '' for ver in self.WindowsSdkVersion: # Try to get it from registry - loc = os.path.join(self.ri.windows_sdk, 'v%s' % ver) + loc = 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): + if not sdkdir or not 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) + 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): + sdkdir = join(install_base, 'WinSDK') + if not sdkdir or not 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): + path = r'Microsoft SDKs\Windows Kits\%s' % intver + d = join(self.ProgramFiles, path) + if isdir(d): sdkdir = d - if not sdkdir or not os.path.isdir(sdkdir): + if not sdkdir or not 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): + d = join(self.ProgramFiles, path) + if isdir(d): sdkdir = d if not sdkdir: # If fail, use Platform SDK - sdkdir = os.path.join(self.VCInstallDir, 'PlatformSDK') + sdkdir = join(self.VCInstallDir, 'PlatformSDK') return sdkdir @property def WindowsSDKExecutablePath(self): """ Microsoft Windows SDK executable directory. + + Return + ------ + str + path """ # Find WinSDK NetFx Tools registry dir name - if self.vc_ver <= 11.0: + if self.vs_ver <= 11.0: netfxver = 35 arch = '' else: netfxver = 40 - hidex86 = True if self.vc_ver <= 12.0 else False + hidex86 = True if self.vs_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 + # list all possibles registry paths regpaths = [] - if self.vc_ver >= 14.0: + if self.vs_ver >= 14.0: for ver in self.NetFxSdkVersion: - regpaths += [os.path.join(self.ri.netfx_sdk, ver, fx)] + regpaths += [join(self.ri.netfx_sdk, ver, fx)] for ver in self.WindowsSdkVersion: - regpaths += [os.path.join(self.ri.windows_sdk, 'v%sA' % ver, fx)] + regpaths += [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 + return execpath @property def FSharpInstallDir(self): """ Microsoft Visual F# directory. + + Return + ------ + str + path """ - path = r'%0.1f\Setup\F#' % self.vc_ver - path = os.path.join(self.ri.visualstudio, path) + path = join(self.ri.visualstudio, r'%0.1f\Setup\F#' % self.vs_ver) return self.ri.lookup(path, 'productdir') or '' @property def UniversalCRTSdkDir(self): """ Microsoft Universal CRT SDK directory. + + Return + ------ + str + path """ # Set Kit Roots versions for specified MSVC++ version - if self.vc_ver >= 14.0: - vers = ('10', '81') - else: - vers = () + vers = ('10', '81') if self.vs_ver >= 14.0 else () # 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 '' + return sdkdir or '' @property def UniversalCRTSdkLastVersion(self): """ - Microsoft Universal C Runtime SDK last version + Microsoft Universal C Runtime SDK last version. + + Return + ------ + str + version """ - return self._use_last_dir_name(os.path.join( - self.UniversalCRTSdkDir, 'lib')) + return self._use_last_dir_name(join(self.UniversalCRTSdkDir, 'lib')) @property def NetFxSdkVersion(self): """ Microsoft .NET Framework SDK versions. + + Return + ------ + tuple of str + versions """ - # Set FxSdk versions for specified MSVC++ version - if self.vc_ver >= 14.0: - return ('4.6.1', '4.6') - else: - return () + # Set FxSdk versions for specified VS version + return (('4.7.2', '4.7.1', '4.7', + '4.6.2', '4.6.1', '4.6', + '4.5.2', '4.5.1', '4.5') + if self.vs_ver >= 14.0 else ()) @property def NetFxSdkDir(self): """ Microsoft .NET Framework SDK directory. + + Return + ------ + str + path """ + sdkdir = '' for ver in self.NetFxSdkVersion: - loc = os.path.join(self.ri.netfx_sdk, ver) + loc = join(self.ri.netfx_sdk, ver) sdkdir = self.ri.lookup(loc, 'kitsinstallationfolder') if sdkdir: break - return sdkdir or '' + return sdkdir @property def FrameworkDir32(self): """ Microsoft .NET Framework 32bit directory. + + Return + ------ + str + path """ # Default path - guess_fw = os.path.join(self.WinDir, r'Microsoft.NET\Framework') + guess_fw = 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 @@ -746,9 +953,14 @@ class SystemInfo: def FrameworkDir64(self): """ Microsoft .NET Framework 64bit directory. + + Return + ------ + str + path """ # Default path - guess_fw = os.path.join(self.WinDir, r'Microsoft.NET\Framework64') + guess_fw = 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 @@ -757,6 +969,11 @@ class SystemInfo: def FrameworkVersion32(self): """ Microsoft .NET Framework 32bit versions. + + Return + ------ + tuple of str + versions """ return self._find_dot_net_versions(32) @@ -764,6 +981,11 @@ class SystemInfo: def FrameworkVersion64(self): """ Microsoft .NET Framework 64bit versions. + + Return + ------ + tuple of str + versions """ return self._find_dot_net_versions(64) @@ -775,6 +997,11 @@ class SystemInfo: ---------- bits: int Platform number of bits: 32 or 64. + + Return + ------ + tuple of str + versions """ # Find actual .NET version in registry reg_ver = self.ri.lookup(self.ri.vc, 'frameworkver%d' % bits) @@ -782,18 +1009,17 @@ class SystemInfo: ver = reg_ver or self._use_last_dir_name(dot_net_dir, 'v') 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 - - def _use_last_dir_name(self, path, prefix=''): + if self.vs_ver >= 12.0: + return ver, 'v4.0' + elif self.vs_ver >= 10.0: + return 'v4.0.30319' if ver.lower()[:2] != 'v4' else ver, 'v3.5' + elif self.vs_ver == 9.0: + return 'v3.5', 'v2.0.50727' + elif self.vs_ver == 8.0: + return 'v3.0', 'v2.0.50727' + + @staticmethod + def _use_last_dir_name(path, prefix=''): """ Return name of the last dir in path or '' if no dir found. @@ -802,12 +1028,17 @@ class SystemInfo: path: str Use dirs in this path prefix: str - Use only dirs startings by this prefix + Use only dirs starting by this prefix + + Return + ------ + str + name """ matching_dirs = ( dir_name - for dir_name in reversed(os.listdir(path)) - if os.path.isdir(os.path.join(path, dir_name)) and + for dir_name in reversed(listdir(path)) + if isdir(join(path, dir_name)) and dir_name.startswith(prefix) ) return next(matching_dirs, None) or '' @@ -818,7 +1049,7 @@ 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. + This function is compatible with Microsoft Visual C++ 9.0 to 14.X. Script created by analysing Microsoft environment configuration files like "vcvars[...].bat", "SetEnv.Cmd", "vcbuildtools.bat", ... @@ -835,7 +1066,7 @@ class EnvironmentInfo: """ # Variables and properties in this class use originals CamelCase variables - # names from Microsoft source files for more easy comparaison. + # names from Microsoft source files for more easy comparison. def __init__(self, arch, vc_ver=None, vc_min_ver=0): self.pi = PlatformInfo(arch) @@ -846,205 +1077,255 @@ class EnvironmentInfo: err = 'No suitable Microsoft Visual C++ version found' raise distutils.errors.DistutilsPlatformError(err) + @property + def vs_ver(self): + """ + Microsoft Visual Studio. + + Return + ------ + float + version + """ + return self.si.vs_ver + @property def vc_ver(self): """ Microsoft Visual C++ version. + + Return + ------ + float + version """ return self.si.vc_ver @property def VSTools(self): """ - Microsoft Visual Studio Tools + Microsoft Visual Studio Tools. + + Return + ------ + list of str + paths """ paths = [r'Common7\IDE', r'Common7\Tools'] - if self.vc_ver >= 14.0: + if self.vs_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] + return [join(self.si.VSInstallDir, path) for path in paths] @property def VCIncludes(self): """ - Microsoft Visual C++ & Microsoft Foundation Class Includes + Microsoft Visual C++ & Microsoft Foundation Class Includes. + + Return + ------ + list of str + paths """ - return [os.path.join(self.si.VCInstallDir, 'Include'), - os.path.join(self.si.VCInstallDir, r'ATLMFC\Include')] + return [join(self.si.VCInstallDir, 'Include'), + join(self.si.VCInstallDir, r'ATLMFC\Include')] @property def VCLibraries(self): """ - Microsoft Visual C++ & Microsoft Foundation Class Libraries + Microsoft Visual C++ & Microsoft Foundation Class Libraries. + + Return + ------ + list of str + paths """ - if self.vc_ver >= 15.0: + if self.vs_ver >= 15.0: arch_subdir = self.pi.target_dir(x64=True) else: 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: + if self.vs_ver >= 14.0: paths += [r'Lib\store%s' % arch_subdir] - return [os.path.join(self.si.VCInstallDir, path) for path in paths] + return [join(self.si.VCInstallDir, path) for path in paths] @property def VCStoreRefs(self): """ - Microsoft Visual C++ store references Libraries + Microsoft Visual C++ store references Libraries. + + Return + ------ + list of str + paths """ - if self.vc_ver < 14.0: + if self.vs_ver < 14.0: return [] - return [os.path.join(self.si.VCInstallDir, r'Lib\store\references')] + return [join(self.si.VCInstallDir, r'Lib\store\references')] @property def VCTools(self): """ - Microsoft Visual C++ Tools + Microsoft Visual C++ Tools. + + Return + ------ + list of str + paths """ si = self.si - tools = [os.path.join(si.VCInstallDir, 'VCPackages')] + tools = [join(si.VCInstallDir, 'VCPackages')] - forcex86 = True if self.vc_ver <= 10.0 else False + forcex86 = True if self.vs_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)] + tools += [join(si.VCInstallDir, 'Bin%s' % arch_subdir)] - if self.vc_ver == 14.0: + if self.vs_ver == 14.0: path = 'Bin%s' % self.pi.current_dir(hidex86=True) - tools += [os.path.join(si.VCInstallDir, path)] + tools += [join(si.VCInstallDir, path)] - elif self.vc_ver >= 15.0: + elif self.vs_ver >= 15.0: host_dir = (r'bin\HostX86%s' if self.pi.current_is_x86() else r'bin\HostX64%s') - tools += [os.path.join( + tools += [join( si.VCInstallDir, host_dir % self.pi.target_dir(x64=True))] if self.pi.current_cpu != self.pi.target_cpu: - tools += [os.path.join( + tools += [join( si.VCInstallDir, host_dir % self.pi.current_dir(x64=True))] else: - tools += [os.path.join(si.VCInstallDir, 'Bin')] + tools += [join(si.VCInstallDir, 'Bin')] return tools @property def OSLibraries(self): """ - Microsoft Windows SDK Libraries + Microsoft Windows SDK Libraries. + + Return + ------ + list of str + paths """ - if self.vc_ver <= 10.0: + if self.vs_ver <= 10.0: arch_subdir = self.pi.target_dir(hidex86=True, x64=True) - return [os.path.join(self.si.WindowsSdkDir, 'Lib%s' % arch_subdir)] + return [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') + lib = join(self.si.WindowsSdkDir, 'lib') libver = self._sdk_subdir - return [os.path.join(lib, '%sum%s' % (libver , arch_subdir))] + return [join(lib, '%sum%s' % (libver , arch_subdir))] @property def OSIncludes(self): """ - Microsoft Windows SDK Include + Microsoft Windows SDK Include. + + Return + ------ + list of str + paths """ - include = os.path.join(self.si.WindowsSdkDir, 'include') + include = join(self.si.WindowsSdkDir, 'include') - if self.vc_ver <= 10.0: - return [include, os.path.join(include, 'gl')] + if self.vs_ver <= 10.0: + return [include, join(include, 'gl')] else: - if self.vc_ver >= 14.0: + if self.vs_ver >= 14.0: sdkver = self._sdk_subdir else: sdkver = '' - return [os.path.join(include, '%sshared' % sdkver), - os.path.join(include, '%sum' % sdkver), - os.path.join(include, '%swinrt' % sdkver)] + return [join(include, '%sshared' % sdkver), + join(include, '%sum' % sdkver), + join(include, '%swinrt' % sdkver)] @property def OSLibpath(self): """ - Microsoft Windows SDK Libraries Paths + Microsoft Windows SDK Libraries Paths. + + Return + ------ + list of str + paths """ - ref = os.path.join(self.si.WindowsSdkDir, 'References') + ref = join(self.si.WindowsSdkDir, 'References') libpath = [] - if self.vc_ver <= 9.0: + if self.vs_ver <= 9.0: libpath += self.OSLibraries - if self.vc_ver >= 11.0: - libpath += [os.path.join(ref, r'CommonConfiguration\Neutral')] + if self.vs_ver >= 11.0: + libpath += [join(ref, r'CommonConfiguration\Neutral')] - if self.vc_ver >= 14.0: + if self.vs_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', - ), + join(self.si.WindowsSdkDir, 'UnionMetadata'), + join(ref, 'Windows.Foundation.UniversalApiContract', '1.0.0.0'), + join(ref, 'Windows.Foundation.FoundationContract', '1.0.0.0'), + join(ref,'Windows.Networking.Connectivity.WwanContract', + '1.0.0.0'), + join(self.si.WindowsSdkDir, 'ExtensionSDKs', 'Microsoft.VCLibs', + '%0.1f' % self.vs_ver, 'References', 'CommonConfiguration', + 'neutral'), ] return libpath @property def SdkTools(self): """ - Microsoft Windows SDK Tools + Microsoft Windows SDK Tools. + + Return + ------ + list of str + paths """ return list(self._sdk_tools()) def _sdk_tools(self): """ - Microsoft Windows SDK Tools paths generator + Microsoft Windows SDK Tools paths generator. + + Return + ------ + generator of str + paths """ - if self.vc_ver < 15.0: - bin_dir = 'Bin' if self.vc_ver <= 11.0 else r'Bin\x86' - yield os.path.join(self.si.WindowsSdkDir, bin_dir) + if self.vs_ver < 15.0: + bin_dir = 'Bin' if self.vs_ver <= 11.0 else r'Bin\x86' + yield 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 - yield os.path.join(self.si.WindowsSdkDir, path) + yield join(self.si.WindowsSdkDir, path) - if self.vc_ver == 10.0 or self.vc_ver == 11.0: + if self.vs_ver in (10.0, 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 - yield os.path.join(self.si.WindowsSdkDir, path) + yield join(self.si.WindowsSdkDir, path) - elif self.vc_ver >= 15.0: - path = os.path.join(self.si.WindowsSdkDir, 'Bin') + elif self.vs_ver >= 15.0: + path = join(self.si.WindowsSdkDir, 'Bin') arch_subdir = self.pi.current_dir(x64=True) sdkver = self.si.WindowsSdkLastVersion - yield os.path.join(path, '%s%s' % (sdkver, arch_subdir)) + yield join(path, '%s%s' % (sdkver, arch_subdir)) if self.si.WindowsSDKExecutablePath: yield self.si.WindowsSDKExecutablePath @@ -1052,7 +1333,12 @@ class EnvironmentInfo: @property def _sdk_subdir(self): """ - Microsoft Windows SDK version subdir + Microsoft Windows SDK version subdir. + + Return + ------ + str + subdir """ ucrtver = self.si.WindowsSdkLastVersion return ('%s\\' % ucrtver) if ucrtver else '' @@ -1060,22 +1346,32 @@ class EnvironmentInfo: @property def SdkSetup(self): """ - Microsoft Windows SDK Setup + Microsoft Windows SDK Setup. + + Return + ------ + list of str + paths """ - if self.vc_ver > 9.0: + if self.vs_ver > 9.0: return [] - return [os.path.join(self.si.WindowsSdkDir, 'Setup')] + return [join(self.si.WindowsSdkDir, 'Setup')] @property def FxTools(self): """ - Microsoft .NET Framework Tools + Microsoft .NET Framework Tools. + + Return + ------ + list of str + paths """ pi = self.pi si = self.si - if self.vc_ver <= 10.0: + if self.vs_ver <= 10.0: include32 = True include64 = not pi.target_is_x86() and not pi.current_is_x86() else: @@ -1084,102 +1380,142 @@ class EnvironmentInfo: tools = [] if include32: - tools += [os.path.join(si.FrameworkDir32, ver) + tools += [join(si.FrameworkDir32, ver) for ver in si.FrameworkVersion32] if include64: - tools += [os.path.join(si.FrameworkDir64, ver) + tools += [join(si.FrameworkDir64, ver) for ver in si.FrameworkVersion64] return tools @property def NetFxSDKLibraries(self): """ - Microsoft .Net Framework SDK Libraries + Microsoft .Net Framework SDK Libraries. + + Return + ------ + list of str + paths """ - if self.vc_ver < 14.0 or not self.si.NetFxSdkDir: + if self.vs_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)] + return [join(self.si.NetFxSdkDir, r'lib\um%s' % arch_subdir)] @property def NetFxSDKIncludes(self): """ - Microsoft .Net Framework SDK Includes + Microsoft .Net Framework SDK Includes. + + Return + ------ + list of str + paths """ - if self.vc_ver < 14.0 or not self.si.NetFxSdkDir: + if self.vs_ver < 14.0 or not self.si.NetFxSdkDir: return [] - return [os.path.join(self.si.NetFxSdkDir, r'include\um')] + return [join(self.si.NetFxSdkDir, r'include\um')] @property def VsTDb(self): """ - Microsoft Visual Studio Team System Database + Microsoft Visual Studio Team System Database. + + Return + ------ + list of str + paths """ - return [os.path.join(self.si.VSInstallDir, r'VSTSDB\Deploy')] + return [join(self.si.VSInstallDir, r'VSTSDB\Deploy')] @property def MSBuild(self): """ - Microsoft Build Engine + Microsoft Build Engine. + + Return + ------ + list of str + paths """ - if self.vc_ver < 12.0: + if self.vs_ver < 12.0: return [] - elif self.vc_ver < 15.0: + elif self.vs_ver < 15.0: base_path = self.si.ProgramFilesx86 arch_subdir = self.pi.current_dir(hidex86=True) else: base_path = self.si.VSInstallDir arch_subdir = '' - path = r'MSBuild\%0.1f\bin%s' % (self.vc_ver, arch_subdir) - build = [os.path.join(base_path, path)] + path = r'MSBuild\%0.1f\bin%s' % (self.vs_ver, arch_subdir) + build = [join(base_path, path)] - if self.vc_ver >= 15.0: + if self.vs_ver >= 15.0: # Add Roslyn C# & Visual Basic Compiler - build += [os.path.join(base_path, path, 'Roslyn')] + build += [join(base_path, path, 'Roslyn')] return build @property def HTMLHelpWorkshop(self): """ - Microsoft HTML Help Workshop + Microsoft HTML Help Workshop. + + Return + ------ + list of str + paths """ - if self.vc_ver < 11.0: + if self.vs_ver < 11.0: return [] - return [os.path.join(self.si.ProgramFilesx86, 'HTML Help Workshop')] + return [join(self.si.ProgramFilesx86, 'HTML Help Workshop')] @property def UCRTLibraries(self): """ - Microsoft Universal C Runtime SDK Libraries + Microsoft Universal C Runtime SDK Libraries. + + Return + ------ + list of str + paths """ - if self.vc_ver < 14.0: + if self.vs_ver < 14.0: return [] arch_subdir = self.pi.target_dir(x64=True) - lib = os.path.join(self.si.UniversalCRTSdkDir, 'lib') + lib = join(self.si.UniversalCRTSdkDir, 'lib') ucrtver = self._ucrt_subdir - return [os.path.join(lib, '%sucrt%s' % (ucrtver, arch_subdir))] + return [join(lib, '%sucrt%s' % (ucrtver, arch_subdir))] @property def UCRTIncludes(self): """ - Microsoft Universal C Runtime SDK Include + Microsoft Universal C Runtime SDK Include. + + Return + ------ + list of str + paths """ - if self.vc_ver < 14.0: + if self.vs_ver < 14.0: return [] - include = os.path.join(self.si.UniversalCRTSdkDir, 'include') - return [os.path.join(include, '%sucrt' % self._ucrt_subdir)] + include = join(self.si.UniversalCRTSdkDir, 'include') + return [join(include, '%sucrt' % self._ucrt_subdir)] @property def _ucrt_subdir(self): """ - Microsoft Universal C Runtime SDK version subdir + Microsoft Universal C Runtime SDK version subdir. + + Return + ------ + str + subdir """ ucrtver = self.si.UniversalCRTSdkLastVersion return ('%s\\' % ucrtver) if ucrtver else '' @@ -1187,31 +1523,52 @@ class EnvironmentInfo: @property def FSharp(self): """ - Microsoft Visual F# + Microsoft Visual F#. + + Return + ------ + list of str + paths """ - if self.vc_ver < 11.0 and self.vc_ver > 12.0: + if 11.0 > self.vs_ver > 12.0: return [] - return self.si.FSharpInstallDir + return [self.si.FSharpInstallDir] @property def VCRuntimeRedist(self): """ - Microsoft Visual C++ runtime redistribuable dll - """ - arch_subdir = self.pi.target_dir(x64=True) - if self.vc_ver < 15: - redist_path = self.si.VCInstallDir - vcruntime = 'redist%s\\Microsoft.VC%d0.CRT\\vcruntime%d0.dll' - else: - redist_path = self.si.VCInstallDir.replace('\\Tools', '\\Redist') - vcruntime = 'onecore%s\\Microsoft.VC%d0.CRT\\vcruntime%d0.dll' - - # Visual Studio 2017 is still Visual C++ 14.0 - dll_ver = 14.0 if self.vc_ver == 15 else self.vc_ver + Microsoft Visual C++ runtime redistributable dll. - vcruntime = vcruntime % (arch_subdir, self.vc_ver, dll_ver) - return os.path.join(redist_path, vcruntime) + Return + ------ + str + path + """ + vcruntime = 'vcruntime%d0.dll' % self.vc_ver + arch_subdir = self.pi.target_dir(x64=True).strip('\\') + + # Installation prefixes candidates + prefixes = [] + tools_path = self.si.VCInstallDir + redist_path = dirname(tools_path.replace(r'\Tools', r'\Redist')) + if isdir(redist_path): + # Redist version may not be exactly the same as tools + redist_path = join(redist_path, listdir(redist_path)[-1]) + prefixes += [redist_path, join(redist_path, 'onecore')] + + prefixes += [join(tools_path, 'redist')] # VS14 legacy path + + # CRT directory + crt_dirs = ('Microsoft.VC%d.CRT' % (self.vc_ver * 10), + # Sometime store in directory with VS version instead of VC + 'Microsoft.VC%d.CRT' % (int(self.vs_ver) * 10)) + + # vcruntime path + for prefix, crt_dir in itertools.product(prefixes, crt_dirs): + path = join(prefix, arch_subdir, crt_dir, vcruntime) + if isfile(path): + return path def return_env(self, exists=True): """ @@ -1221,6 +1578,11 @@ class EnvironmentInfo: ---------- exists: bool It True, only return existing paths. + + Return + ------ + dict + environment """ env = dict( include=self._build_paths('include', @@ -1254,7 +1616,7 @@ class EnvironmentInfo: self.FSharp], exists), ) - if self.vc_ver >= 14 and os.path.isfile(self.VCRuntimeRedist): + if self.vs_ver >= 14 and isfile(self.VCRuntimeRedist): env['py_vcruntime_redist'] = self.VCRuntimeRedist return env @@ -1265,20 +1627,35 @@ class EnvironmentInfo: unique, extant, directories from those paths and from the environment variable. Raise an error if no paths are resolved. + + Parameters + ---------- + name: str + Environment variable name + spec_path_lists: list of str + Paths + exists: bool + It True, only return existing paths. + + Return + ------ + str + Pathsep-separated paths """ # flatten spec_path_lists spec_paths = itertools.chain.from_iterable(spec_path_lists) - env_paths = safe_env.get(name, '').split(os.pathsep) + env_paths = environ.get(name, '').split(pathsep) paths = itertools.chain(spec_paths, env_paths) - extant_paths = list(filter(os.path.isdir, paths)) if exists else paths + extant_paths = list(filter(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) + return pathsep.join(unique_paths) # from Python docs - def _unique_everseen(self, iterable, key=None): + @staticmethod + def _unique_everseen(iterable, key=None): """ List unique elements, preserving order. Remember all elements ever seen. -- cgit v1.2.1 From 7489ea4047661a7dbd46ff155abe45c548284676 Mon Sep 17 00:00:00 2001 From: Benoit Pierre Date: Mon, 28 Oct 2019 18:47:31 +0100 Subject: msvc: fix Python 2 support --- setuptools/msvc.py | 1 + 1 file changed, 1 insertion(+) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index ffa7053b..2ffe1c81 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -20,6 +20,7 @@ This may also support compilers shipped with compatible Visual Studio versions. """ import json +from io import open from os import listdir, pathsep from os.path import join, isfile, isdir, dirname import sys -- cgit v1.2.1 From 3d4d8b9dde61b87271861b8c7ebeb168ac4fa72b Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 19 Jan 2020 12:46:30 -0500 Subject: =?UTF-8?q?=F0=9F=91=B9=20Feed=20the=20hobgoblins=20(delint).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- setuptools/msvc.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 2ffe1c81..fa88c4e8 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -1225,7 +1225,7 @@ class EnvironmentInfo: arch_subdir = self.pi.target_dir(x64=True) lib = join(self.si.WindowsSdkDir, 'lib') libver = self._sdk_subdir - return [join(lib, '%sum%s' % (libver , arch_subdir))] + return [join(lib, '%sum%s' % (libver, arch_subdir))] @property def OSIncludes(self): @@ -1274,13 +1274,16 @@ class EnvironmentInfo: libpath += [ ref, join(self.si.WindowsSdkDir, 'UnionMetadata'), - join(ref, 'Windows.Foundation.UniversalApiContract', '1.0.0.0'), + join( + ref, 'Windows.Foundation.UniversalApiContract', '1.0.0.0'), join(ref, 'Windows.Foundation.FoundationContract', '1.0.0.0'), - join(ref,'Windows.Networking.Connectivity.WwanContract', - '1.0.0.0'), - join(self.si.WindowsSdkDir, 'ExtensionSDKs', 'Microsoft.VCLibs', - '%0.1f' % self.vs_ver, 'References', 'CommonConfiguration', - 'neutral'), + join( + ref, 'Windows.Networking.Connectivity.WwanContract', + '1.0.0.0'), + join( + self.si.WindowsSdkDir, 'ExtensionSDKs', 'Microsoft.VCLibs', + '%0.1f' % self.vs_ver, 'References', 'CommonConfiguration', + 'neutral'), ] return libpath -- cgit v1.2.1 From 5ce9e5f343ca14f9875106f37f16ad498b294183 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 19 Jan 2020 13:25:45 -0500 Subject: =?UTF-8?q?=F0=9F=91=B9=20Feed=20the=20hobgoblins=20(delint).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- setuptools/msvc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index fa88c4e8..c2cbd1e5 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -544,7 +544,7 @@ class SystemInfo: # Except for VS15+, VC version is aligned with VS version self.vs_ver = self.vc_ver = ( - vc_ver or self._find_latest_available_vs_ver()) + vc_ver or self._find_latest_available_vs_ver()) def _find_latest_available_vs_ver(self): """ -- cgit v1.2.1 From 65fa92095484eb14b994574650809fca7cae2d2e Mon Sep 17 00:00:00 2001 From: mayeut Date: Mon, 11 Nov 2019 12:00:16 +0100 Subject: Use CPython 3.8.0 mechanism to find msvc 14+ --- setuptools/msvc.py | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 151 insertions(+), 8 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index c2cbd1e5..213e39c9 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -26,6 +26,7 @@ from os.path import join, isfile, isdir, dirname import sys import platform import itertools +import subprocess import distutils.errors from setuptools.extern.packaging.version import LegacyVersion @@ -142,6 +143,154 @@ def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs): raise +def _msvc14_find_vc2015(): + """Python 3.8 "distutils/_msvccompiler.py" backport""" + try: + key = winreg.OpenKey( + winreg.HKEY_LOCAL_MACHINE, + r"Software\Microsoft\VisualStudio\SxS\VC7", + 0, + winreg.KEY_READ | winreg.KEY_WOW64_32KEY + ) + except OSError: + return None, None + + best_version = 0 + best_dir = None + with key: + for i in itertools.count(): + try: + v, vc_dir, vt = winreg.EnumValue(key, i) + except OSError: + break + if v and vt == winreg.REG_SZ and isdir(vc_dir): + try: + version = int(float(v)) + except (ValueError, TypeError): + continue + if version >= 14 and version > best_version: + best_version, best_dir = version, vc_dir + return best_version, best_dir + + +def _msvc14_find_vc2017(): + """Python 3.8 "distutils/_msvccompiler.py" backport + + Returns "15, path" based on the result of invoking vswhere.exe + If no install is found, returns "None, None" + + The version is returned to avoid unnecessarily changing the function + result. It may be ignored when the path is not None. + + If vswhere.exe is not available, by definition, VS 2017 is not + installed. + """ + root = environ.get("ProgramFiles(x86)") or environ.get("ProgramFiles") + if not root: + return None, None + + try: + path = subprocess.check_output([ + join(root, "Microsoft Visual Studio", "Installer", "vswhere.exe"), + "-latest", + "-prerelease", + "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", + "-property", "installationPath", + "-products", "*", + ]).decode(encoding="mbcs", errors="strict").strip() + except (subprocess.CalledProcessError, OSError, UnicodeDecodeError): + return None, None + + path = join(path, "VC", "Auxiliary", "Build") + if isdir(path): + return 15, path + + return None, None + + +PLAT_SPEC_TO_RUNTIME = { + 'x86': 'x86', + 'x86_amd64': 'x64', + 'x86_arm': 'arm', + 'x86_arm64': 'arm64' +} + + +def _msvc14_find_vcvarsall(plat_spec): + """Python 3.8 "distutils/_msvccompiler.py" backport""" + _, best_dir = _msvc14_find_vc2017() + vcruntime = None + + if plat_spec in PLAT_SPEC_TO_RUNTIME: + vcruntime_plat = PLAT_SPEC_TO_RUNTIME[plat_spec] + else: + vcruntime_plat = 'x64' if 'amd64' in plat_spec else 'x86' + + if best_dir: + vcredist = join(best_dir, "..", "..", "redist", "MSVC", "**", + vcruntime_plat, "Microsoft.VC14*.CRT", + "vcruntime140.dll") + try: + import glob + vcruntime = glob.glob(vcredist, recursive=True)[-1] + except (ImportError, OSError, LookupError): + vcruntime = None + + if not best_dir: + best_version, best_dir = _msvc14_find_vc2015() + if best_version: + vcruntime = join(best_dir, 'redist', vcruntime_plat, + "Microsoft.VC140.CRT", "vcruntime140.dll") + + if not best_dir: + return None, None + + vcvarsall = join(best_dir, "vcvarsall.bat") + if not isfile(vcvarsall): + return None, None + + if not vcruntime or not isfile(vcruntime): + vcruntime = None + + return vcvarsall, vcruntime + + +def _msvc14_get_vc_env(plat_spec): + """Python 3.8 "distutils/_msvccompiler.py" backport""" + if "DISTUTILS_USE_SDK" in environ: + return { + key.lower(): value + for key, value in environ.items() + } + + vcvarsall, vcruntime = _msvc14_find_vcvarsall(plat_spec) + if not vcvarsall: + raise distutils.errors.DistutilsPlatformError( + "Unable to find vcvarsall.bat" + ) + + try: + out = subprocess.check_output( + 'cmd /u /c "{}" {} && set'.format(vcvarsall, plat_spec), + stderr=subprocess.STDOUT, + ).decode('utf-16le', errors='replace') + except subprocess.CalledProcessError as exc: + raise distutils.errors.DistutilsPlatformError( + "Error executing {}".format(exc.cmd) + ) + + env = { + key.lower(): value + for key, _, value in + (line.partition('=') for line in out.splitlines()) + if key and value + } + + if vcruntime: + env['py_vcruntime_redist'] = vcruntime + return env + + def msvc14_get_vc_env(plat_spec): """ Patched "distutils._msvccompiler._get_vc_env" for support extra @@ -159,16 +308,10 @@ def msvc14_get_vc_env(plat_spec): dict environment """ - # 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 + # Always use backport from CPython 3.8 try: - return EnvironmentInfo(plat_spec, vc_min_ver=14.0).return_env() + return _msvc14_get_vc_env(plat_spec) except distutils.errors.DistutilsPlatformError as exc: _augment_exception(exc, 14.0) raise -- cgit v1.2.1 From a9eb9e73def8ca6c469e59f1b008746e368ad4c1 Mon Sep 17 00:00:00 2001 From: Ram Rachum Date: Tue, 16 Jun 2020 13:31:12 +0300 Subject: Fix exception causes all over the codebase --- setuptools/msvc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 213e39c9..72ba0d0c 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -277,7 +277,7 @@ def _msvc14_get_vc_env(plat_spec): except subprocess.CalledProcessError as exc: raise distutils.errors.DistutilsPlatformError( "Error executing {}".format(exc.cmd) - ) + ) from exc env = { key.lower(): value -- cgit v1.2.1 From 9013321c25606a5cd63271cd029c2539490b16d3 Mon Sep 17 00:00:00 2001 From: mattip Date: Mon, 29 Jun 2020 20:37:43 +0300 Subject: catch some resource leaks --- setuptools/msvc.py | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 213e39c9..09f8565e 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -643,8 +643,10 @@ class RegistryInfo: """ key_read = winreg.KEY_READ openkey = winreg.OpenKey + closekey = winreg.CloseKey ms = self.microsoft for hkey in self.HKEYS: + bkey = None try: bkey = openkey(hkey, ms(key), 0, key_read) except (OSError, IOError): @@ -659,6 +661,9 @@ class RegistryInfo: return winreg.QueryValueEx(bkey, name)[0] except (OSError, IOError): pass + finally: + if bkey: + closekey(bkey) class SystemInfo: @@ -726,21 +731,22 @@ class SystemInfo: bkey = winreg.OpenKey(hkey, ms(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 vs_vers: - vs_vers.append(ver) - except ValueError: - pass - for i in range(subkeys): - try: - ver = float(winreg.EnumKey(bkey, i)) - if ver not in vs_vers: - vs_vers.append(ver) - except ValueError: - pass + with bkey: + subkeys, values, _ = winreg.QueryInfoKey(bkey) + for i in range(values): + try: + ver = float(winreg.EnumValue(bkey, i)[0]) + if ver not in vs_vers: + vs_vers.append(ver) + except ValueError: + pass + for i in range(subkeys): + try: + ver = float(winreg.EnumKey(bkey, i)) + if ver not in vs_vers: + vs_vers.append(ver) + except ValueError: + pass return sorted(vs_vers) def find_programdata_vs_vers(self): -- cgit v1.2.1 From fb7ab81a3d080422687bad71f9ae9d36eeefbee2 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 16 Aug 2020 00:29:24 -0400 Subject: Remove Python 2 compatibility --- setuptools/msvc.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 72383eb8..24ea0863 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -30,12 +30,10 @@ import subprocess import distutils.errors from setuptools.extern.packaging.version import LegacyVersion -from setuptools.extern.six.moves import filterfalse - from .monkey import get_unpatched if platform.system() == 'Windows': - from setuptools.extern.six.moves import winreg + import winreg from os import environ else: # Mock winreg and environ so the module can be imported on this platform. @@ -1820,7 +1818,7 @@ class EnvironmentInfo: seen = set() seen_add = seen.add if key is None: - for element in filterfalse(seen.__contains__, iterable): + for element in itertools.filterfalse(seen.__contains__, iterable): seen_add(element) yield element else: -- cgit v1.2.1 From 023cf32a1adfb3b100800f613f5e0cf01dd76c2d Mon Sep 17 00:00:00 2001 From: Aren Cambre Date: Sun, 16 Aug 2020 12:29:14 -0500 Subject: pypa/setuptools#2302 --- setuptools/msvc.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 24ea0863..1ead72b4 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -338,7 +338,7 @@ def _augment_exception(exc, version, arch=''): 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.' + tmpl = 'Microsoft Visual C++ {version:0.1f} or greater is required.' message = tmpl.format(**locals()) msdownload = 'www.microsoft.com/download/details.aspx?id=%d' if version == 9.0: @@ -358,8 +358,9 @@ def _augment_exception(exc, version, arch=''): message += msdownload % 8279 elif version >= 14.0: # For VC++ 14.X Redirect user to latest Visual C++ Build Tools - message += (' Get it with "Build Tools for Visual Studio": ' - r'https://visualstudio.microsoft.com/downloads/') + message += (' Get it with "Microsoft C++ Build Tools": ' + r'https://visualstudio.microsoft.com' + r'/visual-cpp-build-tools/') exc.args = (message, ) -- cgit v1.2.1 From 699afd09f252025ff412c3be101d78576ce0fe60 Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Thu, 31 Dec 2020 18:03:15 +0100 Subject: Simplify `msvc.SystemInfo.find_reg_vs_vers` --- setuptools/msvc.py | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 1ead72b4..53d45e59 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -24,6 +24,7 @@ from io import open from os import listdir, pathsep from os.path import join, isfile, isdir, dirname import sys +import contextlib import platform import itertools import subprocess @@ -724,28 +725,23 @@ class SystemInfo: ms = self.ri.microsoft vckeys = (self.ri.vc, self.ri.vc_for_python, self.ri.vs) vs_vers = [] - for hkey in self.ri.HKEYS: - for key in vckeys: - try: - bkey = winreg.OpenKey(hkey, ms(key), 0, winreg.KEY_READ) - except (OSError, IOError): - continue - with bkey: - subkeys, values, _ = winreg.QueryInfoKey(bkey) - for i in range(values): - try: - ver = float(winreg.EnumValue(bkey, i)[0]) - if ver not in vs_vers: - vs_vers.append(ver) - except ValueError: - pass - for i in range(subkeys): - try: - ver = float(winreg.EnumKey(bkey, i)) - if ver not in vs_vers: - vs_vers.append(ver) - except ValueError: - pass + for hkey, key in itertools.product(self.ri.HKEYS, vckeys): + try: + bkey = winreg.OpenKey(hkey, ms(key), 0, winreg.KEY_READ) + except (OSError, IOError): + continue + with bkey: + subkeys, values, _ = winreg.QueryInfoKey(bkey) + for i in range(values): + with contextlib.suppress(ValueError): + ver = float(winreg.EnumValue(bkey, i)[0]) + if ver not in vs_vers: + vs_vers.append(ver) + for i in range(subkeys): + with contextlib.suppress(ValueError): + ver = float(winreg.EnumKey(bkey, i)) + if ver not in vs_vers: + vs_vers.append(ver) return sorted(vs_vers) def find_programdata_vs_vers(self): -- cgit v1.2.1 From fc891f5cf6d93ad533e2afb5e15a2952408ab358 Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Thu, 31 Dec 2020 13:08:18 +0100 Subject: Apply noqa C901 comments to overly complex code --- setuptools/msvc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 53d45e59..d5e0a952 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -921,8 +921,8 @@ class SystemInfo: """ return self._use_last_dir_name(join(self.WindowsSdkDir, 'lib')) - @property - def WindowsSdkDir(self): + @property # noqa: C901 + def WindowsSdkDir(self): # noqa: C901 # is too complex (12) # FIXME """ Microsoft Windows SDK directory. -- cgit v1.2.1 From eb270456a91449d1ae7a42419b4299ac523dc86d Mon Sep 17 00:00:00 2001 From: dofuuz Date: Thu, 29 Apr 2021 10:38:35 +0900 Subject: Add Visual Studio 2017 Express detection --- setuptools/msvc.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index d5e0a952..3ddbbc56 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -193,6 +193,9 @@ def _msvc14_find_vc2017(): join(root, "Microsoft Visual Studio", "Installer", "vswhere.exe"), "-latest", "-prerelease", + "-requiresAny", + "-requires", "Microsoft.VisualStudio.Component.VC.Tools.ARM", + "-requires", "Microsoft.VisualStudio.Component.VC.Tools.ARM64", "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", "-property", "installationPath", "-products", "*", -- cgit v1.2.1 From ea1ecf7ebcbbcec4c5bd05b4c106708b68652f01 Mon Sep 17 00:00:00 2001 From: dofuuz Date: Fri, 30 Apr 2021 13:37:29 +0900 Subject: Find VC Express 2017 explicitly, not ARM tools. --- setuptools/msvc.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 3ddbbc56..fd4b0781 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -194,9 +194,8 @@ def _msvc14_find_vc2017(): "-latest", "-prerelease", "-requiresAny", - "-requires", "Microsoft.VisualStudio.Component.VC.Tools.ARM", - "-requires", "Microsoft.VisualStudio.Component.VC.Tools.ARM64", "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", + "-requires", "Microsoft.VisualStudio.Workload.WDExpress", "-property", "installationPath", "-products", "*", ]).decode(encoding="mbcs", errors="strict").strip() -- cgit v1.2.1 From 9c2cf25a13bf33a3fd706c97064c0d2fa22be179 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 22 May 2021 19:19:05 -0400 Subject: Use unique_everseen from more_itertools. --- setuptools/msvc.py | 27 ++------------------------- 1 file changed, 2 insertions(+), 25 deletions(-) (limited to 'setuptools/msvc.py') diff --git a/setuptools/msvc.py b/setuptools/msvc.py index fd4b0781..281ea1c2 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -30,6 +30,7 @@ import itertools import subprocess import distutils.errors from setuptools.extern.packaging.version import LegacyVersion +from setuptools.extern.more_itertools import unique_everseen from .monkey import get_unpatched @@ -1800,29 +1801,5 @@ class EnvironmentInfo: if not extant_paths: msg = "%s environment variable is empty" % name.upper() raise distutils.errors.DistutilsPlatformError(msg) - unique_paths = self._unique_everseen(extant_paths) + unique_paths = unique_everseen(extant_paths) return pathsep.join(unique_paths) - - # from Python docs - @staticmethod - def _unique_everseen(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 itertools.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 -- cgit v1.2.1