Index: Lib/distutils/msvccompiler.py =================================================================== --- Lib/distutils/msvccompiler.py (revision 59036) +++ Lib/distutils/msvccompiler.py (working copy) @@ -7,15 +7,17 @@ # Written by Perry Stoll # hacked by Robin Becker and Thomas Heller to do a better job of # finding DevStudio (through the registry) +# ported to VS 2008 by Christian Heimes __revision__ = "$Id$" -import sys, os -from distutils.errors import \ - DistutilsExecError, DistutilsPlatformError, \ - CompileError, LibError, LinkError -from distutils.ccompiler import \ - CCompiler, gen_preprocess_options, gen_lib_options +import os +import subprocess +import sys +from distutils.errors import (DistutilsExecError, DistutilsPlatformError, + CompileError, LibError, LinkError) +from distutils.ccompiler import (CCompiler, gen_preprocess_options, + gen_lib_options) from distutils import log _can_read_reg = False @@ -102,44 +104,57 @@ return s class MacroExpander: + _vsbase = r"Software\Microsoft\VisualStudio\%0.1f" + winsdkbase = r"Software\Microsoft\Microsoft SDKs\Windows" + netframework = r"Software\Microsoft\.NETFramework" + def __init__(self, version): self.macros = {} + self.vsbase = self._vsbase % version self.load_macros(version) def set_macro(self, macro, path, key): for base in HKEYS: d = read_values(base, path) - if d: + if d and key in d: self.macros["$(%s)" % macro] = d[key] - break + return + raise KeyError(key) 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") + self.set_macro("VCInstallDir", self.vsbase + r"\Setup\VC", "productdir") + self.set_macro("VSInstallDir", self.vsbase + r"\Setup\VS", "productdir") + self.set_macro("FrameworkDir", self.netframework, "installroot") try: - if version > 7.0: - self.set_macro("FrameworkSDKDir", net, "sdkinstallrootv1.1") + if version >= 9.0: + self.set_macro("FrameworkSDKDir", self.netframework, + "sdkinstallrootv2.0") + elif version > 7.0: + self.set_macro("FrameworkSDKDir", self.netframework, + "sdkinstallrootv1.1") else: - self.set_macro("FrameworkSDKDir", net, "sdkinstallroot") + self.set_macro("FrameworkSDKDir", self.netframework, + "sdkinstallroot") except KeyError as exc: # raise DistutilsPlatformError( - """Python was built with Visual Studio 2003; + """Python was built with Visual Studio 2008; extensions must be built with a compiler than can generate compatible binaries. -Visual Studio 2003 was not found on this system. If you have Cygwin installed, +Visual Studio 2008 was not found on this system. If you have Cygwin installed, you can try compiling with MingW32, by passing "-c mingw32" to setup.py.""") - 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"] + if version >= 0.9: + self.set_macro("FrameworkVersion", self.vsbase, "clr version") + self.set_macro("WindowsSdkDir", self.winsdkbase, "currentinstallfolder") + else: + 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(): @@ -171,15 +186,15 @@ def get_build_architecture(): """Return the processor architecture. - Possible results are "Intel", "Itanium", or "AMD64". + Possible results are "x86" or "amd64". """ prefix = " bit (" i = sys.version.find(prefix) if i == -1: - return "Intel" + return "x86" j = sys.version.find(")", i) - return sys.version[i+len(prefix):j] + return sys.version[i+len(prefix):j].lower() def normalize_and_reduce_paths(paths): """Return a list of normalized paths with duplicates removed. @@ -195,7 +210,44 @@ reduced_paths.append(np) return reduced_paths +def query_vcvarsall(macros, arch="x86"): + """Launch vcvarsall.bat and read the settings from its environment + """ + vc = macros.macros["$(VCInstallDir)"] + vcvarsall = os.path.join(vc, "vcvarsall.bat") + interesting = set(("include", "lib", "libpath", "path")) + result = {} + + if not os.path.exists(vcvarsall): + raise IOError(vcvarsall) + popen = subprocess.Popen('"%s" & set' % vcvarsall, stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + if popen.wait() != 0: + raise IOError(popen.stderr.read()) + for line in popen.stdout: + if b'=' not in line: + continue + line = line.strip() + key, value = line.split(b'=') + key = convert_mbcs(key.lower()) + + if key in interesting: + value = convert_mbcs(value) + if value.endswith(os.pathsep): + value = value[:-1] + result[key] = value + + if len(result) != len(interesting): + raise ValueError(str(list(result.keys()))) + + return result + +VERSION = get_build_version() +ARCH = get_build_architecture() +MACROS = MacroExpander(VERSION) +VC_ENV = query_vcvarsall(MACROS, ARCH) + class MSVCCompiler(CCompiler) : """Concrete class that implements an interface to Microsoft Visual C++, as defined by the CCompiler abstract class.""" @@ -228,24 +280,14 @@ def __init__(self, verbose=0, dry_run=0, force=0): CCompiler.__init__ (self, verbose, dry_run, force) - self.__version = get_build_version() - self.__arch = get_build_architecture() - if self.__arch == "Intel": - # x86 - if self.__version >= 7: - self.__root = r"Software\Microsoft\VisualStudio" - self.__macros = MacroExpander(self.__version) - else: - self.__root = r"Software\Microsoft\Devstudio" - self.__product = "Visual Studio version %s" % self.__version - else: - # Win64. Assume this was built with the platform SDK - self.__product = "Microsoft SDK compiler %s" % (self.__version + 6) - + self.__version = VERSION + self.__arch = ARCH + self.__root = r"Software\Microsoft\VisualStudio" + self.__macros = MACROS + self.__path = [] self.initialized = False def initialize(self): - self.__paths = [] if "DISTUTILS_USE_SDK" in os.environ and "MSSdk" in os.environ and self.find_exe("cl.exe"): # Assume that the SDK set up everything alright; don't try to be # smarter @@ -255,7 +297,9 @@ self.rc = "rc.exe" self.mc = "mc.exe" else: - self.__paths = self.get_msvc_paths("path") + self.__paths = VC_ENV['path'].split(os.pathsep) + os.environ['lib'] = VC_ENV['lib'] + os.environ['include'] = VC_ENV['include'] if len(self.__paths) == 0: raise DistutilsPlatformError("Python was built with %s, " @@ -268,8 +312,8 @@ 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') + #self.set_path_env_var('lib') + #self.set_path_env_var('include') # extend the MSVC path with the current path try: @@ -281,7 +325,7 @@ os.environ['path'] = ";".join(self.__paths) self.preprocess_options = None - if self.__arch == "Intel": + if self.__arch == "x86": self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GX' , '/DNDEBUG'] self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GX', @@ -582,53 +626,3 @@ 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 self.__macros.sub(d[path]).split(";") - else: - return d[path].split(";") - # MSVC 6 seems to create the registry entries we need only when - # the GUI is run. - if self.__version == 6: - for base in HKEYS: - if read_values(base, r"%s\6.0" % self.__root) is not None: - self.warn("It seems you have Visual Studio 6 installed, " - "but the expected registry settings are not present.\n" - "You must at least run the Visual Studio GUI once " - "so that these entries are created.") - break - 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] = ';'.join(p)