diff options
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/distutils/msvccompiler.py | 332 |
1 files changed, 189 insertions, 143 deletions
diff --git a/Lib/distutils/msvccompiler.py b/Lib/distutils/msvccompiler.py index e07a6d5..b4c890d 100644 --- a/Lib/distutils/msvccompiler.py +++ b/Lib/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 @@ -48,126 +48,116 @@ except ImportError: 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\%s.0" % 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") + 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 += len(prefix) + s, rest = sys.version[i:].split(" ", 1) + n = int(s[:-2]) + if n == 12: + return 6 + elif n == 13: + return 7 + # 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 +189,31 @@ 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") + + 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 +482,68 @@ 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\7.0\VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories" + % (self.__root,)) + else: + key = (r"%s\6.0\Build System\Components\Platforms" + + 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, ';') + |