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