symbian-qemu-0.9.1-12/python-2.6.1/Lib/distutils/msvc9compiler.py
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 """distutils.msvc9compiler
       
     2 
       
     3 Contains MSVCCompiler, an implementation of the abstract CCompiler class
       
     4 for the Microsoft Visual Studio 2008.
       
     5 
       
     6 The module is compatible with VS 2005 and VS 2008. You can find legacy support
       
     7 for older versions of VS in distutils.msvccompiler.
       
     8 """
       
     9 
       
    10 # Written by Perry Stoll
       
    11 # hacked by Robin Becker and Thomas Heller to do a better job of
       
    12 #   finding DevStudio (through the registry)
       
    13 # ported to VS2005 and VS 2008 by Christian Heimes
       
    14 
       
    15 __revision__ = "$Id: msvc9compiler.py 67415 2008-11-28 11:03:48Z christian.heimes $"
       
    16 
       
    17 import os
       
    18 import subprocess
       
    19 import sys
       
    20 from distutils.errors import (DistutilsExecError, DistutilsPlatformError,
       
    21     CompileError, LibError, LinkError)
       
    22 from distutils.ccompiler import (CCompiler, gen_preprocess_options,
       
    23     gen_lib_options)
       
    24 from distutils import log
       
    25 from distutils.util import get_platform
       
    26 
       
    27 import _winreg
       
    28 
       
    29 RegOpenKeyEx = _winreg.OpenKeyEx
       
    30 RegEnumKey = _winreg.EnumKey
       
    31 RegEnumValue = _winreg.EnumValue
       
    32 RegError = _winreg.error
       
    33 
       
    34 HKEYS = (_winreg.HKEY_USERS,
       
    35          _winreg.HKEY_CURRENT_USER,
       
    36          _winreg.HKEY_LOCAL_MACHINE,
       
    37          _winreg.HKEY_CLASSES_ROOT)
       
    38 
       
    39 VS_BASE = r"Software\Microsoft\VisualStudio\%0.1f"
       
    40 WINSDK_BASE = r"Software\Microsoft\Microsoft SDKs\Windows"
       
    41 NET_BASE = r"Software\Microsoft\.NETFramework"
       
    42 
       
    43 # A map keyed by get_platform() return values to values accepted by
       
    44 # 'vcvarsall.bat'.  Note a cross-compile may combine these (eg, 'x86_amd64' is
       
    45 # the param to cross-compile on x86 targetting amd64.)
       
    46 PLAT_TO_VCVARS = {
       
    47     'win32' : 'x86',
       
    48     'win-amd64' : 'amd64',
       
    49     'win-ia64' : 'ia64',
       
    50 }
       
    51 
       
    52 class Reg:
       
    53     """Helper class to read values from the registry
       
    54     """
       
    55 
       
    56     @classmethod
       
    57     def get_value(cls, path, key):
       
    58         for base in HKEYS:
       
    59             d = cls.read_values(base, path)
       
    60             if d and key in d:
       
    61                 return d[key]
       
    62         raise KeyError(key)
       
    63 
       
    64     @classmethod
       
    65     def read_keys(cls, base, key):
       
    66         """Return list of registry keys."""
       
    67         try:
       
    68             handle = RegOpenKeyEx(base, key)
       
    69         except RegError:
       
    70             return None
       
    71         L = []
       
    72         i = 0
       
    73         while True:
       
    74             try:
       
    75                 k = RegEnumKey(handle, i)
       
    76             except RegError:
       
    77                 break
       
    78             L.append(k)
       
    79             i += 1
       
    80         return L
       
    81 
       
    82     @classmethod
       
    83     def read_values(cls, base, key):
       
    84         """Return dict of registry keys and values.
       
    85 
       
    86         All names are converted to lowercase.
       
    87         """
       
    88         try:
       
    89             handle = RegOpenKeyEx(base, key)
       
    90         except RegError:
       
    91             return None
       
    92         d = {}
       
    93         i = 0
       
    94         while True:
       
    95             try:
       
    96                 name, value, type = RegEnumValue(handle, i)
       
    97             except RegError:
       
    98                 break
       
    99             name = name.lower()
       
   100             d[cls.convert_mbcs(name)] = cls.convert_mbcs(value)
       
   101             i += 1
       
   102         return d
       
   103 
       
   104     @staticmethod
       
   105     def convert_mbcs(s):
       
   106         dec = getattr(s, "decode", None)
       
   107         if dec is not None:
       
   108             try:
       
   109                 s = dec("mbcs")
       
   110             except UnicodeError:
       
   111                 pass
       
   112         return s
       
   113 
       
   114 class MacroExpander:
       
   115 
       
   116     def __init__(self, version):
       
   117         self.macros = {}
       
   118         self.vsbase = VS_BASE % version
       
   119         self.load_macros(version)
       
   120 
       
   121     def set_macro(self, macro, path, key):
       
   122         self.macros["$(%s)" % macro] = Reg.get_value(path, key)
       
   123 
       
   124     def load_macros(self, version):
       
   125         self.set_macro("VCInstallDir", self.vsbase + r"\Setup\VC", "productdir")
       
   126         self.set_macro("VSInstallDir", self.vsbase + r"\Setup\VS", "productdir")
       
   127         self.set_macro("FrameworkDir", NET_BASE, "installroot")
       
   128         try:
       
   129             if version >= 8.0:
       
   130                 self.set_macro("FrameworkSDKDir", NET_BASE,
       
   131                                "sdkinstallrootv2.0")
       
   132             else:
       
   133                 raise KeyError("sdkinstallrootv2.0")
       
   134         except KeyError as exc: #
       
   135             raise DistutilsPlatformError(
       
   136             """Python was built with Visual Studio 2008;
       
   137 extensions must be built with a compiler than can generate compatible binaries.
       
   138 Visual Studio 2008 was not found on this system. If you have Cygwin installed,
       
   139 you can try compiling with MingW32, by passing "-c mingw32" to setup.py.""")
       
   140 
       
   141         if version >= 9.0:
       
   142             self.set_macro("FrameworkVersion", self.vsbase, "clr version")
       
   143             self.set_macro("WindowsSdkDir", WINSDK_BASE, "currentinstallfolder")
       
   144         else:
       
   145             p = r"Software\Microsoft\NET Framework Setup\Product"
       
   146             for base in HKEYS:
       
   147                 try:
       
   148                     h = RegOpenKeyEx(base, p)
       
   149                 except RegError:
       
   150                     continue
       
   151                 key = RegEnumKey(h, 0)
       
   152                 d = Reg.get_value(base, r"%s\%s" % (p, key))
       
   153                 self.macros["$(FrameworkVersion)"] = d["version"]
       
   154 
       
   155     def sub(self, s):
       
   156         for k, v in self.macros.items():
       
   157             s = s.replace(k, v)
       
   158         return s
       
   159 
       
   160 def get_build_version():
       
   161     """Return the version of MSVC that was used to build Python.
       
   162 
       
   163     For Python 2.3 and up, the version number is included in
       
   164     sys.version.  For earlier versions, assume the compiler is MSVC 6.
       
   165     """
       
   166     prefix = "MSC v."
       
   167     i = sys.version.find(prefix)
       
   168     if i == -1:
       
   169         return 6
       
   170     i = i + len(prefix)
       
   171     s, rest = sys.version[i:].split(" ", 1)
       
   172     majorVersion = int(s[:-2]) - 6
       
   173     minorVersion = int(s[2:3]) / 10.0
       
   174     # I don't think paths are affected by minor version in version 6
       
   175     if majorVersion == 6:
       
   176         minorVersion = 0
       
   177     if majorVersion >= 6:
       
   178         return majorVersion + minorVersion
       
   179     # else we don't know what version of the compiler this is
       
   180     return None
       
   181 
       
   182 def normalize_and_reduce_paths(paths):
       
   183     """Return a list of normalized paths with duplicates removed.
       
   184 
       
   185     The current order of paths is maintained.
       
   186     """
       
   187     # Paths are normalized so things like:  /a and /a/ aren't both preserved.
       
   188     reduced_paths = []
       
   189     for p in paths:
       
   190         np = os.path.normpath(p)
       
   191         # XXX(nnorwitz): O(n**2), if reduced_paths gets long perhaps use a set.
       
   192         if np not in reduced_paths:
       
   193             reduced_paths.append(np)
       
   194     return reduced_paths
       
   195 
       
   196 def removeDuplicates(variable):
       
   197     """Remove duplicate values of an environment variable.
       
   198     """
       
   199     oldList = variable.split(os.pathsep)
       
   200     newList = []
       
   201     for i in oldList:
       
   202         if i not in newList:
       
   203             newList.append(i)
       
   204     newVariable = os.pathsep.join(newList)
       
   205     return newVariable
       
   206 
       
   207 def find_vcvarsall(version):
       
   208     """Find the vcvarsall.bat file
       
   209 
       
   210     At first it tries to find the productdir of VS 2008 in the registry. If
       
   211     that fails it falls back to the VS90COMNTOOLS env var.
       
   212     """
       
   213     vsbase = VS_BASE % version
       
   214     try:
       
   215         productdir = Reg.get_value(r"%s\Setup\VC" % vsbase,
       
   216                                    "productdir")
       
   217     except KeyError:
       
   218         log.debug("Unable to find productdir in registry")
       
   219         productdir = None
       
   220 
       
   221     if not productdir or not os.path.isdir(productdir):
       
   222         toolskey = "VS%0.f0COMNTOOLS" % version
       
   223         toolsdir = os.environ.get(toolskey, None)
       
   224 
       
   225         if toolsdir and os.path.isdir(toolsdir):
       
   226             productdir = os.path.join(toolsdir, os.pardir, os.pardir, "VC")
       
   227             productdir = os.path.abspath(productdir)
       
   228             if not os.path.isdir(productdir):
       
   229                 log.debug("%s is not a valid directory" % productdir)
       
   230                 return None
       
   231         else:
       
   232             log.debug("Env var %s is not set or invalid" % toolskey)
       
   233     if not productdir:
       
   234         log.debug("No productdir found")
       
   235         return None
       
   236     vcvarsall = os.path.join(productdir, "vcvarsall.bat")
       
   237     if os.path.isfile(vcvarsall):
       
   238         return vcvarsall
       
   239     log.debug("Unable to find vcvarsall.bat")
       
   240     return None
       
   241 
       
   242 def query_vcvarsall(version, arch="x86"):
       
   243     """Launch vcvarsall.bat and read the settings from its environment
       
   244     """
       
   245     vcvarsall = find_vcvarsall(version)
       
   246     interesting = set(("include", "lib", "libpath", "path"))
       
   247     result = {}
       
   248 
       
   249     if vcvarsall is None:
       
   250         raise IOError("Unable to find vcvarsall.bat")
       
   251     log.debug("Calling 'vcvarsall.bat %s' (version=%s)", arch, version)
       
   252     popen = subprocess.Popen('"%s" %s & set' % (vcvarsall, arch),
       
   253                              stdout=subprocess.PIPE,
       
   254                              stderr=subprocess.PIPE)
       
   255 
       
   256     stdout, stderr = popen.communicate()
       
   257     if popen.wait() != 0:
       
   258         raise IOError(stderr.decode("mbcs"))
       
   259 
       
   260     stdout = stdout.decode("mbcs")
       
   261     for line in stdout.split("\n"):
       
   262         line = Reg.convert_mbcs(line)
       
   263         if '=' not in line:
       
   264             continue
       
   265         line = line.strip()
       
   266         key, value = line.split('=', 1)
       
   267         key = key.lower()
       
   268         if key in interesting:
       
   269             if value.endswith(os.pathsep):
       
   270                 value = value[:-1]
       
   271             result[key] = removeDuplicates(value)
       
   272 
       
   273     if len(result) != len(interesting):
       
   274         raise ValueError(str(list(result.keys())))
       
   275 
       
   276     return result
       
   277 
       
   278 # More globals
       
   279 VERSION = get_build_version()
       
   280 if VERSION < 8.0:
       
   281     raise DistutilsPlatformError("VC %0.1f is not supported by this module" % VERSION)
       
   282 # MACROS = MacroExpander(VERSION)
       
   283 
       
   284 class MSVCCompiler(CCompiler) :
       
   285     """Concrete class that implements an interface to Microsoft Visual C++,
       
   286        as defined by the CCompiler abstract class."""
       
   287 
       
   288     compiler_type = 'msvc'
       
   289 
       
   290     # Just set this so CCompiler's constructor doesn't barf.  We currently
       
   291     # don't use the 'set_executables()' bureaucracy provided by CCompiler,
       
   292     # as it really isn't necessary for this sort of single-compiler class.
       
   293     # Would be nice to have a consistent interface with UnixCCompiler,
       
   294     # though, so it's worth thinking about.
       
   295     executables = {}
       
   296 
       
   297     # Private class data (need to distinguish C from C++ source for compiler)
       
   298     _c_extensions = ['.c']
       
   299     _cpp_extensions = ['.cc', '.cpp', '.cxx']
       
   300     _rc_extensions = ['.rc']
       
   301     _mc_extensions = ['.mc']
       
   302 
       
   303     # Needed for the filename generation methods provided by the
       
   304     # base class, CCompiler.
       
   305     src_extensions = (_c_extensions + _cpp_extensions +
       
   306                       _rc_extensions + _mc_extensions)
       
   307     res_extension = '.res'
       
   308     obj_extension = '.obj'
       
   309     static_lib_extension = '.lib'
       
   310     shared_lib_extension = '.dll'
       
   311     static_lib_format = shared_lib_format = '%s%s'
       
   312     exe_extension = '.exe'
       
   313 
       
   314     def __init__(self, verbose=0, dry_run=0, force=0):
       
   315         CCompiler.__init__ (self, verbose, dry_run, force)
       
   316         self.__version = VERSION
       
   317         self.__root = r"Software\Microsoft\VisualStudio"
       
   318         # self.__macros = MACROS
       
   319         self.__paths = []
       
   320         # target platform (.plat_name is consistent with 'bdist')
       
   321         self.plat_name = None
       
   322         self.__arch = None # deprecated name
       
   323         self.initialized = False
       
   324 
       
   325     def initialize(self, plat_name=None):
       
   326         # multi-init means we would need to check platform same each time...
       
   327         assert not self.initialized, "don't init multiple times"
       
   328         if plat_name is None:
       
   329             plat_name = get_platform()
       
   330         # sanity check for platforms to prevent obscure errors later.
       
   331         ok_plats = 'win32', 'win-amd64', 'win-ia64'
       
   332         if plat_name not in ok_plats:
       
   333             raise DistutilsPlatformError("--plat-name must be one of %s" %
       
   334                                          (ok_plats,))
       
   335 
       
   336         if "DISTUTILS_USE_SDK" in os.environ and "MSSdk" in os.environ and self.find_exe("cl.exe"):
       
   337             # Assume that the SDK set up everything alright; don't try to be
       
   338             # smarter
       
   339             self.cc = "cl.exe"
       
   340             self.linker = "link.exe"
       
   341             self.lib = "lib.exe"
       
   342             self.rc = "rc.exe"
       
   343             self.mc = "mc.exe"
       
   344         else:
       
   345             # On x86, 'vcvars32.bat amd64' creates an env that doesn't work;
       
   346             # to cross compile, you use 'x86_amd64'.
       
   347             # On AMD64, 'vcvars32.bat amd64' is a native build env; to cross
       
   348             # compile use 'x86' (ie, it runs the x86 compiler directly)
       
   349             # No idea how itanium handles this, if at all.
       
   350             if plat_name == get_platform() or plat_name == 'win32':
       
   351                 # native build or cross-compile to win32
       
   352                 plat_spec = PLAT_TO_VCVARS[plat_name]
       
   353             else:
       
   354                 # cross compile from win32 -> some 64bit
       
   355                 plat_spec = PLAT_TO_VCVARS[get_platform()] + '_' + \
       
   356                             PLAT_TO_VCVARS[plat_name]
       
   357 
       
   358             vc_env = query_vcvarsall(VERSION, plat_spec)
       
   359 
       
   360             # take care to only use strings in the environment.
       
   361             self.__paths = vc_env['path'].encode('mbcs').split(os.pathsep)
       
   362             os.environ['lib'] = vc_env['lib'].encode('mbcs')
       
   363             os.environ['include'] = vc_env['include'].encode('mbcs')
       
   364 
       
   365             if len(self.__paths) == 0:
       
   366                 raise DistutilsPlatformError("Python was built with %s, "
       
   367                        "and extensions need to be built with the same "
       
   368                        "version of the compiler, but it isn't installed."
       
   369                        % self.__product)
       
   370 
       
   371             self.cc = self.find_exe("cl.exe")
       
   372             self.linker = self.find_exe("link.exe")
       
   373             self.lib = self.find_exe("lib.exe")
       
   374             self.rc = self.find_exe("rc.exe")   # resource compiler
       
   375             self.mc = self.find_exe("mc.exe")   # message compiler
       
   376             #self.set_path_env_var('lib')
       
   377             #self.set_path_env_var('include')
       
   378 
       
   379         # extend the MSVC path with the current path
       
   380         try:
       
   381             for p in os.environ['path'].split(';'):
       
   382                 self.__paths.append(p)
       
   383         except KeyError:
       
   384             pass
       
   385         self.__paths = normalize_and_reduce_paths(self.__paths)
       
   386         os.environ['path'] = ";".join(self.__paths)
       
   387 
       
   388         self.preprocess_options = None
       
   389         if self.__arch == "x86":
       
   390             self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3',
       
   391                                      '/DNDEBUG']
       
   392             self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3',
       
   393                                           '/Z7', '/D_DEBUG']
       
   394         else:
       
   395             # Win64
       
   396             self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GS-' ,
       
   397                                      '/DNDEBUG']
       
   398             self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GS-',
       
   399                                           '/Z7', '/D_DEBUG']
       
   400 
       
   401         self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO']
       
   402         if self.__version >= 7:
       
   403             self.ldflags_shared_debug = [
       
   404                 '/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG', '/pdb:None'
       
   405                 ]
       
   406         self.ldflags_static = [ '/nologo']
       
   407 
       
   408         self.initialized = True
       
   409 
       
   410     # -- Worker methods ------------------------------------------------
       
   411 
       
   412     def object_filenames(self,
       
   413                          source_filenames,
       
   414                          strip_dir=0,
       
   415                          output_dir=''):
       
   416         # Copied from ccompiler.py, extended to return .res as 'object'-file
       
   417         # for .rc input file
       
   418         if output_dir is None: output_dir = ''
       
   419         obj_names = []
       
   420         for src_name in source_filenames:
       
   421             (base, ext) = os.path.splitext (src_name)
       
   422             base = os.path.splitdrive(base)[1] # Chop off the drive
       
   423             base = base[os.path.isabs(base):]  # If abs, chop off leading /
       
   424             if ext not in self.src_extensions:
       
   425                 # Better to raise an exception instead of silently continuing
       
   426                 # and later complain about sources and targets having
       
   427                 # different lengths
       
   428                 raise CompileError ("Don't know how to compile %s" % src_name)
       
   429             if strip_dir:
       
   430                 base = os.path.basename (base)
       
   431             if ext in self._rc_extensions:
       
   432                 obj_names.append (os.path.join (output_dir,
       
   433                                                 base + self.res_extension))
       
   434             elif ext in self._mc_extensions:
       
   435                 obj_names.append (os.path.join (output_dir,
       
   436                                                 base + self.res_extension))
       
   437             else:
       
   438                 obj_names.append (os.path.join (output_dir,
       
   439                                                 base + self.obj_extension))
       
   440         return obj_names
       
   441 
       
   442 
       
   443     def compile(self, sources,
       
   444                 output_dir=None, macros=None, include_dirs=None, debug=0,
       
   445                 extra_preargs=None, extra_postargs=None, depends=None):
       
   446 
       
   447         if not self.initialized:
       
   448             self.initialize()
       
   449         compile_info = self._setup_compile(output_dir, macros, include_dirs,
       
   450                                            sources, depends, extra_postargs)
       
   451         macros, objects, extra_postargs, pp_opts, build = compile_info
       
   452 
       
   453         compile_opts = extra_preargs or []
       
   454         compile_opts.append ('/c')
       
   455         if debug:
       
   456             compile_opts.extend(self.compile_options_debug)
       
   457         else:
       
   458             compile_opts.extend(self.compile_options)
       
   459 
       
   460         for obj in objects:
       
   461             try:
       
   462                 src, ext = build[obj]
       
   463             except KeyError:
       
   464                 continue
       
   465             if debug:
       
   466                 # pass the full pathname to MSVC in debug mode,
       
   467                 # this allows the debugger to find the source file
       
   468                 # without asking the user to browse for it
       
   469                 src = os.path.abspath(src)
       
   470 
       
   471             if ext in self._c_extensions:
       
   472                 input_opt = "/Tc" + src
       
   473             elif ext in self._cpp_extensions:
       
   474                 input_opt = "/Tp" + src
       
   475             elif ext in self._rc_extensions:
       
   476                 # compile .RC to .RES file
       
   477                 input_opt = src
       
   478                 output_opt = "/fo" + obj
       
   479                 try:
       
   480                     self.spawn([self.rc] + pp_opts +
       
   481                                [output_opt] + [input_opt])
       
   482                 except DistutilsExecError as msg:
       
   483                     raise CompileError(msg)
       
   484                 continue
       
   485             elif ext in self._mc_extensions:
       
   486                 # Compile .MC to .RC file to .RES file.
       
   487                 #   * '-h dir' specifies the directory for the
       
   488                 #     generated include file
       
   489                 #   * '-r dir' specifies the target directory of the
       
   490                 #     generated RC file and the binary message resource
       
   491                 #     it includes
       
   492                 #
       
   493                 # For now (since there are no options to change this),
       
   494                 # we use the source-directory for the include file and
       
   495                 # the build directory for the RC file and message
       
   496                 # resources. This works at least for win32all.
       
   497                 h_dir = os.path.dirname(src)
       
   498                 rc_dir = os.path.dirname(obj)
       
   499                 try:
       
   500                     # first compile .MC to .RC and .H file
       
   501                     self.spawn([self.mc] +
       
   502                                ['-h', h_dir, '-r', rc_dir] + [src])
       
   503                     base, _ = os.path.splitext (os.path.basename (src))
       
   504                     rc_file = os.path.join (rc_dir, base + '.rc')
       
   505                     # then compile .RC to .RES file
       
   506                     self.spawn([self.rc] +
       
   507                                ["/fo" + obj] + [rc_file])
       
   508 
       
   509                 except DistutilsExecError as msg:
       
   510                     raise CompileError(msg)
       
   511                 continue
       
   512             else:
       
   513                 # how to handle this file?
       
   514                 raise CompileError("Don't know how to compile %s to %s"
       
   515                                    % (src, obj))
       
   516 
       
   517             output_opt = "/Fo" + obj
       
   518             try:
       
   519                 self.spawn([self.cc] + compile_opts + pp_opts +
       
   520                            [input_opt, output_opt] +
       
   521                            extra_postargs)
       
   522             except DistutilsExecError as msg:
       
   523                 raise CompileError(msg)
       
   524 
       
   525         return objects
       
   526 
       
   527 
       
   528     def create_static_lib(self,
       
   529                           objects,
       
   530                           output_libname,
       
   531                           output_dir=None,
       
   532                           debug=0,
       
   533                           target_lang=None):
       
   534 
       
   535         if not self.initialized:
       
   536             self.initialize()
       
   537         (objects, output_dir) = self._fix_object_args(objects, output_dir)
       
   538         output_filename = self.library_filename(output_libname,
       
   539                                                 output_dir=output_dir)
       
   540 
       
   541         if self._need_link(objects, output_filename):
       
   542             lib_args = objects + ['/OUT:' + output_filename]
       
   543             if debug:
       
   544                 pass # XXX what goes here?
       
   545             try:
       
   546                 self.spawn([self.lib] + lib_args)
       
   547             except DistutilsExecError as msg:
       
   548                 raise LibError(msg)
       
   549         else:
       
   550             log.debug("skipping %s (up-to-date)", output_filename)
       
   551 
       
   552 
       
   553     def link(self,
       
   554              target_desc,
       
   555              objects,
       
   556              output_filename,
       
   557              output_dir=None,
       
   558              libraries=None,
       
   559              library_dirs=None,
       
   560              runtime_library_dirs=None,
       
   561              export_symbols=None,
       
   562              debug=0,
       
   563              extra_preargs=None,
       
   564              extra_postargs=None,
       
   565              build_temp=None,
       
   566              target_lang=None):
       
   567 
       
   568         if not self.initialized:
       
   569             self.initialize()
       
   570         (objects, output_dir) = self._fix_object_args(objects, output_dir)
       
   571         fixed_args = self._fix_lib_args(libraries, library_dirs,
       
   572                                         runtime_library_dirs)
       
   573         (libraries, library_dirs, runtime_library_dirs) = fixed_args
       
   574 
       
   575         if runtime_library_dirs:
       
   576             self.warn ("I don't know what to do with 'runtime_library_dirs': "
       
   577                        + str (runtime_library_dirs))
       
   578 
       
   579         lib_opts = gen_lib_options(self,
       
   580                                    library_dirs, runtime_library_dirs,
       
   581                                    libraries)
       
   582         if output_dir is not None:
       
   583             output_filename = os.path.join(output_dir, output_filename)
       
   584 
       
   585         if self._need_link(objects, output_filename):
       
   586             if target_desc == CCompiler.EXECUTABLE:
       
   587                 if debug:
       
   588                     ldflags = self.ldflags_shared_debug[1:]
       
   589                 else:
       
   590                     ldflags = self.ldflags_shared[1:]
       
   591             else:
       
   592                 if debug:
       
   593                     ldflags = self.ldflags_shared_debug
       
   594                 else:
       
   595                     ldflags = self.ldflags_shared
       
   596 
       
   597             export_opts = []
       
   598             for sym in (export_symbols or []):
       
   599                 export_opts.append("/EXPORT:" + sym)
       
   600 
       
   601             ld_args = (ldflags + lib_opts + export_opts +
       
   602                        objects + ['/OUT:' + output_filename])
       
   603 
       
   604             # The MSVC linker generates .lib and .exp files, which cannot be
       
   605             # suppressed by any linker switches. The .lib files may even be
       
   606             # needed! Make sure they are generated in the temporary build
       
   607             # directory. Since they have different names for debug and release
       
   608             # builds, they can go into the same directory.
       
   609             build_temp = os.path.dirname(objects[0])
       
   610             if export_symbols is not None:
       
   611                 (dll_name, dll_ext) = os.path.splitext(
       
   612                     os.path.basename(output_filename))
       
   613                 implib_file = os.path.join(
       
   614                     build_temp,
       
   615                     self.library_filename(dll_name))
       
   616                 ld_args.append ('/IMPLIB:' + implib_file)
       
   617 
       
   618             # Embedded manifests are recommended - see MSDN article titled
       
   619             # "How to: Embed a Manifest Inside a C/C++ Application"
       
   620             # (currently at http://msdn2.microsoft.com/en-us/library/ms235591(VS.80).aspx)
       
   621             # Ask the linker to generate the manifest in the temp dir, so
       
   622             # we can embed it later.
       
   623             temp_manifest = os.path.join(
       
   624                     build_temp,
       
   625                     os.path.basename(output_filename) + ".manifest")
       
   626             ld_args.append('/MANIFESTFILE:' + temp_manifest)
       
   627 
       
   628             if extra_preargs:
       
   629                 ld_args[:0] = extra_preargs
       
   630             if extra_postargs:
       
   631                 ld_args.extend(extra_postargs)
       
   632 
       
   633             self.mkpath(os.path.dirname(output_filename))
       
   634             try:
       
   635                 self.spawn([self.linker] + ld_args)
       
   636             except DistutilsExecError as msg:
       
   637                 raise LinkError(msg)
       
   638 
       
   639             # embed the manifest
       
   640             # XXX - this is somewhat fragile - if mt.exe fails, distutils
       
   641             # will still consider the DLL up-to-date, but it will not have a
       
   642             # manifest.  Maybe we should link to a temp file?  OTOH, that
       
   643             # implies a build environment error that shouldn't go undetected.
       
   644             mfid = 1 if target_desc == CCompiler.EXECUTABLE else 2
       
   645             out_arg = '-outputresource:%s;%s' % (output_filename, mfid)
       
   646             try:
       
   647                 self.spawn(['mt.exe', '-nologo', '-manifest',
       
   648                             temp_manifest, out_arg])
       
   649             except DistutilsExecError as msg:
       
   650                 raise LinkError(msg)
       
   651         else:
       
   652             log.debug("skipping %s (up-to-date)", output_filename)
       
   653 
       
   654 
       
   655     # -- Miscellaneous methods -----------------------------------------
       
   656     # These are all used by the 'gen_lib_options() function, in
       
   657     # ccompiler.py.
       
   658 
       
   659     def library_dir_option(self, dir):
       
   660         return "/LIBPATH:" + dir
       
   661 
       
   662     def runtime_library_dir_option(self, dir):
       
   663         raise DistutilsPlatformError(
       
   664               "don't know how to set runtime library search path for MSVC++")
       
   665 
       
   666     def library_option(self, lib):
       
   667         return self.library_filename(lib)
       
   668 
       
   669 
       
   670     def find_library_file(self, dirs, lib, debug=0):
       
   671         # Prefer a debugging library if found (and requested), but deal
       
   672         # with it if we don't have one.
       
   673         if debug:
       
   674             try_names = [lib + "_d", lib]
       
   675         else:
       
   676             try_names = [lib]
       
   677         for dir in dirs:
       
   678             for name in try_names:
       
   679                 libfile = os.path.join(dir, self.library_filename (name))
       
   680                 if os.path.exists(libfile):
       
   681                     return libfile
       
   682         else:
       
   683             # Oops, didn't find it in *any* of 'dirs'
       
   684             return None
       
   685 
       
   686     # Helper methods for using the MSVC registry settings
       
   687 
       
   688     def find_exe(self, exe):
       
   689         """Return path to an MSVC executable program.
       
   690 
       
   691         Tries to find the program in several places: first, one of the
       
   692         MSVC program search paths from the registry; next, the directories
       
   693         in the PATH environment variable.  If any of those work, return an
       
   694         absolute path that is known to exist.  If none of them work, just
       
   695         return the original program name, 'exe'.
       
   696         """
       
   697         for p in self.__paths:
       
   698             fn = os.path.join(os.path.abspath(p), exe)
       
   699             if os.path.isfile(fn):
       
   700                 return fn
       
   701 
       
   702         # didn't find it; try existing path
       
   703         for p in os.environ['Path'].split(';'):
       
   704             fn = os.path.join(os.path.abspath(p),exe)
       
   705             if os.path.isfile(fn):
       
   706                 return fn
       
   707 
       
   708         return exe