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