1"""
2Support code for building Python extensions on Windows.
3
4    # NT stuff
5    # 1. Make sure libpython<version>.a exists for gcc.  If not, build it.
6    # 2. Force windows to use gcc (we're struggling with MSVC and g77 support)
7    # 3. Force windows to use g77
8
9"""
10import os
11import platform
12import sys
13import subprocess
14import re
15import textwrap
16
17# Overwrite certain distutils.ccompiler functions:
18import numpy.distutils.ccompiler  # noqa: F401
19from numpy.distutils import log
20# NT stuff
21# 1. Make sure libpython<version>.a exists for gcc.  If not, build it.
22# 2. Force windows to use gcc (we're struggling with MSVC and g77 support)
23#    --> this is done in numpy/distutils/ccompiler.py
24# 3. Force windows to use g77
25
26import distutils.cygwinccompiler
27from distutils.version import StrictVersion
28from distutils.unixccompiler import UnixCCompiler
29from distutils.msvccompiler import get_build_version as get_build_msvc_version
30from distutils.errors import UnknownFileError
31from numpy.distutils.misc_util import (msvc_runtime_library,
32                                       msvc_runtime_version,
33                                       msvc_runtime_major,
34                                       get_build_architecture)
35
36def get_msvcr_replacement():
37    """Replacement for outdated version of get_msvcr from cygwinccompiler"""
38    msvcr = msvc_runtime_library()
39    return [] if msvcr is None else [msvcr]
40
41# monkey-patch cygwinccompiler with our updated version from misc_util
42# to avoid getting an exception raised on Python 3.5
43distutils.cygwinccompiler.get_msvcr = get_msvcr_replacement
44
45# Useful to generate table of symbols from a dll
46_START = re.compile(r'\[Ordinal/Name Pointer\] Table')
47_TABLE = re.compile(r'^\s+\[([\s*[0-9]*)\] ([a-zA-Z0-9_]*)')
48
49# the same as cygwin plus some additional parameters
50class Mingw32CCompiler(distutils.cygwinccompiler.CygwinCCompiler):
51    """ A modified MingW32 compiler compatible with an MSVC built Python.
52
53    """
54
55    compiler_type = 'mingw32'
56
57    def __init__ (self,
58                  verbose=0,
59                  dry_run=0,
60                  force=0):
61
62        distutils.cygwinccompiler.CygwinCCompiler.__init__ (self, verbose,
63                                                            dry_run, force)
64
65        # we need to support 3.2 which doesn't match the standard
66        # get_versions methods regex
67        if self.gcc_version is None:
68            try:
69                out_string  = subprocess.check_output(['gcc', '-dumpversion'])
70            except (OSError, CalledProcessError):
71                out_string = ""  # ignore failures to match old behavior
72            result = re.search(r'(\d+\.\d+)', out_string)
73            if result:
74                self.gcc_version = StrictVersion(result.group(1))
75
76        # A real mingw32 doesn't need to specify a different entry point,
77        # but cygwin 2.91.57 in no-cygwin-mode needs it.
78        if self.gcc_version <= "2.91.57":
79            entry_point = '--entry _DllMain@12'
80        else:
81            entry_point = ''
82
83        if self.linker_dll == 'dllwrap':
84            # Commented out '--driver-name g++' part that fixes weird
85            #   g++.exe: g++: No such file or directory
86            # error (mingw 1.0 in Enthon24 tree, gcc-3.4.5).
87            # If the --driver-name part is required for some environment
88            # then make the inclusion of this part specific to that
89            # environment.
90            self.linker = 'dllwrap' #  --driver-name g++'
91        elif self.linker_dll == 'gcc':
92            self.linker = 'g++'
93
94        # **changes: eric jones 4/11/01
95        # 1. Check for import library on Windows.  Build if it doesn't exist.
96
97        build_import_library()
98
99        # Check for custom msvc runtime library on Windows. Build if it doesn't exist.
100        msvcr_success = build_msvcr_library()
101        msvcr_dbg_success = build_msvcr_library(debug=True)
102        if msvcr_success or msvcr_dbg_success:
103            # add preprocessor statement for using customized msvcr lib
104            self.define_macro('NPY_MINGW_USE_CUSTOM_MSVCR')
105
106        # Define the MSVC version as hint for MinGW
107        msvcr_version = msvc_runtime_version()
108        if msvcr_version:
109            self.define_macro('__MSVCRT_VERSION__', '0x%04i' % msvcr_version)
110
111        # MS_WIN64 should be defined when building for amd64 on windows,
112        # but python headers define it only for MS compilers, which has all
113        # kind of bad consequences, like using Py_ModuleInit4 instead of
114        # Py_ModuleInit4_64, etc... So we add it here
115        if get_build_architecture() == 'AMD64':
116            if self.gcc_version < "4.0":
117                self.set_executables(
118                    compiler='gcc -g -DDEBUG -DMS_WIN64 -mno-cygwin -O0 -Wall',
119                    compiler_so='gcc -g -DDEBUG -DMS_WIN64 -mno-cygwin -O0'
120                                ' -Wall -Wstrict-prototypes',
121                    linker_exe='gcc -g -mno-cygwin',
122                    linker_so='gcc -g -mno-cygwin -shared')
123            else:
124                # gcc-4 series releases do not support -mno-cygwin option
125                self.set_executables(
126                    compiler='gcc -g -DDEBUG -DMS_WIN64 -O0 -Wall',
127                    compiler_so='gcc -g -DDEBUG -DMS_WIN64 -O0 -Wall -Wstrict-prototypes',
128                    linker_exe='gcc -g',
129                    linker_so='gcc -g -shared')
130        else:
131            if self.gcc_version <= "3.0.0":
132                self.set_executables(
133                    compiler='gcc -mno-cygwin -O2 -w',
134                    compiler_so='gcc -mno-cygwin -mdll -O2 -w'
135                                ' -Wstrict-prototypes',
136                    linker_exe='g++ -mno-cygwin',
137                    linker_so='%s -mno-cygwin -mdll -static %s' %
138                              (self.linker, entry_point))
139            elif self.gcc_version < "4.0":
140                self.set_executables(
141                    compiler='gcc -mno-cygwin -O2 -Wall',
142                    compiler_so='gcc -mno-cygwin -O2 -Wall'
143                                ' -Wstrict-prototypes',
144                    linker_exe='g++ -mno-cygwin',
145                    linker_so='g++ -mno-cygwin -shared')
146            else:
147                # gcc-4 series releases do not support -mno-cygwin option
148                self.set_executables(compiler='gcc -O2 -Wall',
149                                     compiler_so='gcc -O2 -Wall -Wstrict-prototypes',
150                                     linker_exe='g++ ',
151                                     linker_so='g++ -shared')
152        # added for python2.3 support
153        # we can't pass it through set_executables because pre 2.2 would fail
154        self.compiler_cxx = ['g++']
155
156        # Maybe we should also append -mthreads, but then the finished dlls
157        # need another dll (mingwm10.dll see Mingw32 docs) (-mthreads: Support
158        # thread-safe exception handling on `Mingw32')
159
160        # no additional libraries needed
161        #self.dll_libraries=[]
162        return
163
164    # __init__ ()
165
166    def link(self,
167             target_desc,
168             objects,
169             output_filename,
170             output_dir,
171             libraries,
172             library_dirs,
173             runtime_library_dirs,
174             export_symbols = None,
175             debug=0,
176             extra_preargs=None,
177             extra_postargs=None,
178             build_temp=None,
179             target_lang=None):
180        # Include the appropriate MSVC runtime library if Python was built
181        # with MSVC >= 7.0 (MinGW standard is msvcrt)
182        runtime_library = msvc_runtime_library()
183        if runtime_library:
184            if not libraries:
185                libraries = []
186            libraries.append(runtime_library)
187        args = (self,
188                target_desc,
189                objects,
190                output_filename,
191                output_dir,
192                libraries,
193                library_dirs,
194                runtime_library_dirs,
195                None, #export_symbols, we do this in our def-file
196                debug,
197                extra_preargs,
198                extra_postargs,
199                build_temp,
200                target_lang)
201        if self.gcc_version < "3.0.0":
202            func = distutils.cygwinccompiler.CygwinCCompiler.link
203        else:
204            func = UnixCCompiler.link
205        func(*args[:func.__code__.co_argcount])
206        return
207
208    def object_filenames (self,
209                          source_filenames,
210                          strip_dir=0,
211                          output_dir=''):
212        if output_dir is None: output_dir = ''
213        obj_names = []
214        for src_name in source_filenames:
215            # use normcase to make sure '.rc' is really '.rc' and not '.RC'
216            (base, ext) = os.path.splitext (os.path.normcase(src_name))
217
218            # added these lines to strip off windows drive letters
219            # without it, .o files are placed next to .c files
220            # instead of the build directory
221            drv, base = os.path.splitdrive(base)
222            if drv:
223                base = base[1:]
224
225            if ext not in (self.src_extensions + ['.rc', '.res']):
226                raise UnknownFileError(
227                      "unknown file type '%s' (from '%s')" % \
228                      (ext, src_name))
229            if strip_dir:
230                base = os.path.basename (base)
231            if ext == '.res' or ext == '.rc':
232                # these need to be compiled to object files
233                obj_names.append (os.path.join (output_dir,
234                                                base + ext + self.obj_extension))
235            else:
236                obj_names.append (os.path.join (output_dir,
237                                                base + self.obj_extension))
238        return obj_names
239
240    # object_filenames ()
241
242
243def find_python_dll():
244    # We can't do much here:
245    # - find it in the virtualenv (sys.prefix)
246    # - find it in python main dir (sys.base_prefix, if in a virtualenv)
247    # - sys.real_prefix is main dir for virtualenvs in Python 2.7
248    # - in system32,
249    # - ortherwise (Sxs), I don't know how to get it.
250    stems = [sys.prefix]
251    if hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix:
252        stems.append(sys.base_prefix)
253    elif hasattr(sys, 'real_prefix') and sys.real_prefix != sys.prefix:
254        stems.append(sys.real_prefix)
255
256    sub_dirs = ['', 'lib', 'bin']
257    # generate possible combinations of directory trees and sub-directories
258    lib_dirs = []
259    for stem in stems:
260        for folder in sub_dirs:
261            lib_dirs.append(os.path.join(stem, folder))
262
263    # add system directory as well
264    if 'SYSTEMROOT' in os.environ:
265        lib_dirs.append(os.path.join(os.environ['SYSTEMROOT'], 'System32'))
266
267    # search in the file system for possible candidates
268    major_version, minor_version = tuple(sys.version_info[:2])
269    implementation = platform.python_implementation()
270    if implementation == 'CPython':
271        dllname = f'python{major_version}{minor_version}.dll'
272    elif implementation == 'PyPy':
273        dllname = f'libpypy{major_version}-c.dll'
274    else:
275        dllname = 'Unknown platform {implementation}'
276    print("Looking for %s" % dllname)
277    for folder in lib_dirs:
278        dll = os.path.join(folder, dllname)
279        if os.path.exists(dll):
280            return dll
281
282    raise ValueError("%s not found in %s" % (dllname, lib_dirs))
283
284def dump_table(dll):
285    st = subprocess.check_output(["objdump.exe", "-p", dll])
286    return st.split(b'\n')
287
288def generate_def(dll, dfile):
289    """Given a dll file location,  get all its exported symbols and dump them
290    into the given def file.
291
292    The .def file will be overwritten"""
293    dump = dump_table(dll)
294    for i in range(len(dump)):
295        if _START.match(dump[i].decode()):
296            break
297    else:
298        raise ValueError("Symbol table not found")
299
300    syms = []
301    for j in range(i+1, len(dump)):
302        m = _TABLE.match(dump[j].decode())
303        if m:
304            syms.append((int(m.group(1).strip()), m.group(2)))
305        else:
306            break
307
308    if len(syms) == 0:
309        log.warn('No symbols found in %s' % dll)
310
311    with open(dfile, 'w') as d:
312        d.write('LIBRARY        %s\n' % os.path.basename(dll))
313        d.write(';CODE          PRELOAD MOVEABLE DISCARDABLE\n')
314        d.write(';DATA          PRELOAD SINGLE\n')
315        d.write('\nEXPORTS\n')
316        for s in syms:
317            #d.write('@%d    %s\n' % (s[0], s[1]))
318            d.write('%s\n' % s[1])
319
320def find_dll(dll_name):
321
322    arch = {'AMD64' : 'amd64',
323            'Intel' : 'x86'}[get_build_architecture()]
324
325    def _find_dll_in_winsxs(dll_name):
326        # Walk through the WinSxS directory to find the dll.
327        winsxs_path = os.path.join(os.environ.get('WINDIR', r'C:\WINDOWS'),
328                                   'winsxs')
329        if not os.path.exists(winsxs_path):
330            return None
331        for root, dirs, files in os.walk(winsxs_path):
332            if dll_name in files and arch in root:
333                return os.path.join(root, dll_name)
334        return None
335
336    def _find_dll_in_path(dll_name):
337        # First, look in the Python directory, then scan PATH for
338        # the given dll name.
339        for path in [sys.prefix] + os.environ['PATH'].split(';'):
340            filepath = os.path.join(path, dll_name)
341            if os.path.exists(filepath):
342                return os.path.abspath(filepath)
343
344    return _find_dll_in_winsxs(dll_name) or _find_dll_in_path(dll_name)
345
346def build_msvcr_library(debug=False):
347    if os.name != 'nt':
348        return False
349
350    # If the version number is None, then we couldn't find the MSVC runtime at
351    # all, because we are running on a Python distribution which is customed
352    # compiled; trust that the compiler is the same as the one available to us
353    # now, and that it is capable of linking with the correct runtime without
354    # any extra options.
355    msvcr_ver = msvc_runtime_major()
356    if msvcr_ver is None:
357        log.debug('Skip building import library: '
358                  'Runtime is not compiled with MSVC')
359        return False
360
361    # Skip using a custom library for versions < MSVC 8.0
362    if msvcr_ver < 80:
363        log.debug('Skip building msvcr library:'
364                  ' custom functionality not present')
365        return False
366
367    msvcr_name = msvc_runtime_library()
368    if debug:
369        msvcr_name += 'd'
370
371    # Skip if custom library already exists
372    out_name = "lib%s.a" % msvcr_name
373    out_file = os.path.join(sys.prefix, 'libs', out_name)
374    if os.path.isfile(out_file):
375        log.debug('Skip building msvcr library: "%s" exists' %
376                  (out_file,))
377        return True
378
379    # Find the msvcr dll
380    msvcr_dll_name = msvcr_name + '.dll'
381    dll_file = find_dll(msvcr_dll_name)
382    if not dll_file:
383        log.warn('Cannot build msvcr library: "%s" not found' %
384                 msvcr_dll_name)
385        return False
386
387    def_name = "lib%s.def" % msvcr_name
388    def_file = os.path.join(sys.prefix, 'libs', def_name)
389
390    log.info('Building msvcr library: "%s" (from %s)' \
391             % (out_file, dll_file))
392
393    # Generate a symbol definition file from the msvcr dll
394    generate_def(dll_file, def_file)
395
396    # Create a custom mingw library for the given symbol definitions
397    cmd = ['dlltool', '-d', def_file, '-l', out_file]
398    retcode = subprocess.call(cmd)
399
400    # Clean up symbol definitions
401    os.remove(def_file)
402
403    return (not retcode)
404
405def build_import_library():
406    if os.name != 'nt':
407        return
408
409    arch = get_build_architecture()
410    if arch == 'AMD64':
411        return _build_import_library_amd64()
412    elif arch == 'Intel':
413        return _build_import_library_x86()
414    else:
415        raise ValueError("Unhandled arch %s" % arch)
416
417def _check_for_import_lib():
418    """Check if an import library for the Python runtime already exists."""
419    major_version, minor_version = tuple(sys.version_info[:2])
420
421    # patterns for the file name of the library itself
422    patterns = ['libpython%d%d.a',
423                'libpython%d%d.dll.a',
424                'libpython%d.%d.dll.a']
425
426    # directory trees that may contain the library
427    stems = [sys.prefix]
428    if hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix:
429        stems.append(sys.base_prefix)
430    elif hasattr(sys, 'real_prefix') and sys.real_prefix != sys.prefix:
431        stems.append(sys.real_prefix)
432
433    # possible subdirectories within those trees where it is placed
434    sub_dirs = ['libs', 'lib']
435
436    # generate a list of candidate locations
437    candidates = []
438    for pat in patterns:
439        filename = pat % (major_version, minor_version)
440        for stem_dir in stems:
441            for folder in sub_dirs:
442                candidates.append(os.path.join(stem_dir, folder, filename))
443
444    # test the filesystem to see if we can find any of these
445    for fullname in candidates:
446        if os.path.isfile(fullname):
447            # already exists, in location given
448            return (True, fullname)
449
450    # needs to be built, preferred location given first
451    return (False, candidates[0])
452
453def _build_import_library_amd64():
454    out_exists, out_file = _check_for_import_lib()
455    if out_exists:
456        log.debug('Skip building import library: "%s" exists', out_file)
457        return
458
459    # get the runtime dll for which we are building import library
460    dll_file = find_python_dll()
461    log.info('Building import library (arch=AMD64): "%s" (from %s)' %
462             (out_file, dll_file))
463
464    # generate symbol list from this library
465    def_name = "python%d%d.def" % tuple(sys.version_info[:2])
466    def_file = os.path.join(sys.prefix, 'libs', def_name)
467    generate_def(dll_file, def_file)
468
469    # generate import library from this symbol list
470    cmd = ['dlltool', '-d', def_file, '-l', out_file]
471    subprocess.check_call(cmd)
472
473def _build_import_library_x86():
474    """ Build the import libraries for Mingw32-gcc on Windows
475    """
476    out_exists, out_file = _check_for_import_lib()
477    if out_exists:
478        log.debug('Skip building import library: "%s" exists', out_file)
479        return
480
481    lib_name = "python%d%d.lib" % tuple(sys.version_info[:2])
482    lib_file = os.path.join(sys.prefix, 'libs', lib_name)
483    if not os.path.isfile(lib_file):
484        # didn't find library file in virtualenv, try base distribution, too,
485        # and use that instead if found there. for Python 2.7 venvs, the base
486        # directory is in attribute real_prefix instead of base_prefix.
487        if hasattr(sys, 'base_prefix'):
488            base_lib = os.path.join(sys.base_prefix, 'libs', lib_name)
489        elif hasattr(sys, 'real_prefix'):
490            base_lib = os.path.join(sys.real_prefix, 'libs', lib_name)
491        else:
492            base_lib = ''  # os.path.isfile('') == False
493
494        if os.path.isfile(base_lib):
495            lib_file = base_lib
496        else:
497            log.warn('Cannot build import library: "%s" not found', lib_file)
498            return
499    log.info('Building import library (ARCH=x86): "%s"', out_file)
500
501    from numpy.distutils import lib2def
502
503    def_name = "python%d%d.def" % tuple(sys.version_info[:2])
504    def_file = os.path.join(sys.prefix, 'libs', def_name)
505    nm_output = lib2def.getnm(
506            lib2def.DEFAULT_NM + [lib_file], shell=False)
507    dlist, flist = lib2def.parse_nm(nm_output)
508    with open(def_file, 'w') as fid:
509        lib2def.output_def(dlist, flist, lib2def.DEF_HEADER, fid)
510
511    dll_name = find_python_dll ()
512
513    cmd = ["dlltool",
514           "--dllname", dll_name,
515           "--def", def_file,
516           "--output-lib", out_file]
517    status = subprocess.check_output(cmd)
518    if status:
519        log.warn('Failed to build import library for gcc. Linking will fail.')
520    return
521
522#=====================================
523# Dealing with Visual Studio MANIFESTS
524#=====================================
525
526# Functions to deal with visual studio manifests. Manifest are a mechanism to
527# enforce strong DLL versioning on windows, and has nothing to do with
528# distutils MANIFEST. manifests are XML files with version info, and used by
529# the OS loader; they are necessary when linking against a DLL not in the
530# system path; in particular, official python 2.6 binary is built against the
531# MS runtime 9 (the one from VS 2008), which is not available on most windows
532# systems; python 2.6 installer does install it in the Win SxS (Side by side)
533# directory, but this requires the manifest for this to work. This is a big
534# mess, thanks MS for a wonderful system.
535
536# XXX: ideally, we should use exactly the same version as used by python. I
537# submitted a patch to get this version, but it was only included for python
538# 2.6.1 and above. So for versions below, we use a "best guess".
539_MSVCRVER_TO_FULLVER = {}
540if sys.platform == 'win32':
541    try:
542        import msvcrt
543        # I took one version in my SxS directory: no idea if it is the good
544        # one, and we can't retrieve it from python
545        _MSVCRVER_TO_FULLVER['80'] = "8.0.50727.42"
546        _MSVCRVER_TO_FULLVER['90'] = "9.0.21022.8"
547        # Value from msvcrt.CRT_ASSEMBLY_VERSION under Python 3.3.0
548        # on Windows XP:
549        _MSVCRVER_TO_FULLVER['100'] = "10.0.30319.460"
550        # Python 3.7 uses 1415, but get_build_version returns 140 ??
551        _MSVCRVER_TO_FULLVER['140'] = "14.15.26726.0"
552        if hasattr(msvcrt, "CRT_ASSEMBLY_VERSION"):
553            major, minor, rest = msvcrt.CRT_ASSEMBLY_VERSION.split(".", 2)
554            _MSVCRVER_TO_FULLVER[major + minor] = msvcrt.CRT_ASSEMBLY_VERSION
555            del major, minor, rest
556    except ImportError:
557        # If we are here, means python was not built with MSVC. Not sure what
558        # to do in that case: manifest building will fail, but it should not be
559        # used in that case anyway
560        log.warn('Cannot import msvcrt: using manifest will not be possible')
561
562def msvc_manifest_xml(maj, min):
563    """Given a major and minor version of the MSVCR, returns the
564    corresponding XML file."""
565    try:
566        fullver = _MSVCRVER_TO_FULLVER[str(maj * 10 + min)]
567    except KeyError:
568        raise ValueError("Version %d,%d of MSVCRT not supported yet" %
569                         (maj, min))
570    # Don't be fooled, it looks like an XML, but it is not. In particular, it
571    # should not have any space before starting, and its size should be
572    # divisible by 4, most likely for alignment constraints when the xml is
573    # embedded in the binary...
574    # This template was copied directly from the python 2.6 binary (using
575    # strings.exe from mingw on python.exe).
576    template = textwrap.dedent("""\
577        <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
578          <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
579            <security>
580              <requestedPrivileges>
581                <requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel>
582              </requestedPrivileges>
583            </security>
584          </trustInfo>
585          <dependency>
586            <dependentAssembly>
587              <assemblyIdentity type="win32" name="Microsoft.VC%(maj)d%(min)d.CRT" version="%(fullver)s" processorArchitecture="*" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
588            </dependentAssembly>
589          </dependency>
590        </assembly>""")
591
592    return template % {'fullver': fullver, 'maj': maj, 'min': min}
593
594def manifest_rc(name, type='dll'):
595    """Return the rc file used to generate the res file which will be embedded
596    as manifest for given manifest file name, of given type ('dll' or
597    'exe').
598
599    Parameters
600    ----------
601    name : str
602            name of the manifest file to embed
603    type : str {'dll', 'exe'}
604            type of the binary which will embed the manifest
605
606    """
607    if type == 'dll':
608        rctype = 2
609    elif type == 'exe':
610        rctype = 1
611    else:
612        raise ValueError("Type %s not supported" % type)
613
614    return """\
615#include "winuser.h"
616%d RT_MANIFEST %s""" % (rctype, name)
617
618def check_embedded_msvcr_match_linked(msver):
619    """msver is the ms runtime version used for the MANIFEST."""
620    # check msvcr major version are the same for linking and
621    # embedding
622    maj = msvc_runtime_major()
623    if maj:
624        if not maj == int(msver):
625            raise ValueError(
626                  "Discrepancy between linked msvcr " \
627                  "(%d) and the one about to be embedded " \
628                  "(%d)" % (int(msver), maj))
629
630def configtest_name(config):
631    base = os.path.basename(config._gen_temp_sourcefile("yo", [], "c"))
632    return os.path.splitext(base)[0]
633
634def manifest_name(config):
635    # Get configest name (including suffix)
636    root = configtest_name(config)
637    exext = config.compiler.exe_extension
638    return root + exext + ".manifest"
639
640def rc_name(config):
641    # Get configtest name (including suffix)
642    root = configtest_name(config)
643    return root + ".rc"
644
645def generate_manifest(config):
646    msver = get_build_msvc_version()
647    if msver is not None:
648        if msver >= 8:
649            check_embedded_msvcr_match_linked(msver)
650            ma = int(msver)
651            mi = int((msver - ma) * 10)
652            # Write the manifest file
653            manxml = msvc_manifest_xml(ma, mi)
654            man = open(manifest_name(config), "w")
655            config.temp_files.append(manifest_name(config))
656            man.write(manxml)
657            man.close()
658