PyXR

c:\python24\lib \ distutils \ msvccompiler.py



0001 """distutils.msvccompiler
0002 
0003 Contains MSVCCompiler, an implementation of the abstract CCompiler class
0004 for the Microsoft Visual Studio.
0005 """
0006 
0007 # Written by Perry Stoll
0008 # hacked by Robin Becker and Thomas Heller to do a better job of
0009 #   finding DevStudio (through the registry)
0010 
0011 # This module should be kept compatible with Python 1.5.2.
0012 
0013 __revision__ = "$Id: msvccompiler.py,v 1.60 2004/07/18 06:14:42 tim_one Exp $"
0014 
0015 import sys, os, string
0016 from distutils.errors import \
0017      DistutilsExecError, DistutilsPlatformError, \
0018      CompileError, LibError, LinkError
0019 from distutils.ccompiler import \
0020      CCompiler, gen_preprocess_options, gen_lib_options
0021 from distutils import log
0022 
0023 _can_read_reg = 0
0024 try:
0025     import _winreg
0026 
0027     _can_read_reg = 1
0028     hkey_mod = _winreg
0029 
0030     RegOpenKeyEx = _winreg.OpenKeyEx
0031     RegEnumKey = _winreg.EnumKey
0032     RegEnumValue = _winreg.EnumValue
0033     RegError = _winreg.error
0034 
0035 except ImportError:
0036     try:
0037         import win32api
0038         import win32con
0039         _can_read_reg = 1
0040         hkey_mod = win32con
0041 
0042         RegOpenKeyEx = win32api.RegOpenKeyEx
0043         RegEnumKey = win32api.RegEnumKey
0044         RegEnumValue = win32api.RegEnumValue
0045         RegError = win32api.error
0046 
0047     except ImportError:
0048         log.info("Warning: Can't read registry to find the "
0049                  "necessary compiler setting\n"
0050                  "Make sure that Python modules _winreg, "
0051                  "win32api or win32con are installed.")
0052         pass
0053 
0054 if _can_read_reg:
0055     HKEYS = (hkey_mod.HKEY_USERS,
0056              hkey_mod.HKEY_CURRENT_USER,
0057              hkey_mod.HKEY_LOCAL_MACHINE,
0058              hkey_mod.HKEY_CLASSES_ROOT)
0059 
0060 def read_keys(base, key):
0061     """Return list of registry keys."""
0062 
0063     try:
0064         handle = RegOpenKeyEx(base, key)
0065     except RegError:
0066         return None
0067     L = []
0068     i = 0
0069     while 1:
0070         try:
0071             k = RegEnumKey(handle, i)
0072         except RegError:
0073             break
0074         L.append(k)
0075         i = i + 1
0076     return L
0077 
0078 def read_values(base, key):
0079     """Return dict of registry keys and values.
0080 
0081     All names are converted to lowercase.
0082     """
0083     try:
0084         handle = RegOpenKeyEx(base, key)
0085     except RegError:
0086         return None
0087     d = {}
0088     i = 0
0089     while 1:
0090         try:
0091             name, value, type = RegEnumValue(handle, i)
0092         except RegError:
0093             break
0094         name = name.lower()
0095         d[convert_mbcs(name)] = convert_mbcs(value)
0096         i = i + 1
0097     return d
0098 
0099 def convert_mbcs(s):
0100     enc = getattr(s, "encode", None)
0101     if enc is not None:
0102         try:
0103             s = enc("mbcs")
0104         except UnicodeError:
0105             pass
0106     return s
0107 
0108 class MacroExpander:
0109 
0110     def __init__(self, version):
0111         self.macros = {}
0112         self.load_macros(version)
0113 
0114     def set_macro(self, macro, path, key):
0115         for base in HKEYS:
0116             d = read_values(base, path)
0117             if d:
0118                 self.macros["$(%s)" % macro] = d[key]
0119                 break
0120 
0121     def load_macros(self, version):
0122         vsbase = r"Software\Microsoft\VisualStudio\%0.1f" % version
0123         self.set_macro("VCInstallDir", vsbase + r"\Setup\VC", "productdir")
0124         self.set_macro("VSInstallDir", vsbase + r"\Setup\VS", "productdir")
0125         net = r"Software\Microsoft\.NETFramework"
0126         self.set_macro("FrameworkDir", net, "installroot")
0127         if version > 7.0:
0128             self.set_macro("FrameworkSDKDir", net, "sdkinstallrootv1.1")
0129         else:
0130             self.set_macro("FrameworkSDKDir", net, "sdkinstallroot")
0131 
0132         p = r"Software\Microsoft\NET Framework Setup\Product"
0133         for base in HKEYS:
0134             try:
0135                 h = RegOpenKeyEx(base, p)
0136             except RegError:
0137                 continue
0138             key = RegEnumKey(h, 0)
0139             d = read_values(base, r"%s\%s" % (p, key))
0140             self.macros["$(FrameworkVersion)"] = d["version"]
0141 
0142     def sub(self, s):
0143         for k, v in self.macros.items():
0144             s = string.replace(s, k, v)
0145         return s
0146 
0147 def get_build_version():
0148     """Return the version of MSVC that was used to build Python.
0149 
0150     For Python 2.3 and up, the version number is included in
0151     sys.version.  For earlier versions, assume the compiler is MSVC 6.
0152     """
0153 
0154     prefix = "MSC v."
0155     i = string.find(sys.version, prefix)
0156     if i == -1:
0157         return 6
0158     i = i + len(prefix)
0159     s, rest = sys.version[i:].split(" ", 1)
0160     majorVersion = int(s[:-2]) - 6
0161     minorVersion = int(s[2:3]) / 10.0
0162     # I don't think paths are affected by minor version in version 6
0163     if majorVersion == 6:
0164         minorVersion = 0
0165     if majorVersion >= 6:
0166         return majorVersion + minorVersion
0167     # else we don't know what version of the compiler this is
0168     return None
0169 
0170 
0171 class MSVCCompiler (CCompiler) :
0172     """Concrete class that implements an interface to Microsoft Visual C++,
0173        as defined by the CCompiler abstract class."""
0174 
0175     compiler_type = 'msvc'
0176 
0177     # Just set this so CCompiler's constructor doesn't barf.  We currently
0178     # don't use the 'set_executables()' bureaucracy provided by CCompiler,
0179     # as it really isn't necessary for this sort of single-compiler class.
0180     # Would be nice to have a consistent interface with UnixCCompiler,
0181     # though, so it's worth thinking about.
0182     executables = {}
0183 
0184     # Private class data (need to distinguish C from C++ source for compiler)
0185     _c_extensions = ['.c']
0186     _cpp_extensions = ['.cc', '.cpp', '.cxx']
0187     _rc_extensions = ['.rc']
0188     _mc_extensions = ['.mc']
0189 
0190     # Needed for the filename generation methods provided by the
0191     # base class, CCompiler.
0192     src_extensions = (_c_extensions + _cpp_extensions +
0193                       _rc_extensions + _mc_extensions)
0194     res_extension = '.res'
0195     obj_extension = '.obj'
0196     static_lib_extension = '.lib'
0197     shared_lib_extension = '.dll'
0198     static_lib_format = shared_lib_format = '%s%s'
0199     exe_extension = '.exe'
0200 
0201     def __init__ (self, verbose=0, dry_run=0, force=0):
0202         CCompiler.__init__ (self, verbose, dry_run, force)
0203         self.__version = get_build_version()
0204         if self.__version >= 7:
0205             self.__root = r"Software\Microsoft\VisualStudio"
0206             self.__macros = MacroExpander(self.__version)
0207         else:
0208             self.__root = r"Software\Microsoft\Devstudio"
0209         self.__paths = self.get_msvc_paths("path")
0210 
0211         if len (self.__paths) == 0:
0212             raise DistutilsPlatformError, \
0213                   ("Python was built with version %s of Visual Studio, "
0214                    "and extensions need to be built with the same "
0215                    "version of the compiler, but it isn't installed." % self.__version)
0216 
0217         self.cc = self.find_exe("cl.exe")
0218         self.linker = self.find_exe("link.exe")
0219         self.lib = self.find_exe("lib.exe")
0220         self.rc = self.find_exe("rc.exe")   # resource compiler
0221         self.mc = self.find_exe("mc.exe")   # message compiler
0222         self.set_path_env_var('lib')
0223         self.set_path_env_var('include')
0224 
0225         # extend the MSVC path with the current path
0226         try:
0227             for p in string.split(os.environ['path'], ';'):
0228                 self.__paths.append(p)
0229         except KeyError:
0230             pass
0231         os.environ['path'] = string.join(self.__paths, ';')
0232 
0233         self.preprocess_options = None
0234         self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GX' ,
0235                                  '/DNDEBUG']
0236         self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GX',
0237                                       '/Z7', '/D_DEBUG']
0238 
0239         self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO']
0240         self.ldflags_shared_debug = [
0241             '/DLL', '/nologo', '/INCREMENTAL:no', '/pdb:None', '/DEBUG'
0242             ]
0243         self.ldflags_static = [ '/nologo']
0244 
0245 
0246     # -- Worker methods ------------------------------------------------
0247 
0248     def object_filenames (self,
0249                           source_filenames,
0250                           strip_dir=0,
0251                           output_dir=''):
0252         # Copied from ccompiler.py, extended to return .res as 'object'-file
0253         # for .rc input file
0254         if output_dir is None: output_dir = ''
0255         obj_names = []
0256         for src_name in source_filenames:
0257             (base, ext) = os.path.splitext (src_name)
0258             if ext not in self.src_extensions:
0259                 # Better to raise an exception instead of silently continuing
0260                 # and later complain about sources and targets having
0261                 # different lengths
0262                 raise CompileError ("Don't know how to compile %s" % src_name)
0263             if strip_dir:
0264                 base = os.path.basename (base)
0265             if ext in self._rc_extensions:
0266                 obj_names.append (os.path.join (output_dir,
0267                                                 base + self.res_extension))
0268             elif ext in self._mc_extensions:
0269                 obj_names.append (os.path.join (output_dir,
0270                                                 base + self.res_extension))
0271             else:
0272                 obj_names.append (os.path.join (output_dir,
0273                                                 base + self.obj_extension))
0274         return obj_names
0275 
0276     # object_filenames ()
0277 
0278 
0279     def compile(self, sources,
0280                 output_dir=None, macros=None, include_dirs=None, debug=0,
0281                 extra_preargs=None, extra_postargs=None, depends=None):
0282 
0283         macros, objects, extra_postargs, pp_opts, build = \
0284                 self._setup_compile(output_dir, macros, include_dirs, sources,
0285                                     depends, extra_postargs)
0286 
0287         compile_opts = extra_preargs or []
0288         compile_opts.append ('/c')
0289         if debug:
0290             compile_opts.extend(self.compile_options_debug)
0291         else:
0292             compile_opts.extend(self.compile_options)
0293 
0294         for obj in objects:
0295             try:
0296                 src, ext = build[obj]
0297             except KeyError:
0298                 continue
0299             if debug:
0300                 # pass the full pathname to MSVC in debug mode,
0301                 # this allows the debugger to find the source file
0302                 # without asking the user to browse for it
0303                 src = os.path.abspath(src)
0304 
0305             if ext in self._c_extensions:
0306                 input_opt = "/Tc" + src
0307             elif ext in self._cpp_extensions:
0308                 input_opt = "/Tp" + src
0309             elif ext in self._rc_extensions:
0310                 # compile .RC to .RES file
0311                 input_opt = src
0312                 output_opt = "/fo" + obj
0313                 try:
0314                     self.spawn ([self.rc] + pp_opts +
0315                                 [output_opt] + [input_opt])
0316                 except DistutilsExecError, msg:
0317                     raise CompileError, msg
0318                 continue
0319             elif ext in self._mc_extensions:
0320 
0321                 # Compile .MC to .RC file to .RES file.
0322                 #   * '-h dir' specifies the directory for the
0323                 #     generated include file
0324                 #   * '-r dir' specifies the target directory of the
0325                 #     generated RC file and the binary message resource
0326                 #     it includes
0327                 #
0328                 # For now (since there are no options to change this),
0329                 # we use the source-directory for the include file and
0330                 # the build directory for the RC file and message
0331                 # resources. This works at least for win32all.
0332 
0333                 h_dir = os.path.dirname (src)
0334                 rc_dir = os.path.dirname (obj)
0335                 try:
0336                     # first compile .MC to .RC and .H file
0337                     self.spawn ([self.mc] +
0338                                 ['-h', h_dir, '-r', rc_dir] + [src])
0339                     base, _ = os.path.splitext (os.path.basename (src))
0340                     rc_file = os.path.join (rc_dir, base + '.rc')
0341                     # then compile .RC to .RES file
0342                     self.spawn ([self.rc] +
0343                                 ["/fo" + obj] + [rc_file])
0344 
0345                 except DistutilsExecError, msg:
0346                     raise CompileError, msg
0347                 continue
0348             else:
0349                 # how to handle this file?
0350                 raise CompileError (
0351                     "Don't know how to compile %s to %s" % \
0352                     (src, obj))
0353 
0354             output_opt = "/Fo" + obj
0355             try:
0356                 self.spawn ([self.cc] + compile_opts + pp_opts +
0357                             [input_opt, output_opt] +
0358                             extra_postargs)
0359             except DistutilsExecError, msg:
0360                 raise CompileError, msg
0361 
0362         return objects
0363 
0364     # compile ()
0365 
0366 
0367     def create_static_lib (self,
0368                            objects,
0369                            output_libname,
0370                            output_dir=None,
0371                            debug=0,
0372                            target_lang=None):
0373 
0374         (objects, output_dir) = self._fix_object_args (objects, output_dir)
0375         output_filename = \
0376             self.library_filename (output_libname, output_dir=output_dir)
0377 
0378         if self._need_link (objects, output_filename):
0379             lib_args = objects + ['/OUT:' + output_filename]
0380             if debug:
0381                 pass                    # XXX what goes here?
0382             try:
0383                 self.spawn ([self.lib] + lib_args)
0384             except DistutilsExecError, msg:
0385                 raise LibError, msg
0386 
0387         else:
0388             log.debug("skipping %s (up-to-date)", output_filename)
0389 
0390     # create_static_lib ()
0391 
0392     def link (self,
0393               target_desc,
0394               objects,
0395               output_filename,
0396               output_dir=None,
0397               libraries=None,
0398               library_dirs=None,
0399               runtime_library_dirs=None,
0400               export_symbols=None,
0401               debug=0,
0402               extra_preargs=None,
0403               extra_postargs=None,
0404               build_temp=None,
0405               target_lang=None):
0406 
0407         (objects, output_dir) = self._fix_object_args (objects, output_dir)
0408         (libraries, library_dirs, runtime_library_dirs) = \
0409             self._fix_lib_args (libraries, library_dirs, runtime_library_dirs)
0410 
0411         if runtime_library_dirs:
0412             self.warn ("I don't know what to do with 'runtime_library_dirs': "
0413                        + str (runtime_library_dirs))
0414 
0415         lib_opts = gen_lib_options (self,
0416                                     library_dirs, runtime_library_dirs,
0417                                     libraries)
0418         if output_dir is not None:
0419             output_filename = os.path.join (output_dir, output_filename)
0420 
0421         if self._need_link (objects, output_filename):
0422 
0423             if target_desc == CCompiler.EXECUTABLE:
0424                 if debug:
0425                     ldflags = self.ldflags_shared_debug[1:]
0426                 else:
0427                     ldflags = self.ldflags_shared[1:]
0428             else:
0429                 if debug:
0430                     ldflags = self.ldflags_shared_debug
0431                 else:
0432                     ldflags = self.ldflags_shared
0433 
0434             export_opts = []
0435             for sym in (export_symbols or []):
0436                 export_opts.append("/EXPORT:" + sym)
0437 
0438             ld_args = (ldflags + lib_opts + export_opts +
0439                        objects + ['/OUT:' + output_filename])
0440 
0441             # The MSVC linker generates .lib and .exp files, which cannot be
0442             # suppressed by any linker switches. The .lib files may even be
0443             # needed! Make sure they are generated in the temporary build
0444             # directory. Since they have different names for debug and release
0445             # builds, they can go into the same directory.
0446             if export_symbols is not None:
0447                 (dll_name, dll_ext) = os.path.splitext(
0448                     os.path.basename(output_filename))
0449                 implib_file = os.path.join(
0450                     os.path.dirname(objects[0]),
0451                     self.library_filename(dll_name))
0452                 ld_args.append ('/IMPLIB:' + implib_file)
0453 
0454             if extra_preargs:
0455                 ld_args[:0] = extra_preargs
0456             if extra_postargs:
0457                 ld_args.extend(extra_postargs)
0458 
0459             self.mkpath (os.path.dirname (output_filename))
0460             try:
0461                 self.spawn ([self.linker] + ld_args)
0462             except DistutilsExecError, msg:
0463                 raise LinkError, msg
0464 
0465         else:
0466             log.debug("skipping %s (up-to-date)", output_filename)
0467 
0468     # link ()
0469 
0470 
0471     # -- Miscellaneous methods -----------------------------------------
0472     # These are all used by the 'gen_lib_options() function, in
0473     # ccompiler.py.
0474 
0475     def library_dir_option (self, dir):
0476         return "/LIBPATH:" + dir
0477 
0478     def runtime_library_dir_option (self, dir):
0479         raise DistutilsPlatformError, \
0480               "don't know how to set runtime library search path for MSVC++"
0481 
0482     def library_option (self, lib):
0483         return self.library_filename (lib)
0484 
0485 
0486     def find_library_file (self, dirs, lib, debug=0):
0487         # Prefer a debugging library if found (and requested), but deal
0488         # with it if we don't have one.
0489         if debug:
0490             try_names = [lib + "_d", lib]
0491         else:
0492             try_names = [lib]
0493         for dir in dirs:
0494             for name in try_names:
0495                 libfile = os.path.join(dir, self.library_filename (name))
0496                 if os.path.exists(libfile):
0497                     return libfile
0498         else:
0499             # Oops, didn't find it in *any* of 'dirs'
0500             return None
0501 
0502     # find_library_file ()
0503 
0504     # Helper methods for using the MSVC registry settings
0505 
0506     def find_exe(self, exe):
0507         """Return path to an MSVC executable program.
0508 
0509         Tries to find the program in several places: first, one of the
0510         MSVC program search paths from the registry; next, the directories
0511         in the PATH environment variable.  If any of those work, return an
0512         absolute path that is known to exist.  If none of them work, just
0513         return the original program name, 'exe'.
0514         """
0515 
0516         for p in self.__paths:
0517             fn = os.path.join(os.path.abspath(p), exe)
0518             if os.path.isfile(fn):
0519                 return fn
0520 
0521         # didn't find it; try existing path
0522         for p in string.split(os.environ['Path'],';'):
0523             fn = os.path.join(os.path.abspath(p),exe)
0524             if os.path.isfile(fn):
0525                 return fn
0526 
0527         return exe
0528 
0529     def get_msvc_paths(self, path, platform='x86'):
0530         """Get a list of devstudio directories (include, lib or path).
0531 
0532         Return a list of strings.  The list will be empty if unable to
0533         access the registry or appropriate registry keys not found.
0534         """
0535 
0536         if not _can_read_reg:
0537             return []
0538 
0539         path = path + " dirs"
0540         if self.__version >= 7:
0541             key = (r"%s\%0.1f\VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories"
0542                    % (self.__root, self.__version))
0543         else:
0544             key = (r"%s\6.0\Build System\Components\Platforms"
0545                    r"\Win32 (%s)\Directories" % (self.__root, platform))
0546 
0547         for base in HKEYS:
0548             d = read_values(base, key)
0549             if d:
0550                 if self.__version >= 7:
0551                     return string.split(self.__macros.sub(d[path]), ";")
0552                 else:
0553                     return string.split(d[path], ";")
0554         # MSVC 6 seems to create the registry entries we need only when
0555         # the GUI is run.
0556         if self.__version == 6:
0557             for base in HKEYS:
0558                 if read_values(base, r"%s\6.0" % self.__root) is not None:
0559                     self.warn("It seems you have Visual Studio 6 installed, "
0560                         "but the expected registry settings are not present.\n"
0561                         "You must at least run the Visual Studio GUI once "
0562                         "so that these entries are created.")
0563                 break
0564         return []
0565 
0566     def set_path_env_var(self, name):
0567         """Set environment variable 'name' to an MSVC path type value.
0568 
0569         This is equivalent to a SET command prior to execution of spawned
0570         commands.
0571         """
0572 
0573         if name == "lib":
0574             p = self.get_msvc_paths("library")
0575         else:
0576             p = self.get_msvc_paths(name)
0577         if p:
0578             os.environ[name] = string.join(p, ';')
0579 

Generated by PyXR 0.9.4
SourceForge.net Logo