Home | History | Annotate | Download | only in distutils
      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$"
     16 
     17 import os
     18 import subprocess
     19 import sys
     20 import re
     21 
     22 from distutils.errors import (DistutilsExecError, DistutilsPlatformError,
     23                               CompileError, LibError, LinkError)
     24 from distutils.ccompiler import CCompiler, gen_lib_options
     25 from distutils import log
     26 from distutils.util import get_platform
     27 
     28 import _winreg
     29 
     30 RegOpenKeyEx = _winreg.OpenKeyEx
     31 RegEnumKey = _winreg.EnumKey
     32 RegEnumValue = _winreg.EnumValue
     33 RegError = _winreg.error
     34 
     35 HKEYS = (_winreg.HKEY_USERS,
     36          _winreg.HKEY_CURRENT_USER,
     37          _winreg.HKEY_LOCAL_MACHINE,
     38          _winreg.HKEY_CLASSES_ROOT)
     39 
     40 NATIVE_WIN64 = (sys.platform == 'win32' and sys.maxsize > 2**32)
     41 if NATIVE_WIN64:
     42     # Visual C++ is a 32-bit application, so we need to look in

     43     # the corresponding registry branch, if we're running a

     44     # 64-bit Python on Win64

     45     VS_BASE = r"Software\Wow6432Node\Microsoft\VisualStudio\%0.1f"
     46     VSEXPRESS_BASE = r"Software\Wow6432Node\Microsoft\VCExpress\%0.1f"
     47     WINSDK_BASE = r"Software\Wow6432Node\Microsoft\Microsoft SDKs\Windows"
     48     NET_BASE = r"Software\Wow6432Node\Microsoft\.NETFramework"
     49 else:
     50     VS_BASE = r"Software\Microsoft\VisualStudio\%0.1f"
     51     VSEXPRESS_BASE = r"Software\Microsoft\VCExpress\%0.1f"
     52     WINSDK_BASE = r"Software\Microsoft\Microsoft SDKs\Windows"
     53     NET_BASE = r"Software\Microsoft\.NETFramework"
     54 
     55 # A map keyed by get_platform() return values to values accepted by

     56 # 'vcvarsall.bat'.  Note a cross-compile may combine these (eg, 'x86_amd64' is

     57 # the param to cross-compile on x86 targetting amd64.)

     58 PLAT_TO_VCVARS = {
     59     'win32' : 'x86',
     60     'win-amd64' : 'amd64',
     61     'win-ia64' : 'ia64',
     62 }
     63 
     64 class Reg:
     65     """Helper class to read values from the registry
     66     """
     67 
     68     def get_value(cls, path, key):
     69         for base in HKEYS:
     70             d = cls.read_values(base, path)
     71             if d and key in d:
     72                 return d[key]
     73         raise KeyError(key)
     74     get_value = classmethod(get_value)
     75 
     76     def read_keys(cls, base, key):
     77         """Return list of registry keys."""
     78         try:
     79             handle = RegOpenKeyEx(base, key)
     80         except RegError:
     81             return None
     82         L = []
     83         i = 0
     84         while True:
     85             try:
     86                 k = RegEnumKey(handle, i)
     87             except RegError:
     88                 break
     89             L.append(k)
     90             i += 1
     91         return L
     92     read_keys = classmethod(read_keys)
     93 
     94     def read_values(cls, base, key):
     95         """Return dict of registry keys and values.
     96 
     97         All names are converted to lowercase.
     98         """
     99         try:
    100             handle = RegOpenKeyEx(base, key)
    101         except RegError:
    102             return None
    103         d = {}
    104         i = 0
    105         while True:
    106             try:
    107                 name, value, type = RegEnumValue(handle, i)
    108             except RegError:
    109                 break
    110             name = name.lower()
    111             d[cls.convert_mbcs(name)] = cls.convert_mbcs(value)
    112             i += 1
    113         return d
    114     read_values = classmethod(read_values)
    115 
    116     def convert_mbcs(s):
    117         dec = getattr(s, "decode", None)
    118         if dec is not None:
    119             try:
    120                 s = dec("mbcs")
    121             except UnicodeError:
    122                 pass
    123         return s
    124     convert_mbcs = staticmethod(convert_mbcs)
    125 
    126 class MacroExpander:
    127 
    128     def __init__(self, version):
    129         self.macros = {}
    130         self.vsbase = VS_BASE % version
    131         self.load_macros(version)
    132 
    133     def set_macro(self, macro, path, key):
    134         self.macros["$(%s)" % macro] = Reg.get_value(path, key)
    135 
    136     def load_macros(self, version):
    137         self.set_macro("VCInstallDir", self.vsbase + r"\Setup\VC", "productdir")
    138         self.set_macro("VSInstallDir", self.vsbase + r"\Setup\VS", "productdir")
    139         self.set_macro("FrameworkDir", NET_BASE, "installroot")
    140         try:
    141             if version >= 8.0:
    142                 self.set_macro("FrameworkSDKDir", NET_BASE,
    143                                "sdkinstallrootv2.0")
    144             else:
    145                 raise KeyError("sdkinstallrootv2.0")
    146         except KeyError:
    147             raise DistutilsPlatformError(
    148             """Python was built with Visual Studio 2008;
    149 extensions must be built with a compiler than can generate compatible binaries.
    150 Visual Studio 2008 was not found on this system. If you have Cygwin installed,
    151 you can try compiling with MingW32, by passing "-c mingw32" to setup.py.""")
    152 
    153         if version >= 9.0:
    154             self.set_macro("FrameworkVersion", self.vsbase, "clr version")
    155             self.set_macro("WindowsSdkDir", WINSDK_BASE, "currentinstallfolder")
    156         else:
    157             p = r"Software\Microsoft\NET Framework Setup\Product"
    158             for base in HKEYS:
    159                 try:
    160                     h = RegOpenKeyEx(base, p)
    161                 except RegError:
    162                     continue
    163                 key = RegEnumKey(h, 0)
    164                 d = Reg.get_value(base, r"%s\%s" % (p, key))
    165                 self.macros["$(FrameworkVersion)"] = d["version"]
    166 
    167     def sub(self, s):
    168         for k, v in self.macros.items():
    169             s = s.replace(k, v)
    170         return s
    171 
    172 def get_build_version():
    173     """Return the version of MSVC that was used to build Python.
    174 
    175     For Python 2.3 and up, the version number is included in
    176     sys.version.  For earlier versions, assume the compiler is MSVC 6.
    177     """
    178     prefix = "MSC v."
    179     i = sys.version.find(prefix)
    180     if i == -1:
    181         return 6
    182     i = i + len(prefix)
    183     s, rest = sys.version[i:].split(" ", 1)
    184     majorVersion = int(s[:-2]) - 6
    185     minorVersion = int(s[2:3]) / 10.0
    186     # I don't think paths are affected by minor version in version 6

    187     if majorVersion == 6:
    188         minorVersion = 0
    189     if majorVersion >= 6:
    190         return majorVersion + minorVersion
    191     # else we don't know what version of the compiler this is

    192     return None
    193 
    194 def normalize_and_reduce_paths(paths):
    195     """Return a list of normalized paths with duplicates removed.
    196 
    197     The current order of paths is maintained.
    198     """
    199     # Paths are normalized so things like:  /a and /a/ aren't both preserved.

    200     reduced_paths = []
    201     for p in paths:
    202         np = os.path.normpath(p)
    203         # XXX(nnorwitz): O(n**2), if reduced_paths gets long perhaps use a set.

    204         if np not in reduced_paths:
    205             reduced_paths.append(np)
    206     return reduced_paths
    207 
    208 def removeDuplicates(variable):
    209     """Remove duplicate values of an environment variable.
    210     """
    211     oldList = variable.split(os.pathsep)
    212     newList = []
    213     for i in oldList:
    214         if i not in newList:
    215             newList.append(i)
    216     newVariable = os.pathsep.join(newList)
    217     return newVariable
    218 
    219 def find_vcvarsall(version):
    220     """Find the vcvarsall.bat file
    221 
    222     At first it tries to find the productdir of VS 2008 in the registry. If
    223     that fails it falls back to the VS90COMNTOOLS env var.
    224     """
    225     vsbase = VS_BASE % version
    226     try:
    227         productdir = Reg.get_value(r"%s\Setup\VC" % vsbase,
    228                                    "productdir")
    229     except KeyError:
    230         productdir = None
    231 
    232     # trying Express edition

    233     if productdir is None:
    234         vsbase = VSEXPRESS_BASE % version
    235         try:
    236             productdir = Reg.get_value(r"%s\Setup\VC" % vsbase,
    237                                        "productdir")
    238         except KeyError:
    239             productdir = None
    240             log.debug("Unable to find productdir in registry")
    241 
    242     if not productdir or not os.path.isdir(productdir):
    243         toolskey = "VS%0.f0COMNTOOLS" % version
    244         toolsdir = os.environ.get(toolskey, None)
    245 
    246         if toolsdir and os.path.isdir(toolsdir):
    247             productdir = os.path.join(toolsdir, os.pardir, os.pardir, "VC")
    248             productdir = os.path.abspath(productdir)
    249             if not os.path.isdir(productdir):
    250                 log.debug("%s is not a valid directory" % productdir)
    251                 return None
    252         else:
    253             log.debug("Env var %s is not set or invalid" % toolskey)
    254     if not productdir:
    255         log.debug("No productdir found")
    256         return None
    257     vcvarsall = os.path.join(productdir, "vcvarsall.bat")
    258     if os.path.isfile(vcvarsall):
    259         return vcvarsall
    260     log.debug("Unable to find vcvarsall.bat")
    261     return None
    262 
    263 def query_vcvarsall(version, arch="x86"):
    264     """Launch vcvarsall.bat and read the settings from its environment
    265     """
    266     vcvarsall = find_vcvarsall(version)
    267     interesting = set(("include", "lib", "libpath", "path"))
    268     result = {}
    269 
    270     if vcvarsall is None:
    271         raise DistutilsPlatformError("Unable to find vcvarsall.bat")
    272     log.debug("Calling 'vcvarsall.bat %s' (version=%s)", arch, version)
    273     popen = subprocess.Popen('"%s" %s & set' % (vcvarsall, arch),
    274                              stdout=subprocess.PIPE,
    275                              stderr=subprocess.PIPE)
    276     try:
    277         stdout, stderr = popen.communicate()
    278         if popen.wait() != 0:
    279             raise DistutilsPlatformError(stderr.decode("mbcs"))
    280 
    281         stdout = stdout.decode("mbcs")
    282         for line in stdout.split("\n"):
    283             line = Reg.convert_mbcs(line)
    284             if '=' not in line:
    285                 continue
    286             line = line.strip()
    287             key, value = line.split('=', 1)
    288             key = key.lower()
    289             if key in interesting:
    290                 if value.endswith(os.pathsep):
    291                     value = value[:-1]
    292                 result[key] = removeDuplicates(value)
    293 
    294     finally:
    295         popen.stdout.close()
    296         popen.stderr.close()
    297 
    298     if len(result) != len(interesting):
    299         raise ValueError(str(list(result.keys())))
    300 
    301     return result
    302 
    303 # More globals

    304 VERSION = get_build_version()
    305 if VERSION < 8.0:
    306     raise DistutilsPlatformError("VC %0.1f is not supported by this module" % VERSION)
    307 # MACROS = MacroExpander(VERSION)

    308 
    309 class MSVCCompiler(CCompiler) :
    310     """Concrete class that implements an interface to Microsoft Visual C++,
    311        as defined by the CCompiler abstract class."""
    312 
    313     compiler_type = 'msvc'
    314 
    315     # Just set this so CCompiler's constructor doesn't barf.  We currently

    316     # don't use the 'set_executables()' bureaucracy provided by CCompiler,

    317     # as it really isn't necessary for this sort of single-compiler class.

    318     # Would be nice to have a consistent interface with UnixCCompiler,

    319     # though, so it's worth thinking about.

    320     executables = {}
    321 
    322     # Private class data (need to distinguish C from C++ source for compiler)

    323     _c_extensions = ['.c']
    324     _cpp_extensions = ['.cc', '.cpp', '.cxx']
    325     _rc_extensions = ['.rc']
    326     _mc_extensions = ['.mc']
    327 
    328     # Needed for the filename generation methods provided by the

    329     # base class, CCompiler.

    330     src_extensions = (_c_extensions + _cpp_extensions +
    331                       _rc_extensions + _mc_extensions)
    332     res_extension = '.res'
    333     obj_extension = '.obj'
    334     static_lib_extension = '.lib'
    335     shared_lib_extension = '.dll'
    336     static_lib_format = shared_lib_format = '%s%s'
    337     exe_extension = '.exe'
    338 
    339     def __init__(self, verbose=0, dry_run=0, force=0):
    340         CCompiler.__init__ (self, verbose, dry_run, force)
    341         self.__version = VERSION
    342         self.__root = r"Software\Microsoft\VisualStudio"
    343         # self.__macros = MACROS

    344         self.__paths = []
    345         # target platform (.plat_name is consistent with 'bdist')

    346         self.plat_name = None
    347         self.__arch = None # deprecated name

    348         self.initialized = False
    349 
    350     def initialize(self, plat_name=None):
    351         # multi-init means we would need to check platform same each time...

    352         assert not self.initialized, "don't init multiple times"
    353         if plat_name is None:
    354             plat_name = get_platform()
    355         # sanity check for platforms to prevent obscure errors later.

    356         ok_plats = 'win32', 'win-amd64', 'win-ia64'
    357         if plat_name not in ok_plats:
    358             raise DistutilsPlatformError("--plat-name must be one of %s" %
    359                                          (ok_plats,))
    360 
    361         if "DISTUTILS_USE_SDK" in os.environ and "MSSdk" in os.environ and self.find_exe("cl.exe"):
    362             # Assume that the SDK set up everything alright; don't try to be

    363             # smarter

    364             self.cc = "cl.exe"
    365             self.linker = "link.exe"
    366             self.lib = "lib.exe"
    367             self.rc = "rc.exe"
    368             self.mc = "mc.exe"
    369         else:
    370             # On x86, 'vcvars32.bat amd64' creates an env that doesn't work;

    371             # to cross compile, you use 'x86_amd64'.

    372             # On AMD64, 'vcvars32.bat amd64' is a native build env; to cross

    373             # compile use 'x86' (ie, it runs the x86 compiler directly)

    374             # No idea how itanium handles this, if at all.

    375             if plat_name == get_platform() or plat_name == 'win32':
    376                 # native build or cross-compile to win32

    377                 plat_spec = PLAT_TO_VCVARS[plat_name]
    378             else:
    379                 # cross compile from win32 -> some 64bit

    380                 plat_spec = PLAT_TO_VCVARS[get_platform()] + '_' + \
    381                             PLAT_TO_VCVARS[plat_name]
    382 
    383             vc_env = query_vcvarsall(VERSION, plat_spec)
    384 
    385             # take care to only use strings in the environment.

    386             self.__paths = vc_env['path'].encode('mbcs').split(os.pathsep)
    387             os.environ['lib'] = vc_env['lib'].encode('mbcs')
    388             os.environ['include'] = vc_env['include'].encode('mbcs')
    389 
    390             if len(self.__paths) == 0:
    391                 raise DistutilsPlatformError("Python was built with %s, "
    392                        "and extensions need to be built with the same "
    393                        "version of the compiler, but it isn't installed."
    394                        % self.__product)
    395 
    396             self.cc = self.find_exe("cl.exe")
    397             self.linker = self.find_exe("link.exe")
    398             self.lib = self.find_exe("lib.exe")
    399             self.rc = self.find_exe("rc.exe")   # resource compiler

    400             self.mc = self.find_exe("mc.exe")   # message compiler

    401             #self.set_path_env_var('lib')

    402             #self.set_path_env_var('include')

    403 
    404         # extend the MSVC path with the current path

    405         try:
    406             for p in os.environ['path'].split(';'):
    407                 self.__paths.append(p)
    408         except KeyError:
    409             pass
    410         self.__paths = normalize_and_reduce_paths(self.__paths)
    411         os.environ['path'] = ";".join(self.__paths)
    412 
    413         self.preprocess_options = None
    414         if self.__arch == "x86":
    415             self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3',
    416                                      '/DNDEBUG']
    417             self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3',
    418                                           '/Z7', '/D_DEBUG']
    419         else:
    420             # Win64

    421             self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GS-' ,
    422                                      '/DNDEBUG']
    423             self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GS-',
    424                                           '/Z7', '/D_DEBUG']
    425 
    426         self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO']
    427         if self.__version >= 7:
    428             self.ldflags_shared_debug = [
    429                 '/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG', '/pdb:None'
    430                 ]
    431         self.ldflags_static = [ '/nologo']
    432 
    433         self.initialized = True
    434 
    435     # -- Worker methods ------------------------------------------------

    436 
    437     def object_filenames(self,
    438                          source_filenames,
    439                          strip_dir=0,
    440                          output_dir=''):
    441         # Copied from ccompiler.py, extended to return .res as 'object'-file

    442         # for .rc input file

    443         if output_dir is None: output_dir = ''
    444         obj_names = []
    445         for src_name in source_filenames:
    446             (base, ext) = os.path.splitext (src_name)
    447             base = os.path.splitdrive(base)[1] # Chop off the drive

    448             base = base[os.path.isabs(base):]  # If abs, chop off leading /

    449             if ext not in self.src_extensions:
    450                 # Better to raise an exception instead of silently continuing

    451                 # and later complain about sources and targets having

    452                 # different lengths

    453                 raise CompileError ("Don't know how to compile %s" % src_name)
    454             if strip_dir:
    455                 base = os.path.basename (base)
    456             if ext in self._rc_extensions:
    457                 obj_names.append (os.path.join (output_dir,
    458                                                 base + self.res_extension))
    459             elif ext in self._mc_extensions:
    460                 obj_names.append (os.path.join (output_dir,
    461                                                 base + self.res_extension))
    462             else:
    463                 obj_names.append (os.path.join (output_dir,
    464                                                 base + self.obj_extension))
    465         return obj_names
    466 
    467 
    468     def compile(self, sources,
    469                 output_dir=None, macros=None, include_dirs=None, debug=0,
    470                 extra_preargs=None, extra_postargs=None, depends=None):
    471 
    472         if not self.initialized:
    473             self.initialize()
    474         compile_info = self._setup_compile(output_dir, macros, include_dirs,
    475                                            sources, depends, extra_postargs)
    476         macros, objects, extra_postargs, pp_opts, build = compile_info
    477 
    478         compile_opts = extra_preargs or []
    479         compile_opts.append ('/c')
    480         if debug:
    481             compile_opts.extend(self.compile_options_debug)
    482         else:
    483             compile_opts.extend(self.compile_options)
    484 
    485         for obj in objects:
    486             try:
    487                 src, ext = build[obj]
    488             except KeyError:
    489                 continue
    490             if debug:
    491                 # pass the full pathname to MSVC in debug mode,

    492                 # this allows the debugger to find the source file

    493                 # without asking the user to browse for it

    494                 src = os.path.abspath(src)
    495 
    496             if ext in self._c_extensions:
    497                 input_opt = "/Tc" + src
    498             elif ext in self._cpp_extensions:
    499                 input_opt = "/Tp" + src
    500             elif ext in self._rc_extensions:
    501                 # compile .RC to .RES file

    502                 input_opt = src
    503                 output_opt = "/fo" + obj
    504                 try:
    505                     self.spawn([self.rc] + pp_opts +
    506                                [output_opt] + [input_opt])
    507                 except DistutilsExecError, msg:
    508                     raise CompileError(msg)
    509                 continue
    510             elif ext in self._mc_extensions:
    511                 # Compile .MC to .RC file to .RES file.

    512                 #   * '-h dir' specifies the directory for the

    513                 #     generated include file

    514                 #   * '-r dir' specifies the target directory of the

    515                 #     generated RC file and the binary message resource

    516                 #     it includes

    517                 #

    518                 # For now (since there are no options to change this),

    519                 # we use the source-directory for the include file and

    520                 # the build directory for the RC file and message

    521                 # resources. This works at least for win32all.

    522                 h_dir = os.path.dirname(src)
    523                 rc_dir = os.path.dirname(obj)
    524                 try:
    525                     # first compile .MC to .RC and .H file

    526                     self.spawn([self.mc] +
    527                                ['-h', h_dir, '-r', rc_dir] + [src])
    528                     base, _ = os.path.splitext (os.path.basename (src))
    529                     rc_file = os.path.join (rc_dir, base + '.rc')
    530                     # then compile .RC to .RES file

    531                     self.spawn([self.rc] +
    532                                ["/fo" + obj] + [rc_file])
    533 
    534                 except DistutilsExecError, msg:
    535                     raise CompileError(msg)
    536                 continue
    537             else:
    538                 # how to handle this file?

    539                 raise CompileError("Don't know how to compile %s to %s"
    540                                    % (src, obj))
    541 
    542             output_opt = "/Fo" + obj
    543             try:
    544                 self.spawn([self.cc] + compile_opts + pp_opts +
    545                            [input_opt, output_opt] +
    546                            extra_postargs)
    547             except DistutilsExecError, msg:
    548                 raise CompileError(msg)
    549 
    550         return objects
    551 
    552 
    553     def create_static_lib(self,
    554                           objects,
    555                           output_libname,
    556                           output_dir=None,
    557                           debug=0,
    558                           target_lang=None):
    559 
    560         if not self.initialized:
    561             self.initialize()
    562         (objects, output_dir) = self._fix_object_args(objects, output_dir)
    563         output_filename = self.library_filename(output_libname,
    564                                                 output_dir=output_dir)
    565 
    566         if self._need_link(objects, output_filename):
    567             lib_args = objects + ['/OUT:' + output_filename]
    568             if debug:
    569                 pass # XXX what goes here?

    570             try:
    571                 self.spawn([self.lib] + lib_args)
    572             except DistutilsExecError, msg:
    573                 raise LibError(msg)
    574         else:
    575             log.debug("skipping %s (up-to-date)", output_filename)
    576 
    577 
    578     def link(self,
    579              target_desc,
    580              objects,
    581              output_filename,
    582              output_dir=None,
    583              libraries=None,
    584              library_dirs=None,
    585              runtime_library_dirs=None,
    586              export_symbols=None,
    587              debug=0,
    588              extra_preargs=None,
    589              extra_postargs=None,
    590              build_temp=None,
    591              target_lang=None):
    592 
    593         if not self.initialized:
    594             self.initialize()
    595         (objects, output_dir) = self._fix_object_args(objects, output_dir)
    596         fixed_args = self._fix_lib_args(libraries, library_dirs,
    597                                         runtime_library_dirs)
    598         (libraries, library_dirs, runtime_library_dirs) = fixed_args
    599 
    600         if runtime_library_dirs:
    601             self.warn ("I don't know what to do with 'runtime_library_dirs': "
    602                        + str (runtime_library_dirs))
    603 
    604         lib_opts = gen_lib_options(self,
    605                                    library_dirs, runtime_library_dirs,
    606                                    libraries)
    607         if output_dir is not None:
    608             output_filename = os.path.join(output_dir, output_filename)
    609 
    610         if self._need_link(objects, output_filename):
    611             if target_desc == CCompiler.EXECUTABLE:
    612                 if debug:
    613                     ldflags = self.ldflags_shared_debug[1:]
    614                 else:
    615                     ldflags = self.ldflags_shared[1:]
    616             else:
    617                 if debug:
    618                     ldflags = self.ldflags_shared_debug
    619                 else:
    620                     ldflags = self.ldflags_shared
    621 
    622             export_opts = []
    623             for sym in (export_symbols or []):
    624                 export_opts.append("/EXPORT:" + sym)
    625 
    626             ld_args = (ldflags + lib_opts + export_opts +
    627                        objects + ['/OUT:' + output_filename])
    628 
    629             # The MSVC linker generates .lib and .exp files, which cannot be

    630             # suppressed by any linker switches. The .lib files may even be

    631             # needed! Make sure they are generated in the temporary build

    632             # directory. Since they have different names for debug and release

    633             # builds, they can go into the same directory.

    634             build_temp = os.path.dirname(objects[0])
    635             if export_symbols is not None:
    636                 (dll_name, dll_ext) = os.path.splitext(
    637                     os.path.basename(output_filename))
    638                 implib_file = os.path.join(
    639                     build_temp,
    640                     self.library_filename(dll_name))
    641                 ld_args.append ('/IMPLIB:' + implib_file)
    642 
    643             # Embedded manifests are recommended - see MSDN article titled

    644             # "How to: Embed a Manifest Inside a C/C++ Application"

    645             # (currently at http://msdn2.microsoft.com/en-us/library/ms235591(VS.80).aspx)

    646             # Ask the linker to generate the manifest in the temp dir, so

    647             # we can embed it later.

    648             temp_manifest = os.path.join(
    649                     build_temp,
    650                     os.path.basename(output_filename) + ".manifest")
    651             ld_args.append('/MANIFESTFILE:' + temp_manifest)
    652 
    653             if extra_preargs:
    654                 ld_args[:0] = extra_preargs
    655             if extra_postargs:
    656                 ld_args.extend(extra_postargs)
    657 
    658             self.mkpath(os.path.dirname(output_filename))
    659             try:
    660                 self.spawn([self.linker] + ld_args)
    661             except DistutilsExecError, msg:
    662                 raise LinkError(msg)
    663 
    664             # embed the manifest

    665             # XXX - this is somewhat fragile - if mt.exe fails, distutils

    666             # will still consider the DLL up-to-date, but it will not have a

    667             # manifest.  Maybe we should link to a temp file?  OTOH, that

    668             # implies a build environment error that shouldn't go undetected.

    669             if target_desc == CCompiler.EXECUTABLE:
    670                 mfid = 1
    671             else:
    672                 mfid = 2
    673                 self._remove_visual_c_ref(temp_manifest)
    674             out_arg = '-outputresource:%s;%s' % (output_filename, mfid)
    675             try:
    676                 self.spawn(['mt.exe', '-nologo', '-manifest',
    677                             temp_manifest, out_arg])
    678             except DistutilsExecError, msg:
    679                 raise LinkError(msg)
    680         else:
    681             log.debug("skipping %s (up-to-date)", output_filename)
    682 
    683     def _remove_visual_c_ref(self, manifest_file):
    684         try:
    685             # Remove references to the Visual C runtime, so they will

    686             # fall through to the Visual C dependency of Python.exe.

    687             # This way, when installed for a restricted user (e.g.

    688             # runtimes are not in WinSxS folder, but in Python's own

    689             # folder), the runtimes do not need to be in every folder

    690             # with .pyd's.

    691             manifest_f = open(manifest_file)
    692             try:
    693                 manifest_buf = manifest_f.read()
    694             finally:
    695                 manifest_f.close()
    696             pattern = re.compile(
    697                 r"""<assemblyIdentity.*?name=("|')Microsoft\."""\
    698                 r"""VC\d{2}\.CRT("|').*?(/>|</assemblyIdentity>)""",
    699                 re.DOTALL)
    700             manifest_buf = re.sub(pattern, "", manifest_buf)
    701             pattern = "<dependentAssembly>\s*</dependentAssembly>"
    702             manifest_buf = re.sub(pattern, "", manifest_buf)
    703             manifest_f = open(manifest_file, 'w')
    704             try:
    705                 manifest_f.write(manifest_buf)
    706             finally:
    707                 manifest_f.close()
    708         except IOError:
    709             pass
    710 
    711     # -- Miscellaneous methods -----------------------------------------
    712     # These are all used by the 'gen_lib_options() function, in
    713     # ccompiler.py.
    714 
    715     def library_dir_option(self, dir):
    716         return "/LIBPATH:" + dir
    717 
    718     def runtime_library_dir_option(self, dir):
    719         raise DistutilsPlatformError(
    720               "don't know how to set runtime library search path for MSVC++")
    721 
    722     def library_option(self, lib):
    723         return self.library_filename(lib)
    724 
    725 
    726     def find_library_file(self, dirs, lib, debug=0):
    727         # Prefer a debugging library if found (and requested), but deal
    728         # with it if we don't have one.
    729         if debug:
    730             try_names = [lib + "_d", lib]
    731         else:
    732             try_names = [lib]
    733         for dir in dirs:
    734             for name in try_names:
    735                 libfile = os.path.join(dir, self.library_filename (name))
    736                 if os.path.exists(libfile):
    737                     return libfile
    738         else:
    739             # Oops, didn't find it in *any* of 'dirs'

    740             return None
    741 
    742     # Helper methods for using the MSVC registry settings

    743 
    744     def find_exe(self, exe):
    745         """Return path to an MSVC executable program.
    746 
    747         Tries to find the program in several places: first, one of the
    748         MSVC program search paths from the registry; next, the directories
    749         in the PATH environment variable.  If any of those work, return an
    750         absolute path that is known to exist.  If none of them work, just
    751         return the original program name, 'exe'.
    752         """
    753         for p in self.__paths:
    754             fn = os.path.join(os.path.abspath(p), exe)
    755             if os.path.isfile(fn):
    756                 return fn
    757 
    758         # didn't find it; try existing path

    759         for p in os.environ['Path'].split(';'):
    760             fn = os.path.join(os.path.abspath(p),exe)
    761             if os.path.isfile(fn):
    762                 return fn
    763 
    764         return exe
    765