msvc9compiler.py (20557B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\stdlib\distutils\msvc9compiler.py 2 __revision__ = '$Id: msvc9compiler.py 87602 2011-01-01 04:24:26Z richard.tew $' 3 import os 4 import subprocess 5 import sys 6 import re 7 from distutils.errors import DistutilsExecError, DistutilsPlatformError, CompileError, LibError, LinkError 8 from distutils.ccompiler import CCompiler, gen_lib_options 9 from distutils import log 10 from distutils.util import get_platform 11 import _winreg 12 RegOpenKeyEx = _winreg.OpenKeyEx 13 RegEnumKey = _winreg.EnumKey 14 RegEnumValue = _winreg.EnumValue 15 RegError = _winreg.error 16 HKEYS = (_winreg.HKEY_USERS, 17 _winreg.HKEY_CURRENT_USER, 18 _winreg.HKEY_LOCAL_MACHINE, 19 _winreg.HKEY_CLASSES_ROOT) 20 NATIVE_WIN64 = sys.platform == 'win32' and sys.maxsize > 4294967296L 21 if NATIVE_WIN64: 22 VS_BASE = 'Software\\Wow6432Node\\Microsoft\\VisualStudio\\%0.1f' 23 VSEXPRESS_BASE = 'Software\\Wow6432Node\\Microsoft\\VCExpress\\%0.1f' 24 WINSDK_BASE = 'Software\\Wow6432Node\\Microsoft\\Microsoft SDKs\\Windows' 25 NET_BASE = 'Software\\Wow6432Node\\Microsoft\\.NETFramework' 26 else: 27 VS_BASE = 'Software\\Microsoft\\VisualStudio\\%0.1f' 28 VSEXPRESS_BASE = 'Software\\Microsoft\\VCExpress\\%0.1f' 29 WINSDK_BASE = 'Software\\Microsoft\\Microsoft SDKs\\Windows' 30 NET_BASE = 'Software\\Microsoft\\.NETFramework' 31 PLAT_TO_VCVARS = {'win32': 'x86', 32 'win-amd64': 'amd64', 33 'win-ia64': 'ia64'} 34 35 class Reg: 36 37 def get_value(cls, path, key): 38 for base in HKEYS: 39 d = cls.read_values(base, path) 40 if d and key in d: 41 return d[key] 42 43 raise KeyError(key) 44 45 get_value = classmethod(get_value) 46 47 def read_keys(cls, base, key): 48 try: 49 handle = RegOpenKeyEx(base, key) 50 except RegError: 51 return None 52 53 L = [] 54 i = 0 55 while True: 56 try: 57 k = RegEnumKey(handle, i) 58 except RegError: 59 break 60 61 L.append(k) 62 i += 1 63 64 return L 65 66 read_keys = classmethod(read_keys) 67 68 def read_values(cls, base, key): 69 try: 70 handle = RegOpenKeyEx(base, key) 71 except RegError: 72 return None 73 74 d = {} 75 i = 0 76 while True: 77 try: 78 name, value, type = RegEnumValue(handle, i) 79 except RegError: 80 break 81 82 name = name.lower() 83 d[cls.convert_mbcs(name)] = cls.convert_mbcs(value) 84 i += 1 85 86 return d 87 88 read_values = classmethod(read_values) 89 90 def convert_mbcs(s): 91 dec = getattr(s, 'decode', None) 92 if dec is not None: 93 try: 94 s = dec('mbcs') 95 except UnicodeError: 96 pass 97 98 return s 99 100 convert_mbcs = staticmethod(convert_mbcs) 101 102 103 class MacroExpander: 104 105 def __init__(self, version): 106 self.macros = {} 107 self.vsbase = VS_BASE % version 108 self.load_macros(version) 109 110 def set_macro(self, macro, path, key): 111 self.macros['$(%s)' % macro] = Reg.get_value(path, key) 112 113 def load_macros(self, version): 114 self.set_macro('VCInstallDir', self.vsbase + '\\Setup\\VC', 'productdir') 115 self.set_macro('VSInstallDir', self.vsbase + '\\Setup\\VS', 'productdir') 116 self.set_macro('FrameworkDir', NET_BASE, 'installroot') 117 try: 118 if version >= 8.0: 119 self.set_macro('FrameworkSDKDir', NET_BASE, 'sdkinstallrootv2.0') 120 else: 121 raise KeyError('sdkinstallrootv2.0') 122 except KeyError: 123 raise DistutilsPlatformError('Python was built with Visual Studio 2008;\nextensions must be built with a compiler than can generate compatible binaries.\nVisual Studio 2008 was not found on this system. If you have Cygwin installed,\nyou can try compiling with MingW32, by passing "-c mingw32" to setup.py.') 124 125 if version >= 9.0: 126 self.set_macro('FrameworkVersion', self.vsbase, 'clr version') 127 self.set_macro('WindowsSdkDir', WINSDK_BASE, 'currentinstallfolder') 128 else: 129 p = 'Software\\Microsoft\\NET Framework Setup\\Product' 130 for base in HKEYS: 131 try: 132 h = RegOpenKeyEx(base, p) 133 except RegError: 134 continue 135 136 key = RegEnumKey(h, 0) 137 d = Reg.get_value(base, '%s\\%s' % (p, key)) 138 self.macros['$(FrameworkVersion)'] = d['version'] 139 140 def sub(self, s): 141 for k, v in self.macros.items(): 142 s = s.replace(k, v) 143 144 return s 145 146 147 def get_build_version(): 148 prefix = 'MSC v.' 149 i = sys.version.find(prefix) 150 if i == -1: 151 return 6 152 i = i + len(prefix) 153 s, rest = sys.version[i:].split(' ', 1) 154 majorVersion = int(s[:-2]) - 6 155 minorVersion = int(s[2:3]) / 10.0 156 if majorVersion == 6: 157 minorVersion = 0 158 if majorVersion >= 6: 159 return majorVersion + minorVersion 160 161 162 def normalize_and_reduce_paths(paths): 163 reduced_paths = [] 164 for p in paths: 165 np = os.path.normpath(p) 166 if np not in reduced_paths: 167 reduced_paths.append(np) 168 169 return reduced_paths 170 171 172 def removeDuplicates(variable): 173 oldList = variable.split(os.pathsep) 174 newList = [] 175 for i in oldList: 176 if i not in newList: 177 newList.append(i) 178 179 newVariable = os.pathsep.join(newList) 180 return newVariable 181 182 183 def find_vcvarsall(version): 184 vsbase = VS_BASE % version 185 try: 186 productdir = Reg.get_value('%s\\Setup\\VC' % vsbase, 'productdir') 187 except KeyError: 188 productdir = None 189 190 if productdir is None: 191 vsbase = VSEXPRESS_BASE % version 192 try: 193 productdir = Reg.get_value('%s\\Setup\\VC' % vsbase, 'productdir') 194 except KeyError: 195 productdir = None 196 log.debug('Unable to find productdir in registry') 197 198 if not productdir or not os.path.isdir(productdir): 199 toolskey = 'VS%0.f0COMNTOOLS' % version 200 toolsdir = os.environ.get(toolskey, None) 201 if toolsdir and os.path.isdir(toolsdir): 202 productdir = os.path.join(toolsdir, os.pardir, os.pardir, 'VC') 203 productdir = os.path.abspath(productdir) 204 if not os.path.isdir(productdir): 205 log.debug('%s is not a valid directory' % productdir) 206 return 207 else: 208 log.debug('Env var %s is not set or invalid' % toolskey) 209 if not productdir: 210 log.debug('No productdir found') 211 return 212 vcvarsall = os.path.join(productdir, 'vcvarsall.bat') 213 if os.path.isfile(vcvarsall): 214 return vcvarsall 215 log.debug('Unable to find vcvarsall.bat') 216 217 218 def query_vcvarsall(version, arch = 'x86'): 219 vcvarsall = find_vcvarsall(version) 220 interesting = set(('include', 'lib', 'libpath', 'path')) 221 result = {} 222 if vcvarsall is None: 223 raise DistutilsPlatformError('Unable to find vcvarsall.bat') 224 log.debug("Calling 'vcvarsall.bat %s' (version=%s)", arch, version) 225 popen = subprocess.Popen('"%s" %s & set' % (vcvarsall, arch), stdout=subprocess.PIPE, stderr=subprocess.PIPE) 226 try: 227 stdout, stderr = popen.communicate() 228 if popen.wait() != 0: 229 raise DistutilsPlatformError(stderr.decode('mbcs')) 230 stdout = stdout.decode('mbcs') 231 for line in stdout.split('\n'): 232 line = Reg.convert_mbcs(line) 233 if '=' not in line: 234 continue 235 line = line.strip() 236 key, value = line.split('=', 1) 237 key = key.lower() 238 if key in interesting: 239 if value.endswith(os.pathsep): 240 value = value[:-1] 241 result[key] = removeDuplicates(value) 242 243 finally: 244 popen.stdout.close() 245 popen.stderr.close() 246 247 if len(result) != len(interesting): 248 raise ValueError(str(list(result.keys()))) 249 return result 250 251 252 VERSION = get_build_version() 253 if VERSION < 8.0: 254 raise DistutilsPlatformError('VC %0.1f is not supported by this module' % VERSION) 255 256 class MSVCCompiler(CCompiler): 257 compiler_type = 'msvc' 258 executables = {} 259 _c_extensions = ['.c'] 260 _cpp_extensions = ['.cc', '.cpp', '.cxx'] 261 _rc_extensions = ['.rc'] 262 _mc_extensions = ['.mc'] 263 src_extensions = _c_extensions + _cpp_extensions + _rc_extensions + _mc_extensions 264 res_extension = '.res' 265 obj_extension = '.obj' 266 static_lib_extension = '.lib' 267 shared_lib_extension = '.dll' 268 static_lib_format = shared_lib_format = '%s%s' 269 exe_extension = '.exe' 270 271 def __init__(self, verbose = 0, dry_run = 0, force = 0): 272 CCompiler.__init__(self, verbose, dry_run, force) 273 self.__version = VERSION 274 self.__root = 'Software\\Microsoft\\VisualStudio' 275 self.__paths = [] 276 self.plat_name = None 277 self.__arch = None 278 self.initialized = False 279 280 def initialize(self, plat_name = None): 281 if plat_name is None: 282 plat_name = get_platform() 283 ok_plats = ('win32', 'win-amd64', 'win-ia64') 284 if plat_name not in ok_plats: 285 raise DistutilsPlatformError('--plat-name must be one of %s' % (ok_plats,)) 286 if 'DISTUTILS_USE_SDK' in os.environ and 'MSSdk' in os.environ and self.find_exe('cl.exe'): 287 self.cc = 'cl.exe' 288 self.linker = 'link.exe' 289 self.lib = 'lib.exe' 290 self.rc = 'rc.exe' 291 self.mc = 'mc.exe' 292 else: 293 if plat_name == get_platform() or plat_name == 'win32': 294 plat_spec = PLAT_TO_VCVARS[plat_name] 295 else: 296 plat_spec = PLAT_TO_VCVARS[get_platform()] + '_' + PLAT_TO_VCVARS[plat_name] 297 vc_env = query_vcvarsall(VERSION, plat_spec) 298 self.__paths = vc_env['path'].encode('mbcs').split(os.pathsep) 299 os.environ['lib'] = vc_env['lib'].encode('mbcs') 300 os.environ['include'] = vc_env['include'].encode('mbcs') 301 if len(self.__paths) == 0: 302 raise DistutilsPlatformError("Python was built with %s, and extensions need to be built with the same version of the compiler, but it isn't installed." % self.__product) 303 self.cc = self.find_exe('cl.exe') 304 self.linker = self.find_exe('link.exe') 305 self.lib = self.find_exe('lib.exe') 306 self.rc = self.find_exe('rc.exe') 307 self.mc = self.find_exe('mc.exe') 308 try: 309 for p in os.environ['path'].split(';'): 310 self.__paths.append(p) 311 312 except KeyError: 313 pass 314 315 self.__paths = normalize_and_reduce_paths(self.__paths) 316 os.environ['path'] = ';'.join(self.__paths) 317 self.preprocess_options = None 318 if self.__arch == 'x86': 319 self.compile_options = ['/nologo', 320 '/Ox', 321 '/MD', 322 '/W3', 323 '/DNDEBUG'] 324 self.compile_options_debug = ['/nologo', 325 '/Od', 326 '/MDd', 327 '/W3', 328 '/Z7', 329 '/D_DEBUG'] 330 else: 331 self.compile_options = ['/nologo', 332 '/Ox', 333 '/MD', 334 '/W3', 335 '/GS-', 336 '/DNDEBUG'] 337 self.compile_options_debug = ['/nologo', 338 '/Od', 339 '/MDd', 340 '/W3', 341 '/GS-', 342 '/Z7', 343 '/D_DEBUG'] 344 self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO'] 345 if self.__version >= 7: 346 self.ldflags_shared_debug = ['/DLL', 347 '/nologo', 348 '/INCREMENTAL:no', 349 '/DEBUG', 350 '/pdb:None'] 351 self.ldflags_static = ['/nologo'] 352 self.initialized = True 353 354 def object_filenames(self, source_filenames, strip_dir = 0, output_dir = ''): 355 if output_dir is None: 356 output_dir = '' 357 obj_names = [] 358 for src_name in source_filenames: 359 base, ext = os.path.splitext(src_name) 360 base = os.path.splitdrive(base)[1] 361 base = base[os.path.isabs(base):] 362 if ext not in self.src_extensions: 363 raise CompileError("Don't know how to compile %s" % src_name) 364 if strip_dir: 365 base = os.path.basename(base) 366 if ext in self._rc_extensions: 367 obj_names.append(os.path.join(output_dir, base + self.res_extension)) 368 elif ext in self._mc_extensions: 369 obj_names.append(os.path.join(output_dir, base + self.res_extension)) 370 else: 371 obj_names.append(os.path.join(output_dir, base + self.obj_extension)) 372 373 return obj_names 374 375 def compile(self, sources, output_dir = None, macros = None, include_dirs = None, debug = 0, extra_preargs = None, extra_postargs = None, depends = None): 376 if not self.initialized: 377 self.initialize() 378 compile_info = self._setup_compile(output_dir, macros, include_dirs, sources, depends, extra_postargs) 379 macros, objects, extra_postargs, pp_opts, build = compile_info 380 compile_opts = extra_preargs or [] 381 compile_opts.append('/c') 382 if debug: 383 compile_opts.extend(self.compile_options_debug) 384 else: 385 compile_opts.extend(self.compile_options) 386 for obj in objects: 387 try: 388 src, ext = build[obj] 389 except KeyError: 390 continue 391 392 if debug: 393 src = os.path.abspath(src) 394 if ext in self._c_extensions: 395 input_opt = '/Tc' + src 396 elif ext in self._cpp_extensions: 397 input_opt = '/Tp' + src 398 elif ext in self._rc_extensions: 399 input_opt = src 400 output_opt = '/fo' + obj 401 try: 402 self.spawn([self.rc] + pp_opts + [output_opt] + [input_opt]) 403 except DistutilsExecError as msg: 404 raise CompileError(msg) 405 406 continue 407 elif ext in self._mc_extensions: 408 h_dir = os.path.dirname(src) 409 rc_dir = os.path.dirname(obj) 410 try: 411 self.spawn([self.mc] + ['-h', 412 h_dir, 413 '-r', 414 rc_dir] + [src]) 415 base, _ = os.path.splitext(os.path.basename(src)) 416 rc_file = os.path.join(rc_dir, base + '.rc') 417 self.spawn([self.rc] + ['/fo' + obj] + [rc_file]) 418 except DistutilsExecError as msg: 419 raise CompileError(msg) 420 421 continue 422 else: 423 raise CompileError("Don't know how to compile %s to %s" % (src, obj)) 424 output_opt = '/Fo' + obj 425 try: 426 self.spawn([self.cc] + compile_opts + pp_opts + [input_opt, output_opt] + extra_postargs) 427 except DistutilsExecError as msg: 428 raise CompileError(msg) 429 430 return objects 431 432 def create_static_lib(self, objects, output_libname, output_dir = None, debug = 0, target_lang = None): 433 if not self.initialized: 434 self.initialize() 435 objects, output_dir = self._fix_object_args(objects, output_dir) 436 output_filename = self.library_filename(output_libname, output_dir=output_dir) 437 if self._need_link(objects, output_filename): 438 lib_args = objects + ['/OUT:' + output_filename] 439 if debug: 440 pass 441 try: 442 self.spawn([self.lib] + lib_args) 443 except DistutilsExecError as msg: 444 raise LibError(msg) 445 446 else: 447 log.debug('skipping %s (up-to-date)', output_filename) 448 449 def link(self, target_desc, objects, output_filename, output_dir = None, libraries = None, library_dirs = None, runtime_library_dirs = None, export_symbols = None, debug = 0, extra_preargs = None, extra_postargs = None, build_temp = None, target_lang = None): 450 if not self.initialized: 451 self.initialize() 452 objects, output_dir = self._fix_object_args(objects, output_dir) 453 fixed_args = self._fix_lib_args(libraries, library_dirs, runtime_library_dirs) 454 libraries, library_dirs, runtime_library_dirs = fixed_args 455 if runtime_library_dirs: 456 self.warn("I don't know what to do with 'runtime_library_dirs': " + str(runtime_library_dirs)) 457 lib_opts = gen_lib_options(self, library_dirs, runtime_library_dirs, libraries) 458 if output_dir is not None: 459 output_filename = os.path.join(output_dir, output_filename) 460 if self._need_link(objects, output_filename): 461 if target_desc == CCompiler.EXECUTABLE: 462 if debug: 463 ldflags = self.ldflags_shared_debug[1:] 464 else: 465 ldflags = self.ldflags_shared[1:] 466 elif debug: 467 ldflags = self.ldflags_shared_debug 468 else: 469 ldflags = self.ldflags_shared 470 export_opts = [] 471 for sym in export_symbols or []: 472 export_opts.append('/EXPORT:' + sym) 473 474 ld_args = ldflags + lib_opts + export_opts + objects + ['/OUT:' + output_filename] 475 build_temp = os.path.dirname(objects[0]) 476 if export_symbols is not None: 477 dll_name, dll_ext = os.path.splitext(os.path.basename(output_filename)) 478 implib_file = os.path.join(build_temp, self.library_filename(dll_name)) 479 ld_args.append('/IMPLIB:' + implib_file) 480 temp_manifest = os.path.join(build_temp, os.path.basename(output_filename) + '.manifest') 481 ld_args.append('/MANIFESTFILE:' + temp_manifest) 482 if extra_preargs: 483 ld_args[:0] = extra_preargs 484 if extra_postargs: 485 ld_args.extend(extra_postargs) 486 self.mkpath(os.path.dirname(output_filename)) 487 try: 488 self.spawn([self.linker] + ld_args) 489 except DistutilsExecError as msg: 490 raise LinkError(msg) 491 492 if target_desc == CCompiler.EXECUTABLE: 493 mfid = 1 494 else: 495 mfid = 2 496 self._remove_visual_c_ref(temp_manifest) 497 out_arg = '-outputresource:%s;%s' % (output_filename, mfid) 498 try: 499 self.spawn(['mt.exe', 500 '-nologo', 501 '-manifest', 502 temp_manifest, 503 out_arg]) 504 except DistutilsExecError as msg: 505 raise LinkError(msg) 506 507 else: 508 log.debug('skipping %s (up-to-date)', output_filename) 509 510 def _remove_visual_c_ref(self, manifest_file): 511 try: 512 manifest_f = open(manifest_file) 513 try: 514 manifest_buf = manifest_f.read() 515 finally: 516 manifest_f.close() 517 518 pattern = re.compile('<assemblyIdentity.*?name=("|\')Microsoft\\.VC\\d{2}\\.CRT("|\').*?(/>|</assemblyIdentity>)', re.DOTALL) 519 manifest_buf = re.sub(pattern, '', manifest_buf) 520 pattern = '<dependentAssembly>\\s*</dependentAssembly>' 521 manifest_buf = re.sub(pattern, '', manifest_buf) 522 manifest_f = open(manifest_file, 'w') 523 try: 524 manifest_f.write(manifest_buf) 525 finally: 526 manifest_f.close() 527 528 except IOError: 529 pass 530 531 def library_dir_option(self, dir): 532 return '/LIBPATH:' + dir 533 534 def runtime_library_dir_option(self, dir): 535 raise DistutilsPlatformError("don't know how to set runtime library search path for MSVC++") 536 537 def library_option(self, lib): 538 return self.library_filename(lib) 539 540 def find_library_file(self, dirs, lib, debug = 0): 541 if debug: 542 try_names = [lib + '_d', lib] 543 else: 544 try_names = [lib] 545 for dir in dirs: 546 for name in try_names: 547 libfile = os.path.join(dir, self.library_filename(name)) 548 if os.path.exists(libfile): 549 return libfile 550 551 else: 552 return None 553 554 def find_exe(self, exe): 555 for p in self.__paths: 556 fn = os.path.join(os.path.abspath(p), exe) 557 if os.path.isfile(fn): 558 return fn 559 560 for p in os.environ['Path'].split(';'): 561 fn = os.path.join(os.path.abspath(p), exe) 562 if os.path.isfile(fn): 563 return fn 564 565 return exe