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