[Python-checkins] python/dist/src/Lib/distutils msvccompiler.py,1.53,1.54

jhylton@users.sourceforge.net jhylton@users.sourceforge.net
Fri, 09 May 2003 09:06:45 -0700


Update of /cvsroot/python/python/dist/src/Lib/distutils
In directory sc8-pr-cvs1:/tmp/cvs-serv4990/Lib/distutils

Modified Files:
	msvccompiler.py 
Log Message:
Variant of SF patch 614770: MSVC 7 support

distutils now looks for the compiler version in sys.version, falling
back to MSVC 6 if the version isn't listed (Python 2.2 and lower).
Add helper routines for reading the registry.  Refactor many
module functions into methods of the compiler to avoid passing
lots of state as arguments.


Index: msvccompiler.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/distutils/msvccompiler.py,v
retrieving revision 1.53
retrieving revision 1.54
diff -C2 -d -r1.53 -r1.54
*** msvccompiler.py	31 Jan 2003 20:40:15 -0000	1.53
--- msvccompiler.py	9 May 2003 16:06:42 -0000	1.54
***************
*** 2,6 ****
  
  Contains MSVCCompiler, an implementation of the abstract CCompiler class
! for the Microsoft Visual Studio."""
  
  # Written by Perry Stoll
--- 2,7 ----
  
  Contains MSVCCompiler, an implementation of the abstract CCompiler class
! for the Microsoft Visual Studio.
! """
  
  # Written by Perry Stoll
***************
*** 13,17 ****
  
  import sys, os, string
- from types import *
  from distutils.errors import \
       DistutilsExecError, DistutilsPlatformError, \
--- 14,17 ----
***************
*** 49,172 ****
  
  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
! 
! 
! 
! 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'
      L = []
!     for base in (HKEY_CLASSES_ROOT,
!                  HKEY_LOCAL_MACHINE,
!                  HKEY_CURRENT_USER,
!                  HKEY_USERS):
          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
          except RegError:
!             pass
!     L.sort()
!     L.reverse()
      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 []
  
!     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):
          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
          except RegError:
!             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,';')
  
  
  class MSVCCompiler (CCompiler) :
--- 49,162 ----
  
  if _can_read_reg:
!     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."""
  
!     try:
!         handle = RegOpenKeyEx(base, key)
!     except RegError:
!         return None
      L = []
!     i = 0
!     while 1:
          try:
!             k = RegEnumKey(handle, i)
          except RegError:
!             break
!         L.append(k)
!         i = i + 1
      return L
  
! def read_values(base, key):
!     """Return dict of registry keys and values.
  
!     All names are converted to lowercase.
!     """
!     try:
!         handle = RegOpenKeyEx(base, key)
!     except RegError:
!         return None
!     d = {}
!     i = 0
!     while 1:
          try:
!             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 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) :
***************
*** 200,236 ****
      exe_extension = '.exe'
  
! 
!     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,';')
!         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.preprocess_options = None
--- 190,218 ----
      exe_extension = '.exe'
  
!     def __init__ (self, verbose=0, dry_run=0, force=0):
          CCompiler.__init__ (self, verbose, dry_run, force)
!         self.__version = get_build_version()
!         if self.__version == 7:
!             self.__root = r"Software\Microsoft\VisualStudio"
!             self.__macros = MacroExpander(self.__version)
!         else:
!             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
***************
*** 501,503 ****
      # find_library_file ()
  
! # class MSVCCompiler
--- 483,549 ----
      # find_library_file ()
  
!     # 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, ';')
!