annotate DEPENDENCIES/mingw32/Python27/Lib/site-packages/numpy/distutils/mingw32ccompiler.py @ 118:770eb830ec19 emscripten

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