X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/1e4a197e4c60e461b8068b0619692ea083e30b8b..fc576e8d26ac732652485a08368ff9276a48525a:/wxPython/distutils/msvccompiler.py diff --git a/wxPython/distutils/msvccompiler.py b/wxPython/distutils/msvccompiler.py index e07a6d5a0c..5f3d8de872 100644 --- a/wxPython/distutils/msvccompiler.py +++ b/wxPython/distutils/msvccompiler.py @@ -1,7 +1,8 @@ """distutils.msvccompiler Contains MSVCCompiler, an implementation of the abstract CCompiler class -for the Microsoft Visual Studio.""" +for the Microsoft Visual Studio. +""" # Written by Perry Stoll # hacked by Robin Becker and Thomas Heller to do a better job of @@ -12,7 +13,6 @@ for the Microsoft Visual Studio.""" __revision__ = "$Id$" import sys, os, string -from types import * from distutils.errors import \ DistutilsExecError, DistutilsPlatformError, \ CompileError, LibError, LinkError @@ -45,129 +45,128 @@ except ImportError: RegError = win32api.error except ImportError: + log.info("Warning: Can't read registry to find the " + "necessary compiler setting\n" + "Make sure that Python modules _winreg, " + "win32api or win32con are installed.") pass if _can_read_reg: - HKEY_CLASSES_ROOT = hkey_mod.HKEY_CLASSES_ROOT - HKEY_LOCAL_MACHINE = hkey_mod.HKEY_LOCAL_MACHINE - HKEY_CURRENT_USER = hkey_mod.HKEY_CURRENT_USER - HKEY_USERS = hkey_mod.HKEY_USERS + HKEYS = (hkey_mod.HKEY_USERS, + hkey_mod.HKEY_CURRENT_USER, + hkey_mod.HKEY_LOCAL_MACHINE, + hkey_mod.HKEY_CLASSES_ROOT) +def read_keys(base, key): + """Return list of registry keys.""" - -def get_devstudio_versions (): - """Get list of devstudio versions from the Windows registry. Return a - list of strings containing version numbers; the list will be - empty if we were unable to access the registry (eg. couldn't import - a registry-access module) or the appropriate registry keys weren't - found.""" - - if not _can_read_reg: - return [] - - K = 'Software\\Microsoft\\Devstudio' + try: + handle = RegOpenKeyEx(base, key) + except RegError: + return None L = [] - for base in (HKEY_CLASSES_ROOT, - HKEY_LOCAL_MACHINE, - HKEY_CURRENT_USER, - HKEY_USERS): + i = 0 + while 1: try: - k = RegOpenKeyEx(base,K) - i = 0 - while 1: - try: - p = RegEnumKey(k,i) - if p[0] in '123456789' and p not in L: - L.append(p) - except RegError: - break - i = i + 1 + k = RegEnumKey(handle, i) except RegError: - pass - L.sort() - L.reverse() + break + L.append(k) + i = i + 1 return L -# get_devstudio_versions () - - -def get_msvc_paths (path, version='6.0', platform='x86'): - """Get a list of devstudio directories (include, lib or path). Return - a list of strings; will be empty list if unable to access the - registry or appropriate registry keys not found.""" - - if not _can_read_reg: - return [] +def read_values(base, key): + """Return dict of registry keys and values. - L = [] - if path=='lib': - path= 'Library' - path = string.upper(path + ' Dirs') - K = ('Software\\Microsoft\\Devstudio\\%s\\' + - 'Build System\\Components\\Platforms\\Win32 (%s)\\Directories') % \ - (version,platform) - for base in (HKEY_CLASSES_ROOT, - HKEY_LOCAL_MACHINE, - HKEY_CURRENT_USER, - HKEY_USERS): + All names are converted to lowercase. + """ + try: + handle = RegOpenKeyEx(base, key) + except RegError: + return None + d = {} + i = 0 + while 1: try: - k = RegOpenKeyEx(base,K) - i = 0 - while 1: - try: - (p,v,t) = RegEnumValue(k,i) - if string.upper(p) == path: - V = string.split(v,';') - for v in V: - if hasattr(v, "encode"): - try: - v = v.encode("mbcs") - except UnicodeError: - pass - if v == '' or v in L: continue - L.append(v) - break - i = i + 1 - except RegError: - break + name, value, type = RegEnumValue(handle, i) except RegError: + break + name = name.lower() + d[convert_mbcs(name)] = convert_mbcs(value) + i = i + 1 + return d + +def convert_mbcs(s): + enc = getattr(s, "encode", None) + if enc is not None: + try: + s = enc("mbcs") + except UnicodeError: pass - return L - -# get_msvc_paths() - - -def find_exe (exe, version_number): - """Try to find an MSVC executable program 'exe' (from version - 'version_number' of MSVC) in several places: first, one of the MSVC - program search paths from the registry; next, the directories in the - PATH environment variable. If any of those work, return an absolute - path that is known to exist. If none of them work, just return the - original program name, 'exe'.""" - - for p in get_msvc_paths ('path', version_number): - fn = os.path.join (os.path.abspath(p), exe) - if os.path.isfile(fn): - return fn - - # didn't find it; try existing path - for p in string.split (os.environ['Path'],';'): - fn = os.path.join(os.path.abspath(p),exe) - if os.path.isfile(fn): - return fn - - return exe # last desperate hope - - -def set_path_env_var (name, version_number): - """Set environment variable 'name' to an MSVC path type value obtained - from 'get_msvc_paths()'. This is equivalent to a SET command prior - to execution of spawned commands.""" - - p = get_msvc_paths (name, version_number) - if p: - os.environ[name] = string.join (p,';') + return s + +class MacroExpander: + + def __init__(self, version): + self.macros = {} + self.load_macros(version) + + def set_macro(self, macro, path, key): + for base in HKEYS: + d = read_values(base, path) + if d: + self.macros["$(%s)" % macro] = d[key] + break + + def load_macros(self, version): + vsbase = r"Software\Microsoft\VisualStudio\%0.1f" % version + self.set_macro("VCInstallDir", vsbase + r"\Setup\VC", "productdir") + self.set_macro("VSInstallDir", vsbase + r"\Setup\VS", "productdir") + net = r"Software\Microsoft\.NETFramework" + self.set_macro("FrameworkDir", net, "installroot") + if version > 7.0: + self.set_macro("FrameworkSDKDir", net, "sdkinstallrootv1.1") + else: + self.set_macro("FrameworkSDKDir", net, "sdkinstallroot") + p = r"Software\Microsoft\NET Framework Setup\Product" + for base in HKEYS: + try: + h = RegOpenKeyEx(base, p) + except RegError: + continue + key = RegEnumKey(h, 0) + d = read_values(base, r"%s\%s" % (p, key)) + self.macros["$(FrameworkVersion)"] = d["version"] + + def sub(self, s): + for k, v in self.macros.items(): + s = string.replace(s, k, v) + return s + +def get_build_version(): + """Return the version of MSVC that was used to build Python. + + For Python 2.3 and up, the version number is included in + sys.version. For earlier versions, assume the compiler is MSVC 6. + """ + + prefix = "MSC v." + i = string.find(sys.version, prefix) + if i == -1: + return 6 + i = i + len(prefix) + s, rest = sys.version[i:].split(" ", 1) + majorVersion = int(s[:-2]) - 6 + minorVersion = int(s[2:3]) / 10.0 + # I don't think paths are affected by minor version in version 6 + if majorVersion == 6: + minorVersion = 0 + if majorVersion >= 6: + return majorVersion + minorVersion + # else we don't know what version of the compiler this is + return None + class MSVCCompiler (CCompiler) : """Concrete class that implements an interface to Microsoft Visual C++, @@ -199,39 +198,37 @@ class MSVCCompiler (CCompiler) : static_lib_format = shared_lib_format = '%s%s' exe_extension = '.exe' - - def __init__ (self, - verbose=0, - dry_run=0, - force=0): - + def __init__ (self, verbose=0, dry_run=0, force=0): CCompiler.__init__ (self, verbose, dry_run, force) - versions = get_devstudio_versions () - - if versions: - version = versions[0] # highest version - - self.cc = find_exe("cl.exe", version) - self.linker = find_exe("link.exe", version) - self.lib = find_exe("lib.exe", version) - self.rc = find_exe("rc.exe", version) # resource compiler - self.mc = find_exe("mc.exe", version) # message compiler - set_path_env_var ('lib', version) - set_path_env_var ('include', version) - path=get_msvc_paths('path', version) - try: - for p in string.split(os.environ['path'],';'): - path.append(p) - except KeyError: - pass - os.environ['path'] = string.join(path,';') + self.__version = get_build_version() + if self.__version >= 7: + self.__root = r"Software\Microsoft\VisualStudio" + self.__macros = MacroExpander(self.__version) else: - # devstudio not found in the registry - self.cc = "cl.exe" - self.linker = "link.exe" - self.lib = "lib.exe" - self.rc = "rc.exe" - self.mc = "mc.exe" + self.__root = r"Software\Microsoft\Devstudio" + self.__paths = self.get_msvc_paths("path") + + if len (self.__paths) == 0: + raise DistutilsPlatformError, \ + ("Python was built with version %s of Visual Studio, " + "and extensions need to be built with the same " + "version of the compiler, but it isn't installed." % self.__version) + + self.cc = self.find_exe("cl.exe") + self.linker = self.find_exe("link.exe") + self.lib = self.find_exe("lib.exe") + self.rc = self.find_exe("rc.exe") # resource compiler + self.mc = self.find_exe("mc.exe") # message compiler + self.set_path_env_var('lib') + self.set_path_env_var('include') + + # extend the MSVC path with the current path + try: + for p in string.split(os.environ['path'], ';'): + self.__paths.append(p) + except KeyError: + pass + os.environ['path'] = string.join(self.__paths, ';') self.preprocess_options = None self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GX' , @@ -500,4 +497,69 @@ class MSVCCompiler (CCompiler) : # find_library_file () -# class MSVCCompiler + # Helper methods for using the MSVC registry settings + + def find_exe(self, exe): + """Return path to an MSVC executable program. + + Tries to find the program in several places: first, one of the + MSVC program search paths from the registry; next, the directories + in the PATH environment variable. If any of those work, return an + absolute path that is known to exist. If none of them work, just + return the original program name, 'exe'. + """ + + for p in self.__paths: + fn = os.path.join(os.path.abspath(p), exe) + if os.path.isfile(fn): + return fn + + # didn't find it; try existing path + for p in string.split(os.environ['Path'],';'): + fn = os.path.join(os.path.abspath(p),exe) + if os.path.isfile(fn): + return fn + + return exe + + def get_msvc_paths(self, path, platform='x86'): + """Get a list of devstudio directories (include, lib or path). + + Return a list of strings. The list will be empty if unable to + access the registry or appropriate registry keys not found. + """ + + if not _can_read_reg: + return [] + + path = path + " dirs" + if self.__version >= 7: + key = (r"%s\%0.1f\VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories" + % (self.__root, self.__version)) + else: + key = (r"%s\6.0\Build System\Components\Platforms" + r"\Win32 (%s)\Directories" % (self.__root, platform)) + + for base in HKEYS: + d = read_values(base, key) + if d: + if self.__version >= 7: + return string.split(self.__macros.sub(d[path]), ";") + else: + return string.split(d[path], ";") + return [] + + def set_path_env_var(self, name): + """Set environment variable 'name' to an MSVC path type value. + + This is equivalent to a SET command prior to execution of spawned + commands. + """ + + if name == "lib": + p = self.get_msvc_paths("library") + else: + p = self.get_msvc_paths(name) + if p: + os.environ[name] = string.join(p, ';') +