Commit 72db3cf5 authored by JGoutin's avatar JGoutin

* Move non registry parts from RegistryInfo to SystemInfo.

* Rename many variable to use the same names as in MSVC .bat files. This really help to compare the Python script with original sources.
* Split compute_env to EnvironmentInfo class.
* Continue to add support for MSVC14.
* Some more little fixes.
parent 75282e55
...@@ -4,6 +4,7 @@ This module improve support for Microsoft Visual C++ compilers. (Windows Only) ...@@ -4,6 +4,7 @@ This module improve support for Microsoft Visual C++ compilers. (Windows Only)
import os import os
import itertools import itertools
import distutils.errors import distutils.errors
import winreg
try: try:
# Distutil file for MSVC++ 9.0 and upper # Distutil file for MSVC++ 9.0 and upper
...@@ -30,16 +31,16 @@ def patch_for_specialized_compiler(): ...@@ -30,16 +31,16 @@ def patch_for_specialized_compiler():
Known supported compilers: Known supported compilers:
-------------------------- --------------------------
Microsoft Visual C++ 9.0: Microsoft Visual C++ 9.0:
Microsoft Visual C++ Compiler for Python 2.7 (x86, amd64); Microsoft Visual C++ Compiler for Python 2.7 (x86, amd64);
Microsoft Windows SDK 7.0 (x86, x64, ia64); Microsoft Windows SDK 7.0 (x86, x64, ia64);
Microsoft Windows SDK 6.1 (x86, x64, ia64) Microsoft Windows SDK 6.1 (x86, x64, ia64)
Microsoft Visual C++ 10.0: Microsoft Visual C++ 10.0:
Microsoft Windows SDK 7.1 (x86, x64, ia64) Microsoft Windows SDK 7.1 (x86, x64, ia64)
Microsoft Visual C++ 14.0: Microsoft Visual C++ 14.0:
Microsoft Visual C++ Build Tools 2015 (x86, x64, arm) Microsoft Visual C++ Build Tools 2015 (x86, x64, arm)
""" """
if 'distutils' not in globals(): if 'distutils' not in globals():
# The module isn't available to be patched # The module isn't available to be patched
...@@ -74,8 +75,8 @@ def msvc9_find_vcvarsall(version): ...@@ -74,8 +75,8 @@ def msvc9_find_vcvarsall(version):
Known supported compilers Known supported compilers
------------------------- -------------------------
Microsoft Visual C++ 9.0: Microsoft Visual C++ 9.0:
Microsoft Visual C++ Compiler for Python 2.7 (x86, amd64) Microsoft Visual C++ Compiler for Python 2.7 (x86, amd64)
Parameters Parameters
---------- ----------
...@@ -115,13 +116,13 @@ def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs): ...@@ -115,13 +116,13 @@ def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs):
Known supported compilers Known supported compilers
------------------------- -------------------------
Microsoft Visual C++ 9.0: Microsoft Visual C++ 9.0:
Microsoft Visual C++ Compiler for Python 2.7 (x86, amd64); Microsoft Visual C++ Compiler for Python 2.7 (x86, amd64);
Microsoft Windows SDK 7.0 (x86, x64, ia64); Microsoft Windows SDK 7.0 (x86, x64, ia64);
Microsoft Windows SDK 6.1 (x86, x64, ia64) Microsoft Windows SDK 6.1 (x86, x64, ia64)
Microsoft Visual C++ 10.0: Microsoft Visual C++ 10.0:
Microsoft Windows SDK 7.1 (x86, x64, ia64) Microsoft Windows SDK 7.1 (x86, x64, ia64)
Parameters Parameters
---------- ----------
...@@ -138,15 +139,15 @@ def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs): ...@@ -138,15 +139,15 @@ def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs):
try: try:
return unpatched['msvc9_query_vcvarsall'](ver, arch, *args, **kwargs) return unpatched['msvc9_query_vcvarsall'](ver, arch, *args, **kwargs)
except distutils.errors.DistutilsPlatformError: except distutils.errors.DistutilsPlatformError:
# Error if Vcvarsall.bat is missing # Pass error if Vcvarsall.bat is missing
pass pass
except ValueError: except ValueError:
# Error if environment not set after executing vcvarsall.bat # Pass error if environment not set after executing vcvarsall.bat
pass pass
# If vcvarsall.bat fail, try to set environment directly # If error, try to set environment directly
try: try:
return _compute_env(ver, arch) return EnvironmentInfo(arch, ver).return_env()
except distutils.errors.DistutilsPlatformError as exc: except distutils.errors.DistutilsPlatformError as exc:
_augment_exception(exc, ver, arch) _augment_exception(exc, ver, arch)
raise raise
...@@ -159,8 +160,8 @@ def msvc14_get_vc_env(plat_spec): ...@@ -159,8 +160,8 @@ def msvc14_get_vc_env(plat_spec):
Known supported compilers Known supported compilers
------------------------- -------------------------
Microsoft Visual C++ 14.0: Microsoft Visual C++ 14.0:
Microsoft Visual C++ Build Tools 2015 (x86, x64, arm) Microsoft Visual C++ Build Tools 2015 (x86, x64, arm)
Parameters Parameters
---------- ----------
...@@ -171,21 +172,22 @@ def msvc14_get_vc_env(plat_spec): ...@@ -171,21 +172,22 @@ def msvc14_get_vc_env(plat_spec):
------ ------
environment: dict environment: dict
""" """
# Try to get environement from vcvarsall.bat (Classical way)
try: try:
return unpatched['msv14_get_vc_env'](plat_spec) return unpatched['msv14_get_vc_env'](plat_spec)
except distutils.errors.DistutilsPlatformError: except distutils.errors.DistutilsPlatformError:
# Error if Vcvarsall.bat is missing # Pass error Vcvarsall.bat is missing
pass pass
# If vcvarsall.bat fail, try to set environment directly # If error, try to set environment directly
try: try:
return _compute_env(version, plat_spec) return EnvironmentInfo(plat_spec, vcvermin=14.0).return_env()
except distutils.errors.DistutilsPlatformError as exc: except distutils.errors.DistutilsPlatformError as exc:
_augment_exception(exc, version, plat_spec) _augment_exception(exc, 14.0)
raise raise
def _augment_exception(exc, version, arch): def _augment_exception(exc, version, arch=''):
""" """
Add details to the exception message to help guide the user Add details to the exception message to help guide the user
as to what action will resolve it. as to what action will resolve it.
...@@ -193,32 +195,33 @@ def _augment_exception(exc, version, arch): ...@@ -193,32 +195,33 @@ def _augment_exception(exc, version, arch):
# Error if MSVC++ directory not found or environment not set # Error if MSVC++ directory not found or environment not set
message = exc.args[0] message = exc.args[0]
if "vcvarsall.bat" in message: if "vcvarsall" in message.lower() or "visual c" in message.lower():
# Special error message if MSVC++ not installed # Special error message if MSVC++ not installed
message = 'Microsoft Visual C++ %0.1f is required (%s).' %\ message = 'Microsoft Visual C++ %0.1f is required (%s).' %\
(version, message) (version, message)
if int(version) == 9: msdownload = r'www.microsoft.com/download/details.aspx?id=%d'
if version == 9.0:
if arch.lower().find('ia64') > -1: if arch.lower().find('ia64') > -1:
# For VC++ 9.0, if IA64 support is needed, redirect user # For VC++ 9.0, if IA64 support is needed, redirect user
# to Windows SDK 7.0 # to Windows SDK 7.0
message += ' Get it with "Microsoft Windows SDK 7.0": ' message += ' Get it with "Microsoft Windows SDK 7.0": '
message += r'www.microsoft.com/download/details.aspx?id=3138' message += msdownload % 3138
else: else:
# For VC++ 9.0 redirect user to Vc++ for Python 2.7 : # For VC++ 9.0 redirect user to Vc++ for Python 2.7 :
# This redirection link is maintained by Microsoft. # This redirection link is maintained by Microsoft.
# Contact vspython@microsoft.com if it needs updating. # Contact vspython@microsoft.com if it needs updating.
message += r' Get it from http://aka.ms/vcpython27' message += r' Get it from http://aka.ms/vcpython27'
elif int(version) == 10: elif version == 10.0:
# For VC++ 10.0 Redirect user to Windows SDK 7.1 # For VC++ 10.0 Redirect user to Windows SDK 7.1
message += ' Get it with "Microsoft Windows SDK 7.1": ' message += ' Get it with "Microsoft Windows SDK 7.1": '
message += r'www.microsoft.com/download/details.aspx?id=8279' message += msdownload % 8279
exc.args[0] = message exc.args[0] = message
class PlatformInfo: class PlatformInfo:
""" """
Find architecture informations and system paths. Current and Target Architectures informations.
Parameters Parameters
---------- ----------
...@@ -226,9 +229,6 @@ class PlatformInfo: ...@@ -226,9 +229,6 @@ class PlatformInfo:
Target architecture. Target architecture.
""" """
current_cpu = os.environ['processor_architecture'].lower() current_cpu = os.environ['processor_architecture'].lower()
win_dir = os.environ['WinDir']
program_files = os.environ['ProgramFiles']
program_files_x86 = os.environ.get('ProgramFiles(x86)', program_files)
def __init__(self, arch): def __init__(self, arch):
self.arch = arch.lower() self.arch = arch.lower()
...@@ -241,9 +241,9 @@ class PlatformInfo: ...@@ -241,9 +241,9 @@ class PlatformInfo:
return self.target_cpu == 'x86' return self.target_cpu == 'x86'
def current_is_x86(self): def current_is_x86(self):
return self.current_cpu != 'x86' return self.current_cpu == 'x86'
def ccpu_dir(self, hidex86=False, x64=False): def current_dir(self, hidex86=False, x64=False):
""" """
Current platform specific subfolder. Current platform specific subfolder.
...@@ -256,7 +256,8 @@ class PlatformInfo: ...@@ -256,7 +256,8 @@ class PlatformInfo:
Return Return
------ ------
subfolder: str (starting with'\') subfolder: str
"\target"
""" """
return ( return (
'' if (self.current_cpu == 'x86' and hidex86) else '' if (self.current_cpu == 'x86' and hidex86) else
...@@ -264,7 +265,7 @@ class PlatformInfo: ...@@ -264,7 +265,7 @@ class PlatformInfo:
r'\%s' % self.current_cpu r'\%s' % self.current_cpu
) )
def tcpu_dir(self, hidex86=False, x64=False): def target_dir(self, hidex86=False, x64=False):
""" """
Target platform specific subfolder. Target platform specific subfolder.
...@@ -277,7 +278,8 @@ class PlatformInfo: ...@@ -277,7 +278,8 @@ class PlatformInfo:
Return Return
------ ------
subfolder: str (starting with'\') subfolder: str
"\current"
""" """
return ( return (
'' if (self.target_cpu == 'x86' and hidex86) else '' if (self.target_cpu == 'x86' and hidex86) else
...@@ -285,9 +287,9 @@ class PlatformInfo: ...@@ -285,9 +287,9 @@ class PlatformInfo:
r'\%s' % self.target_cpu r'\%s' % self.target_cpu
) )
def tools_extra(self, forcex86=False): def cross_dir(self, forcex86=False):
""" """
Platform specific subfolder for Visual C++ Tools. Cross platform specific subfolder.
Parameters Parameters
---------- ----------
...@@ -297,9 +299,11 @@ class PlatformInfo: ...@@ -297,9 +299,11 @@ class PlatformInfo:
Return Return
------ ------
subfolder: str (starting with'\') subfolder: str
"\current" if target architecture is current architecture,
"\current_target" if not.
""" """
path = self.tcpu_dir(True) path = self.target_dir(True)
if self.target_cpu != self.current_cpu: if self.target_cpu != self.current_cpu:
current = 'x86' if forcex86 else self.current_cpu current = 'x86' if forcex86 else self.current_cpu
path = path.replace('\\', '\\%s_' % current) path = path.replace('\\', '\\%s_' % current)
...@@ -308,24 +312,25 @@ class PlatformInfo: ...@@ -308,24 +312,25 @@ class PlatformInfo:
class RegistryInfo: class RegistryInfo:
""" """
Find Microsoft Visual C++ compiler related paths using registry or Microsoft Visual Studio related registry informations.
default paths.
Parameters Parameters
---------- ----------
platform_info: platform_info platform_info: PlatformInfo
"platform_info" instance. "PlatformInfo" instance.
version: float
Required Microsoft Visual C++ version.
""" """
def __init__(self, platform_info, version): 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 self.pi = platform_info
self.version = version
@property @property
def microsoft(self): def microsoft(self):
""" """
Microsoft registry path. Microsoft software registry key.
""" """
return os.path.join( return os.path.join(
'Software', 'Software',
...@@ -336,292 +341,530 @@ class RegistryInfo: ...@@ -336,292 +341,530 @@ class RegistryInfo:
@property @property
def sxs(self): def sxs(self):
""" """
Visual Studio SxS registry path. Microsoft Visual Studio SxS registry key.
""" """
return os.path.join(self.microsoft, r'VisualStudio\SxS') return os.path.join(self.microsoft, r'VisualStudio\SxS')
@property @property
def vc(self): def vc(self):
""" """
Visual C++ registry path. Microsoft Visual C++ registry key.
""" """
return os.path.join(self.sxs, 'VC7') return os.path.join(self.sxs, 'VC7')
@property @property
def vs(self): def vs(self):
""" """
Visual Studio registry path. Microsoft Visual Studio registry key.
""" """
return os.path.join(self.sxs, 'VS7') return os.path.join(self.sxs, 'VS7')
@property @property
def vc_for_python(self): def vc_for_python(self):
""" """
Visual C++ for Python. Microsoft Visual C++ for Python registry key.
""" """
path = r'DevDiv\VCForPython\%0.1f' % self.version path = r'DevDiv\VCForPython'
return os.path.join(self.microsoft, path) return os.path.join(self.microsoft, path)
@property @property
def windows_sdk(self): def windows_sdk(self):
""" """
Windows/Platform SDK registry path. Microsoft Windows/Platform SDK registry key.
""" """
return os.path.join(self.microsoft, r'Microsoft SDKs\Windows') return os.path.join(self.microsoft, r'Microsoft SDKs\Windows')
def find_visual_studio(self): 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.
vcver: float
Required Microsoft Visual C++ version.
"""
WinDir = os.environ['WinDir']
ProgramFiles = os.environ['ProgramFiles']
ProgramFilesx86 = os.environ.get('ProgramFiles(x86)', ProgramFiles)
def __init__(self, registry_info, vcver=None):
self.ri = registry_info
if vcver:
self.vcver = vcver
else:
try:
self.vcver = self.find_availables_vcver()[-1]
except IndexError:
err = 'No Microsoft Visual C++ version found'
raise distutils.errors.DistutilsPlatformError(err)
def find_availables_vcver(self):
"""
Find all availables Microsoft Visual C++ versions.
"""
vckeys = (self.ri.vc, self.ri.vc_for_python)
vsvers = []
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 vsvers:
vsvers.append(ver)
except ValueError:
pass
for i in range(subkeys):
try:
ver = float(winreg.EnumKey(bkey, i))
if ver not in vsvers:
vsvers.append(ver)
except ValueError:
pass
return sorted(vsvers)
@property
def VSInstallDir(self):
""" """
Find Microsoft Visual Studio directory. Microsoft Visual Studio directory.
""" """
# Default path # Default path
name = 'Microsoft Visual Studio %0.1f' % self.version name = 'Microsoft Visual Studio %0.1f' % self.vcver
default = os.path.join(self.pi.program_files_x86, name) default = os.path.join(self.ProgramFilesx86, name)
# Try to get path from registry, if fail use default path # Try to get path from registry, if fail use default path
return self._lookup(self.vs, '%0.1f' % self.version) or default return self.ri.lookup(self.ri.vs, '%0.1f' % self.vcver) or default
def find_visual_c(self): @property
def VCInstallDir(self):
""" """
Find Microsoft Visual C++ directory. Microsoft Visual C++ directory.
""" """
# Default path # Default path
default = r'Microsoft Visual Studio %0.1f\VC' % self.version default = r'Microsoft Visual Studio %0.1f\VC' % self.vcver
guess_vc = os.path.join(self.pi.program_files_x86, default) guess_vc = os.path.join(self.ProgramFilesx86, default)
# Try to get "VC++ for Python" path from registry as default path # Try to get "VC++ for Python" path from registry as default path
python_vc = self._lookup(self.vc_for_python, 'installdir') path = os.path.join(self.ri.vc_for_python, '%0.1f' % self.vcver)
python_vc = self.ri.lookup(path, 'installdir')
default_vc = os.path.join(python_vc, 'VC') if python_vc else guess_vc 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 # Try to get path from registry, if fail use default path
result = self._lookup(self.vc, '%0.1f' % self.version) or default_vc result = self.ri.lookup(self.ri.vc, '%0.1f' % self.vcver) or default_vc
if not os.path.isdir(result): if not os.path.isdir(result):
msg = 'vcvarsall.bat and Visual C++ directory not found' msg = 'Microsoft Visual C++ directory not found'
raise distutils.errors.DistutilsPlatformError(msg) raise distutils.errors.DistutilsPlatformError(msg)
return result return result
def find_windows_sdk(self): @property
def WindowsSdkDir(self):
""" """
Find Microsoft Windows SDK directory. Microsoft Windows SDK directory.
""" """
WindowsSdkDir = '' sdkdir = ''
if self.version == 9.0: if self.vcver == 9.0:
WindowsSdkVer = ('7.0', '6.1', '6.0a') sdkver = ('7.0', '6.1', '6.0a')
elif self.version == 10.0: elif self.vcver == 10.0:
WindowsSdkVer = ('7.1', '7.0a') sdkver = ('7.1', '7.0a')
elif self.vcver == 14.0:
sdkver = ('10.0', '8.1', '8.1a')
else: else:
WindowsSdkVer = () sdkver = ()
for ver in WindowsSdkVer: for ver in sdkver:
# Try to get it from registry # Try to get it from registry
loc = os.path.join(self.windows_sdk, 'v%s' % ver) loc = os.path.join(self.ri.windows_sdk, 'v%s' % ver)
WindowsSdkDir = self._lookup(loc, 'installationfolder') sdkdir = self.ri.lookup(loc, 'installationfolder')
if WindowsSdkDir: if sdkdir:
break break
if not WindowsSdkDir or not os.path.isdir(WindowsSdkDir): if not sdkdir or not os.path.isdir(sdkdir):
# Try to get "VC++ for Python" version from registry # Try to get "VC++ for Python" version from registry
install_base = self._lookup(self.vc_for_python, 'installdir') path = os.path.join(self.ri.vc_for_python, '%0.1f' % self.vcver)
install_base = self.ri.lookup(path, 'installdir')
if install_base: if install_base:
WindowsSdkDir = os.path.join(install_base, 'WinSDK') sdkdir = os.path.join(install_base, 'WinSDK')
if not WindowsSdkDir or not os.path.isdir(WindowsSdkDir): if not sdkdir or not os.path.isdir(sdkdir):
# If fail, use default path # If fail, use default new path
for ver in WindowsSdkVer: for ver in sdkver:
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 sdkver:
path = r'Microsoft SDKs\Windows\v%s' % ver path = r'Microsoft SDKs\Windows\v%s' % ver
d = os.path.join(self.pi.program_files, path) d = os.path.join(self.ProgramFiles, path)
if os.path.isdir(d): if os.path.isdir(d):
WindowsSdkDir = d sdkdir = d
if not WindowsSdkDir: if not sdkdir:
# If fail, use Platform SDK # If fail, use Platform SDK
WindowsSdkDir = os.path.join(self.find_visual_c(), 'PlatformSDK') sdkdir = os.path.join(self.VCInstallDir, 'PlatformSDK')
return WindowsSdkDir return sdkdir
def find_dot_net_versions(self):
"""
Find Microsoft .NET Framework Versions.
"""
if self.version == 10.0:
v4 = self._lookup(self.vc, 'frameworkver32') or ''
if v4.lower()[:2] != 'v4':
v4 = None
# default to last v4 version
v4 = v4 or 'v4.0.30319'
FrameworkVer = (v4, 'v3.5')
elif self.version == 9.0:
FrameworkVer = ('v3.5', 'v2.0.50727')
elif self.version == 8.0:
FrameworkVer = ('v3.0', 'v2.0.50727')
return FrameworkVer
def find_dot_net_32(self): @property
def FrameworkDir32(self):
""" """
Find Microsoft .NET Framework 32bit directory. Microsoft .NET Framework 32bit directory.
""" """
# Default path # Default path
guess_fw = os.path.join(self.pi.win_dir, r'Microsoft.NET\Framework') guess_fw = os.path.join(self.WinDir, r'Microsoft.NET\Framework')
# Try to get path from registry, if fail use default path # Try to get path from registry, if fail use default path
return self._lookup(self.vc, 'frameworkdir32') or guess_fw return self.ri.lookup(self.ri.vc, 'frameworkdir32') or guess_fw
def find_dot_net_64(self): @property
def FrameworkDir64(self):
""" """
Find Microsoft .NET Framework 64bit directory. Microsoft .NET Framework 64bit directory.
""" """
# Default path # Default path
guess_fw = os.path.join(self.pi.win_dir, r'Microsoft.NET\Framework64') guess_fw = os.path.join(self.WinDir, r'Microsoft.NET\Framework64')
# Try to get path from registry, if fail use default path # Try to get path from registry, if fail use default path
return self._lookup(self.vc, 'frameworkdir64') or guess_fw return self.ri.lookup(self.ri.vc, 'frameworkdir64') or guess_fw
def _lookup(self, base, key): @property
try: def FrameworkVersion32(self):
return msvc9compiler.Reg.get_value(base, key) """
except KeyError: Microsoft .NET Framework 32bit versions.
pass """
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.
def _compute_env(version, arch): 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.vcver >= 14.0:
frameworkver = (ver, 'v4.0')
elif self.vcver == 10.0:
if ver.lower()[:2] != 'v4':
ver = ''
ver = ver or 'v4.0.30319'
frameworkver = (ver, 'v3.5')
elif self.vcver == 9.0:
frameworkver = ('v3.5', 'v2.0.50727')
elif self.vcver == 8.0:
frameworkver = ('v3.0', 'v2.0.50727')
return frameworkver
class EnvironmentInfo:
""" """
Return environment variables for specified Microsoft Visual C++ version Return environment variables for specified Microsoft Visual C++ version
and platform. and platform : Lib, Include, Path and libpath.
Microsoft Visual C++ known compatibles versions This function is compatible with Microsoft Visual C++ 9.0 to 14.0.
-----------------------------------------------
9.0, 10.0, 14.0 Parameters
""" ----------
pi = PlatformInfo(arch) arch: str
reg = RegistryInfo(pi, version) Target architecture.
vcver: float
# Set Microsoft Visual Studio Tools Required Microsoft Visual C++ version. If not set, autodetect the last
paths = [r'Common7\IDE', r'Common7\Tools'] version.
if version >= 14.0: vcvermin: float
paths.append(r'Common7\IDE\CommonExtensions\Microsoft\TestWindow') Minimum Microsoft Visual C++ version.
paths.append(r'Team Tools\Performance Tools')
paths.append(r'Team Tools\Performance Tools' + pi.ccpu_dir(True, True))
VSTools = [os.path.join(reg.find_visual_studio(), path) for path in paths]
# Set Microsoft Visual C++ & Microsoft Foundation Class Includes
VCIncludes = [os.path.join(reg.find_visual_c(), 'Include'),
os.path.join(reg.find_visual_c(), 'ATLMFC\Include')]
# Set Microsoft Visual C++ & Microsoft Foundation Class Libraries
paths = ['Lib' + pi.tcpu_dir(True), r'ATLMFC\Lib' + pi.tcpu_dir(True)]
if version >= 14.0:
paths.append(r'Lib\store' + pi.tcpu_dir(True))
VCLibraries = [os.path.join(reg.find_visual_c(), path) for path in paths]
# Set Microsoft Visual C++ store references Libraries
if version >= 14.0:
path = r'Lib\store\references'
VCStoreRefs = [os.path.join(reg.find_visual_c(), path)]
else:
VCStoreRefs = []
# Set Microsoft Visual C++ Tools
path = 'Bin' + pi.tools_extra(False if version >= 14.0 else True)
VCTools = [
os.path.join(reg.find_visual_c(), 'VCPackages'),
os.path.join(reg.find_visual_c(), path),
]
if pi.tools_extra() and version >= 14.0:
path = 'Bin' + pi.ccpu_dir(True)
VCTools.append(os.path.join(reg.find_visual_c(), path))
else:
VCTools.append(os.path.join(reg.find_visual_c(), 'Bin'))
# Set Microsoft Windows SDK Libraries
path = 'Lib' + pi.tcpu_dir(True, True)
OSLibraries = [os.path.join(reg.find_windows_sdk(), path)]
# Set Microsoft Windows SDK Include
OSIncludes = [
os.path.join(reg.find_windows_sdk(), 'Include'),
os.path.join(reg.find_windows_sdk(), r'Include\gl'),
]
# Set Microsoft Windows SDK Tools
SdkTools = [os.path.join(reg.find_windows_sdk(), 'Bin')]
if not pi.target_is_x86():
path = 'Bin' + pi.tcpu_dir(True, True)
SdkTools.append(os.path.join(reg.find_windows_sdk(), path))
if version == 10.0:
path = r'Bin\NETFX 4.0 Tools' + pi.tcpu_dir(True, True)
SdkTools.append(os.path.join(reg.find_windows_sdk(), path))
# Set Microsoft Windows SDK Setup
SdkSetup = [os.path.join(reg.find_windows_sdk(), 'Setup')]
# Set Microsoft .NET Framework Tools
roots = [reg.find_dot_net_32()]
include_64_framework = not pi.target_is_x86() and not pi.current_is_x86()
roots += [reg.find_dot_net_64()] if include_64_framework else []
FxTools = [
os.path.join(root, ver)
for root, ver in itertools.product(roots, reg.find_dot_net_versions())
]
# Set Microsoft Visual Studio Team System Database
VsTDb = [os.path.join(reg.find_visual_studio(), r'VSTSDB\Deploy')]
# Set Microsoft Build Engine
path = r'\MSBuild\%0.1f\bin%s' % (version, pi.ccpu_dir(True))
MSBuild = [
os.path.join(pi.program_files_x86, path),
os.path.join(pi.program_files, path)
]
# Set Microsoft HTML Help Workshop
path = 'HTML Help Workshop'
HTMLWork = [
os.path.join(pi.program_files_x86, path),
os.path.join(pi.program_files, path)
]
# Return environment
return dict(
include=_build_paths('include', [VCIncludes, OSIncludes]),
lib=_build_paths('lib', [VCLibraries, OSLibraries, FxTools]),
libpath=_build_paths('libpath', [VCLibraries, FxTools, VCStoreRefs]),
path=_build_paths('path', [VCTools, VSTools, VsTDb, SdkTools, SdkSetup,
FxTools, MSBuild, HTMLWork]),
)
def _build_paths(name, spec_path_lists):
"""
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 def __init__(self, arch, vcver=None, vcvermin=None):
spec_paths = itertools.chain.from_iterable(spec_path_lists) self.pi = PlatformInfo(arch)
env_paths = os.environ.get(name, '').split(os.pathsep) self.ri = RegistryInfo(self.pi)
paths = itertools.chain(spec_paths, env_paths) self.si = SystemInfo(self.ri, vcver)
extant_paths = list(filter(os.path.isdir, paths))
if not extant_paths: if self.vcver < vcvermin:
msg = "%s environment variable is empty" % name.upper() err = 'No suitable Microsoft Visual C++ version found'
raise distutils.errors.DistutilsPlatformError(msg) raise distutils.errors.DistutilsPlatformError(err)
unique_paths = _unique_everseen(extant_paths)
return os.pathsep.join(unique_paths) @property
def vcver(self):
"""
# from Python docs Microsoft Visual C++ version.
def _unique_everseen(iterable, key=None): """
"List unique elements, preserving order. Remember all elements ever seen." return self.si.vcver
# unique_everseen('AAAABBBCCDAABBB') --> A B C D
# unique_everseen('ABBCcAD', str.lower) --> A B C D @property
seen = set() def VSTools(self):
seen_add = seen.add """
filterfalse = six.moves.filterfalse Microsoft Visual Studio Tools
if key is None: """
for element in filterfalse(seen.__contains__, iterable): paths = [r'Common7\IDE', r'Common7\Tools']
seen_add(element) if self.vcver >= 14.0:
yield element arch_subdir = self.pi.current_dir(hidex86=True, x64=True)
else: paths += [r'Common7\IDE\CommonExtensions\Microsoft\TestWindow']
for element in iterable: paths += [r'Team Tools\Performance Tools']
k = key(element) paths += [r'Team Tools\Performance Tools%s' % arch_subdir]
if k not in seen: return [os.path.join(self.si.VSInstallDir, path) for path in paths]
seen_add(k)
@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.vcver >= 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
"""
path = os.path.join(self.si.VCInstallDir, r'Lib\store\references')
return [path] if self.vcver >= 14.0 else []
@property
def VCTools(self):
"""
Microsoft Visual C++ Tools
"""
forcex86 = True if self.vcver <= 10.0 else False
arch_subdir = self.pi.cross_dir(forcex86)
tools = [
os.path.join(self.si.VCInstallDir, 'VCPackages'),
os.path.join(self.si.VCInstallDir, 'Bin%s' % arch_subdir),
]
if self.pi.cross_dir() and self.vcver >= 14.0:
path = 'Bin%s' % self.pi.current_dir(hidex86=True)
tools += [os.path.join(self.si.VCInstallDir, path)]
else:
tools += [os.path.join(self.si.VCInstallDir, 'Bin')]
return tools
@property
def OSLibraries(self):
"""
Microsoft Windows SDK Libraries
"""
arch_subdir = self.pi.target_dir(hidex86=True, x64=True)
return [os.path.join(self.si.WindowsSdkDir, 'Bin%s' % arch_subdir)]
@property
def OSIncludes(self):
"""
Microsoft Windows SDK Include
"""
return [
os.path.join(self.si.WindowsSdkDir, 'Include'),
os.path.join(self.si.WindowsSdkDir, r'Include\gl'),
]
@property
def SdkTools(self):
"""
Microsoft Windows SDK Tools
"""
if self.vcver <= 10:
arch_subdir = self.pi.target_dir(hidex86=True, x64=True)
else:
arch_subdir = self.pi.target_dir(x64=True)
tools = [os.path.join(self.si.WindowsSdkDir, 'Bin')]
if not self.pi.target_is_x86():
path = 'Bin%s' % arch_subdir
tools += [os.path.join(self.si.WindowsSdkDir, path)]
if self.vcver == 10.0:
path = r'Bin\NETFX 4.0 Tools%s' % arch_subdir
tools += [os.path.join(self.si.WindowsSdkDir, path)]
return tools
@property
def SdkSetup(self):
"""
Microsoft Windows SDK Setup
"""
return [os.path.join(self.si.WindowsSdkDir, 'Setup')]
@property
def FxTools(self):
"""
Microsoft .NET Framework Tools
"""
pi = self.pi
si = self.si
if self.vcver <= 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 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
"""
arch_subdir = self.pi.current_dir(hidex86=True)
path = r'\MSBuild\%0.1f\bin%s' % (self.vcver, arch_subdir)
return [
os.path.join(self.si.ProgramFilesx86, path),
os.path.join(self.si.ProgramFiles, path)
]
@property
def HTMLWs(self):
"""
Microsoft HTML Help Workshop
"""
return [
os.path.join(self.si.ProgramFilesx86, 'HTML Help Workshop'),
os.path.join(self.si.ProgramFiles, 'HTML Help Workshop')
]
@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.vcver, self.vcver)
return os.path.join(self.si.VCInstallDir, vcruntime)
def return_env(self):
"""
Return environment dict.
"""
env = dict(
include=self._build_paths('include',
[self.VCIncludes,
self.OSIncludes]),
lib=self._build_paths('lib',
[self.VCLibraries,
self.OSLibraries,
self.FxTools]),
libpath=self._build_paths('libpath',
[self.VCLibraries,
self.FxTools,
self.VCStoreRefs]),
path=self._build_paths('path',
[self.VCTools,
self.VSTools,
self.VsTDb,
self.SdkTools,
self.SdkSetup,
self.FxTools,
self.MSBuild,
self.HTMLWs]),
)
if self.vcver >= 14 and os.path.isfile(self.VCRuntimeRedist):
env['py_vcruntime_redist'] = self.VCRuntimeRedist
return env
def _build_paths(self, name, spec_path_lists):
"""
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 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
filterfalse = six.moves.filterfalse
if key is None:
for element in filterfalse(seen.__contains__, iterable):
seen_add(element)
yield element yield element
else:
for element in iterable:
k = key(element)
if k not in seen:
seen_add(k)
yield element
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment