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