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