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