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