1"""distutils.msvccompiler 2 3Contains MSVCCompiler, an implementation of the abstract CCompiler class 4for the Microsoft Visual Studio. 5""" 6 7# Written by Perry Stoll 8# hacked by Robin Becker and Thomas Heller to do a better job of 9# finding DevStudio (through the registry) 10 11__revision__ = "$Id$" 12 13import sys 14import os 15import string 16 17from distutils.errors import (DistutilsExecError, DistutilsPlatformError, 18 CompileError, LibError, LinkError) 19from distutils.ccompiler import CCompiler, gen_lib_options 20from distutils import log 21 22_can_read_reg = 0 23try: 24 import _winreg 25 26 _can_read_reg = 1 27 hkey_mod = _winreg 28 29 RegOpenKeyEx = _winreg.OpenKeyEx 30 RegEnumKey = _winreg.EnumKey 31 RegEnumValue = _winreg.EnumValue 32 RegError = _winreg.error 33 34except ImportError: 35 try: 36 import win32api 37 import win32con 38 _can_read_reg = 1 39 hkey_mod = win32con 40 41 RegOpenKeyEx = win32api.RegOpenKeyEx 42 RegEnumKey = win32api.RegEnumKey 43 RegEnumValue = win32api.RegEnumValue 44 RegError = win32api.error 45 46 except ImportError: 47 log.info("Warning: Can't read registry to find the " 48 "necessary compiler setting\n" 49 "Make sure that Python modules _winreg, " 50 "win32api or win32con are installed.") 51 pass 52 53if _can_read_reg: 54 HKEYS = (hkey_mod.HKEY_USERS, 55 hkey_mod.HKEY_CURRENT_USER, 56 hkey_mod.HKEY_LOCAL_MACHINE, 57 hkey_mod.HKEY_CLASSES_ROOT) 58 59def read_keys(base, key): 60 """Return list of registry keys.""" 61 62 try: 63 handle = RegOpenKeyEx(base, key) 64 except RegError: 65 return None 66 L = [] 67 i = 0 68 while 1: 69 try: 70 k = RegEnumKey(handle, i) 71 except RegError: 72 break 73 L.append(k) 74 i = i + 1 75 return L 76 77def read_values(base, key): 78 """Return dict of registry keys and values. 79 80 All names are converted to lowercase. 81 """ 82 try: 83 handle = RegOpenKeyEx(base, key) 84 except RegError: 85 return None 86 d = {} 87 i = 0 88 while 1: 89 try: 90 name, value, type = RegEnumValue(handle, i) 91 except RegError: 92 break 93 name = name.lower() 94 d[convert_mbcs(name)] = convert_mbcs(value) 95 i = i + 1 96 return d 97 98def convert_mbcs(s): 99 enc = getattr(s, "encode", None) 100 if enc is not None: 101 try: 102 s = enc("mbcs") 103 except UnicodeError: 104 pass 105 return s 106 107class MacroExpander: 108 109 def __init__(self, version): 110 self.macros = {} 111 self.load_macros(version) 112 113 def set_macro(self, macro, path, key): 114 for base in HKEYS: 115 d = read_values(base, path) 116 if d: 117 self.macros["$(%s)" % macro] = d[key] 118 break 119 120 def load_macros(self, version): 121 vsbase = r"Software\Microsoft\VisualStudio\%0.1f" % version 122 self.set_macro("VCInstallDir", vsbase + r"\Setup\VC", "productdir") 123 self.set_macro("VSInstallDir", vsbase + r"\Setup\VS", "productdir") 124 net = r"Software\Microsoft\.NETFramework" 125 self.set_macro("FrameworkDir", net, "installroot") 126 try: 127 if version > 7.0: 128 self.set_macro("FrameworkSDKDir", net, "sdkinstallrootv1.1") 129 else: 130 self.set_macro("FrameworkSDKDir", net, "sdkinstallroot") 131 except KeyError: 132 raise DistutilsPlatformError, \ 133 ("""Python was built with Visual Studio 2003; 134extensions must be built with a compiler than can generate compatible binaries. 135Visual Studio 2003 was not found on this system. If you have Cygwin installed, 136you can try compiling with MingW32, by passing "-c mingw32" to setup.py.""") 137 138 p = r"Software\Microsoft\NET Framework Setup\Product" 139 for base in HKEYS: 140 try: 141 h = RegOpenKeyEx(base, p) 142 except RegError: 143 continue 144 key = RegEnumKey(h, 0) 145 d = read_values(base, r"%s\%s" % (p, key)) 146 self.macros["$(FrameworkVersion)"] = d["version"] 147 148 def sub(self, s): 149 for k, v in self.macros.items(): 150 s = string.replace(s, k, v) 151 return s 152 153def get_build_version(): 154 """Return the version of MSVC that was used to build Python. 155 156 For Python 2.3 and up, the version number is included in 157 sys.version. For earlier versions, assume the compiler is MSVC 6. 158 """ 159 160 prefix = "MSC v." 161 i = string.find(sys.version, prefix) 162 if i == -1: 163 return 6 164 i = i + len(prefix) 165 s, rest = sys.version[i:].split(" ", 1) 166 majorVersion = int(s[:-2]) - 6 167 minorVersion = int(s[2:3]) / 10.0 168 # I don't think paths are affected by minor version in version 6 169 if majorVersion == 6: 170 minorVersion = 0 171 if majorVersion >= 6: 172 return majorVersion + minorVersion 173 # else we don't know what version of the compiler this is 174 return None 175 176def get_build_architecture(): 177 """Return the processor architecture. 178 179 Possible results are "Intel", "Itanium", or "AMD64". 180 """ 181 182 prefix = " bit (" 183 i = string.find(sys.version, prefix) 184 if i == -1: 185 return "Intel" 186 j = string.find(sys.version, ")", i) 187 return sys.version[i+len(prefix):j] 188 189def normalize_and_reduce_paths(paths): 190 """Return a list of normalized paths with duplicates removed. 191 192 The current order of paths is maintained. 193 """ 194 # Paths are normalized so things like: /a and /a/ aren't both preserved. 195 reduced_paths = [] 196 for p in paths: 197 np = os.path.normpath(p) 198 # XXX(nnorwitz): O(n**2), if reduced_paths gets long perhaps use a set. 199 if np not in reduced_paths: 200 reduced_paths.append(np) 201 return reduced_paths 202 203 204class MSVCCompiler (CCompiler) : 205 """Concrete class that implements an interface to Microsoft Visual C++, 206 as defined by the CCompiler abstract class.""" 207 208 compiler_type = 'msvc' 209 210 # Just set this so CCompiler's constructor doesn't barf. We currently 211 # don't use the 'set_executables()' bureaucracy provided by CCompiler, 212 # as it really isn't necessary for this sort of single-compiler class. 213 # Would be nice to have a consistent interface with UnixCCompiler, 214 # though, so it's worth thinking about. 215 executables = {} 216 217 # Private class data (need to distinguish C from C++ source for compiler) 218 _c_extensions = ['.c'] 219 _cpp_extensions = ['.cc', '.cpp', '.cxx'] 220 _rc_extensions = ['.rc'] 221 _mc_extensions = ['.mc'] 222 223 # Needed for the filename generation methods provided by the 224 # base class, CCompiler. 225 src_extensions = (_c_extensions + _cpp_extensions + 226 _rc_extensions + _mc_extensions) 227 res_extension = '.res' 228 obj_extension = '.obj' 229 static_lib_extension = '.lib' 230 shared_lib_extension = '.dll' 231 static_lib_format = shared_lib_format = '%s%s' 232 exe_extension = '.exe' 233 234 def __init__ (self, verbose=0, dry_run=0, force=0): 235 CCompiler.__init__ (self, verbose, dry_run, force) 236 self.__version = get_build_version() 237 self.__arch = get_build_architecture() 238 if self.__arch == "Intel": 239 # x86 240 if self.__version >= 7: 241 self.__root = r"Software\Microsoft\VisualStudio" 242 self.__macros = MacroExpander(self.__version) 243 else: 244 self.__root = r"Software\Microsoft\Devstudio" 245 self.__product = "Visual Studio version %s" % self.__version 246 else: 247 # Win64. Assume this was built with the platform SDK 248 self.__product = "Microsoft SDK compiler %s" % (self.__version + 6) 249 250 self.initialized = False 251 252 def initialize(self): 253 self.__paths = [] 254 if "DISTUTILS_USE_SDK" in os.environ and "MSSdk" in os.environ and self.find_exe("cl.exe"): 255 # Assume that the SDK set up everything alright; don't try to be 256 # smarter 257 self.cc = "cl.exe" 258 self.linker = "link.exe" 259 self.lib = "lib.exe" 260 self.rc = "rc.exe" 261 self.mc = "mc.exe" 262 else: 263 self.__paths = self.get_msvc_paths("path") 264 265 if len (self.__paths) == 0: 266 raise DistutilsPlatformError, \ 267 ("Python was built with %s, " 268 "and extensions need to be built with the same " 269 "version of the compiler, but it isn't installed." % self.__product) 270 271 self.cc = self.find_exe("cl.exe") 272 self.linker = self.find_exe("link.exe") 273 self.lib = self.find_exe("lib.exe") 274 self.rc = self.find_exe("rc.exe") # resource compiler 275 self.mc = self.find_exe("mc.exe") # message compiler 276 self.set_path_env_var('lib') 277 self.set_path_env_var('include') 278 279 # extend the MSVC path with the current path 280 try: 281 for p in string.split(os.environ['path'], ';'): 282 self.__paths.append(p) 283 except KeyError: 284 pass 285 self.__paths = normalize_and_reduce_paths(self.__paths) 286 os.environ['path'] = string.join(self.__paths, ';') 287 288 self.preprocess_options = None 289 if self.__arch == "Intel": 290 self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GX' , 291 '/DNDEBUG'] 292 self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GX', 293 '/Z7', '/D_DEBUG'] 294 else: 295 # Win64 296 self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GS-' , 297 '/DNDEBUG'] 298 self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GS-', 299 '/Z7', '/D_DEBUG'] 300 301 self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO'] 302 if self.__version >= 7: 303 self.ldflags_shared_debug = [ 304 '/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG' 305 ] 306 else: 307 self.ldflags_shared_debug = [ 308 '/DLL', '/nologo', '/INCREMENTAL:no', '/pdb:None', '/DEBUG' 309 ] 310 self.ldflags_static = [ '/nologo'] 311 312 self.initialized = True 313 314 # -- Worker methods ------------------------------------------------ 315 316 def object_filenames (self, 317 source_filenames, 318 strip_dir=0, 319 output_dir=''): 320 # Copied from ccompiler.py, extended to return .res as 'object'-file 321 # for .rc input file 322 if output_dir is None: output_dir = '' 323 obj_names = [] 324 for src_name in source_filenames: 325 (base, ext) = os.path.splitext (src_name) 326 base = os.path.splitdrive(base)[1] # Chop off the drive 327 base = base[os.path.isabs(base):] # If abs, chop off leading / 328 if ext not in self.src_extensions: 329 # Better to raise an exception instead of silently continuing 330 # and later complain about sources and targets having 331 # different lengths 332 raise CompileError ("Don't know how to compile %s" % src_name) 333 if strip_dir: 334 base = os.path.basename (base) 335 if ext in self._rc_extensions: 336 obj_names.append (os.path.join (output_dir, 337 base + self.res_extension)) 338 elif ext in self._mc_extensions: 339 obj_names.append (os.path.join (output_dir, 340 base + self.res_extension)) 341 else: 342 obj_names.append (os.path.join (output_dir, 343 base + self.obj_extension)) 344 return obj_names 345 346 # object_filenames () 347 348 349 def compile(self, sources, 350 output_dir=None, macros=None, include_dirs=None, debug=0, 351 extra_preargs=None, extra_postargs=None, depends=None): 352 353 if not self.initialized: self.initialize() 354 macros, objects, extra_postargs, pp_opts, build = \ 355 self._setup_compile(output_dir, macros, include_dirs, sources, 356 depends, extra_postargs) 357 358 compile_opts = extra_preargs or [] 359 compile_opts.append ('/c') 360 if debug: 361 compile_opts.extend(self.compile_options_debug) 362 else: 363 compile_opts.extend(self.compile_options) 364 365 for obj in objects: 366 try: 367 src, ext = build[obj] 368 except KeyError: 369 continue 370 if debug: 371 # pass the full pathname to MSVC in debug mode, 372 # this allows the debugger to find the source file 373 # without asking the user to browse for it 374 src = os.path.abspath(src) 375 376 if ext in self._c_extensions: 377 input_opt = "/Tc" + src 378 elif ext in self._cpp_extensions: 379 input_opt = "/Tp" + src 380 elif ext in self._rc_extensions: 381 # compile .RC to .RES file 382 input_opt = src 383 output_opt = "/fo" + obj 384 try: 385 self.spawn ([self.rc] + pp_opts + 386 [output_opt] + [input_opt]) 387 except DistutilsExecError, msg: 388 raise CompileError, msg 389 continue 390 elif ext in self._mc_extensions: 391 392 # Compile .MC to .RC file to .RES file. 393 # * '-h dir' specifies the directory for the 394 # generated include file 395 # * '-r dir' specifies the target directory of the 396 # generated RC file and the binary message resource 397 # it includes 398 # 399 # For now (since there are no options to change this), 400 # we use the source-directory for the include file and 401 # the build directory for the RC file and message 402 # resources. This works at least for win32all. 403 404 h_dir = os.path.dirname (src) 405 rc_dir = os.path.dirname (obj) 406 try: 407 # first compile .MC to .RC and .H file 408 self.spawn ([self.mc] + 409 ['-h', h_dir, '-r', rc_dir] + [src]) 410 base, _ = os.path.splitext (os.path.basename (src)) 411 rc_file = os.path.join (rc_dir, base + '.rc') 412 # then compile .RC to .RES file 413 self.spawn ([self.rc] + 414 ["/fo" + obj] + [rc_file]) 415 416 except DistutilsExecError, msg: 417 raise CompileError, msg 418 continue 419 else: 420 # how to handle this file? 421 raise CompileError ( 422 "Don't know how to compile %s to %s" % \ 423 (src, obj)) 424 425 output_opt = "/Fo" + obj 426 try: 427 self.spawn ([self.cc] + compile_opts + pp_opts + 428 [input_opt, output_opt] + 429 extra_postargs) 430 except DistutilsExecError, msg: 431 raise CompileError, msg 432 433 return objects 434 435 # compile () 436 437 438 def create_static_lib (self, 439 objects, 440 output_libname, 441 output_dir=None, 442 debug=0, 443 target_lang=None): 444 445 if not self.initialized: self.initialize() 446 (objects, output_dir) = self._fix_object_args (objects, output_dir) 447 output_filename = \ 448 self.library_filename (output_libname, output_dir=output_dir) 449 450 if self._need_link (objects, output_filename): 451 lib_args = objects + ['/OUT:' + output_filename] 452 if debug: 453 pass # XXX what goes here? 454 try: 455 self.spawn ([self.lib] + lib_args) 456 except DistutilsExecError, msg: 457 raise LibError, msg 458 459 else: 460 log.debug("skipping %s (up-to-date)", output_filename) 461 462 # create_static_lib () 463 464 def link (self, 465 target_desc, 466 objects, 467 output_filename, 468 output_dir=None, 469 libraries=None, 470 library_dirs=None, 471 runtime_library_dirs=None, 472 export_symbols=None, 473 debug=0, 474 extra_preargs=None, 475 extra_postargs=None, 476 build_temp=None, 477 target_lang=None): 478 479 if not self.initialized: self.initialize() 480 (objects, output_dir) = self._fix_object_args (objects, output_dir) 481 (libraries, library_dirs, runtime_library_dirs) = \ 482 self._fix_lib_args (libraries, library_dirs, runtime_library_dirs) 483 484 if runtime_library_dirs: 485 self.warn ("I don't know what to do with 'runtime_library_dirs': " 486 + str (runtime_library_dirs)) 487 488 lib_opts = gen_lib_options (self, 489 library_dirs, runtime_library_dirs, 490 libraries) 491 if output_dir is not None: 492 output_filename = os.path.join (output_dir, output_filename) 493 494 if self._need_link (objects, output_filename): 495 496 if target_desc == CCompiler.EXECUTABLE: 497 if debug: 498 ldflags = self.ldflags_shared_debug[1:] 499 else: 500 ldflags = self.ldflags_shared[1:] 501 else: 502 if debug: 503 ldflags = self.ldflags_shared_debug 504 else: 505 ldflags = self.ldflags_shared 506 507 export_opts = [] 508 for sym in (export_symbols or []): 509 export_opts.append("/EXPORT:" + sym) 510 511 ld_args = (ldflags + lib_opts + export_opts + 512 objects + ['/OUT:' + output_filename]) 513 514 # The MSVC linker generates .lib and .exp files, which cannot be 515 # suppressed by any linker switches. The .lib files may even be 516 # needed! Make sure they are generated in the temporary build 517 # directory. Since they have different names for debug and release 518 # builds, they can go into the same directory. 519 if export_symbols is not None: 520 (dll_name, dll_ext) = os.path.splitext( 521 os.path.basename(output_filename)) 522 implib_file = os.path.join( 523 os.path.dirname(objects[0]), 524 self.library_filename(dll_name)) 525 ld_args.append ('/IMPLIB:' + implib_file) 526 527 if extra_preargs: 528 ld_args[:0] = extra_preargs 529 if extra_postargs: 530 ld_args.extend(extra_postargs) 531 532 self.mkpath (os.path.dirname (output_filename)) 533 try: 534 self.spawn ([self.linker] + ld_args) 535 except DistutilsExecError, msg: 536 raise LinkError, msg 537 538 else: 539 log.debug("skipping %s (up-to-date)", output_filename) 540 541 # link () 542 543 544 # -- Miscellaneous methods ----------------------------------------- 545 # These are all used by the 'gen_lib_options() function, in 546 # ccompiler.py. 547 548 def library_dir_option (self, dir): 549 return "/LIBPATH:" + dir 550 551 def runtime_library_dir_option (self, dir): 552 raise DistutilsPlatformError, \ 553 "don't know how to set runtime library search path for MSVC++" 554 555 def library_option (self, lib): 556 return self.library_filename (lib) 557 558 559 def find_library_file (self, dirs, lib, debug=0): 560 # Prefer a debugging library if found (and requested), but deal 561 # with it if we don't have one. 562 if debug: 563 try_names = [lib + "_d", lib] 564 else: 565 try_names = [lib] 566 for dir in dirs: 567 for name in try_names: 568 libfile = os.path.join(dir, self.library_filename (name)) 569 if os.path.exists(libfile): 570 return libfile 571 else: 572 # Oops, didn't find it in *any* of 'dirs' 573 return None 574 575 # find_library_file () 576 577 # Helper methods for using the MSVC registry settings 578 579 def find_exe(self, exe): 580 """Return path to an MSVC executable program. 581 582 Tries to find the program in several places: first, one of the 583 MSVC program search paths from the registry; next, the directories 584 in the PATH environment variable. If any of those work, return an 585 absolute path that is known to exist. If none of them work, just 586 return the original program name, 'exe'. 587 """ 588 589 for p in self.__paths: 590 fn = os.path.join(os.path.abspath(p), exe) 591 if os.path.isfile(fn): 592 return fn 593 594 # didn't find it; try existing path 595 for p in string.split(os.environ['Path'],';'): 596 fn = os.path.join(os.path.abspath(p),exe) 597 if os.path.isfile(fn): 598 return fn 599 600 return exe 601 602 def get_msvc_paths(self, path, platform='x86'): 603 """Get a list of devstudio directories (include, lib or path). 604 605 Return a list of strings. The list will be empty if unable to 606 access the registry or appropriate registry keys not found. 607 """ 608 609 if not _can_read_reg: 610 return [] 611 612 path = path + " dirs" 613 if self.__version >= 7: 614 key = (r"%s\%0.1f\VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories" 615 % (self.__root, self.__version)) 616 else: 617 key = (r"%s\6.0\Build System\Components\Platforms" 618 r"\Win32 (%s)\Directories" % (self.__root, platform)) 619 620 for base in HKEYS: 621 d = read_values(base, key) 622 if d: 623 if self.__version >= 7: 624 return string.split(self.__macros.sub(d[path]), ";") 625 else: 626 return string.split(d[path], ";") 627 # MSVC 6 seems to create the registry entries we need only when 628 # the GUI is run. 629 if self.__version == 6: 630 for base in HKEYS: 631 if read_values(base, r"%s\6.0" % self.__root) is not None: 632 self.warn("It seems you have Visual Studio 6 installed, " 633 "but the expected registry settings are not present.\n" 634 "You must at least run the Visual Studio GUI once " 635 "so that these entries are created.") 636 break 637 return [] 638 639 def set_path_env_var(self, name): 640 """Set environment variable 'name' to an MSVC path type value. 641 642 This is equivalent to a SET command prior to execution of spawned 643 commands. 644 """ 645 646 if name == "lib": 647 p = self.get_msvc_paths("library") 648 else: 649 p = self.get_msvc_paths(name) 650 if p: 651 os.environ[name] = string.join(p, ';') 652 653 654if get_build_version() >= 8.0: 655 log.debug("Importing new compiler from distutils.msvc9compiler") 656 OldMSVCCompiler = MSVCCompiler 657 from distutils.msvc9compiler import MSVCCompiler 658 # get_build_architecture not really relevant now we support cross-compile 659 from distutils.msvc9compiler import MacroExpander 660