0001 """distutils.msvccompiler 0002 0003 Contains MSVCCompiler, an implementation of the abstract CCompiler class 0004 for the Microsoft Visual Studio. 0005 """ 0006 0007 # Written by Perry Stoll 0008 # hacked by Robin Becker and Thomas Heller to do a better job of 0009 # finding DevStudio (through the registry) 0010 0011 # This module should be kept compatible with Python 1.5.2. 0012 0013 __revision__ = "$Id: msvccompiler.py,v 1.60 2004/07/18 06:14:42 tim_one Exp $" 0014 0015 import sys, os, string 0016 from distutils.errors import \ 0017 DistutilsExecError, DistutilsPlatformError, \ 0018 CompileError, LibError, LinkError 0019 from distutils.ccompiler import \ 0020 CCompiler, gen_preprocess_options, gen_lib_options 0021 from distutils import log 0022 0023 _can_read_reg = 0 0024 try: 0025 import _winreg 0026 0027 _can_read_reg = 1 0028 hkey_mod = _winreg 0029 0030 RegOpenKeyEx = _winreg.OpenKeyEx 0031 RegEnumKey = _winreg.EnumKey 0032 RegEnumValue = _winreg.EnumValue 0033 RegError = _winreg.error 0034 0035 except ImportError: 0036 try: 0037 import win32api 0038 import win32con 0039 _can_read_reg = 1 0040 hkey_mod = win32con 0041 0042 RegOpenKeyEx = win32api.RegOpenKeyEx 0043 RegEnumKey = win32api.RegEnumKey 0044 RegEnumValue = win32api.RegEnumValue 0045 RegError = win32api.error 0046 0047 except ImportError: 0048 log.info("Warning: Can't read registry to find the " 0049 "necessary compiler setting\n" 0050 "Make sure that Python modules _winreg, " 0051 "win32api or win32con are installed.") 0052 pass 0053 0054 if _can_read_reg: 0055 HKEYS = (hkey_mod.HKEY_USERS, 0056 hkey_mod.HKEY_CURRENT_USER, 0057 hkey_mod.HKEY_LOCAL_MACHINE, 0058 hkey_mod.HKEY_CLASSES_ROOT) 0059 0060 def read_keys(base, key): 0061 """Return list of registry keys.""" 0062 0063 try: 0064 handle = RegOpenKeyEx(base, key) 0065 except RegError: 0066 return None 0067 L = [] 0068 i = 0 0069 while 1: 0070 try: 0071 k = RegEnumKey(handle, i) 0072 except RegError: 0073 break 0074 L.append(k) 0075 i = i + 1 0076 return L 0077 0078 def read_values(base, key): 0079 """Return dict of registry keys and values. 0080 0081 All names are converted to lowercase. 0082 """ 0083 try: 0084 handle = RegOpenKeyEx(base, key) 0085 except RegError: 0086 return None 0087 d = {} 0088 i = 0 0089 while 1: 0090 try: 0091 name, value, type = RegEnumValue(handle, i) 0092 except RegError: 0093 break 0094 name = name.lower() 0095 d[convert_mbcs(name)] = convert_mbcs(value) 0096 i = i + 1 0097 return d 0098 0099 def convert_mbcs(s): 0100 enc = getattr(s, "encode", None) 0101 if enc is not None: 0102 try: 0103 s = enc("mbcs") 0104 except UnicodeError: 0105 pass 0106 return s 0107 0108 class MacroExpander: 0109 0110 def __init__(self, version): 0111 self.macros = {} 0112 self.load_macros(version) 0113 0114 def set_macro(self, macro, path, key): 0115 for base in HKEYS: 0116 d = read_values(base, path) 0117 if d: 0118 self.macros["$(%s)" % macro] = d[key] 0119 break 0120 0121 def load_macros(self, version): 0122 vsbase = r"Software\Microsoft\VisualStudio\%0.1f" % version 0123 self.set_macro("VCInstallDir", vsbase + r"\Setup\VC", "productdir") 0124 self.set_macro("VSInstallDir", vsbase + r"\Setup\VS", "productdir") 0125 net = r"Software\Microsoft\.NETFramework" 0126 self.set_macro("FrameworkDir", net, "installroot") 0127 if version > 7.0: 0128 self.set_macro("FrameworkSDKDir", net, "sdkinstallrootv1.1") 0129 else: 0130 self.set_macro("FrameworkSDKDir", net, "sdkinstallroot") 0131 0132 p = r"Software\Microsoft\NET Framework Setup\Product" 0133 for base in HKEYS: 0134 try: 0135 h = RegOpenKeyEx(base, p) 0136 except RegError: 0137 continue 0138 key = RegEnumKey(h, 0) 0139 d = read_values(base, r"%s\%s" % (p, key)) 0140 self.macros["$(FrameworkVersion)"] = d["version"] 0141 0142 def sub(self, s): 0143 for k, v in self.macros.items(): 0144 s = string.replace(s, k, v) 0145 return s 0146 0147 def get_build_version(): 0148 """Return the version of MSVC that was used to build Python. 0149 0150 For Python 2.3 and up, the version number is included in 0151 sys.version. For earlier versions, assume the compiler is MSVC 6. 0152 """ 0153 0154 prefix = "MSC v." 0155 i = string.find(sys.version, prefix) 0156 if i == -1: 0157 return 6 0158 i = i + len(prefix) 0159 s, rest = sys.version[i:].split(" ", 1) 0160 majorVersion = int(s[:-2]) - 6 0161 minorVersion = int(s[2:3]) / 10.0 0162 # I don't think paths are affected by minor version in version 6 0163 if majorVersion == 6: 0164 minorVersion = 0 0165 if majorVersion >= 6: 0166 return majorVersion + minorVersion 0167 # else we don't know what version of the compiler this is 0168 return None 0169 0170 0171 class MSVCCompiler (CCompiler) : 0172 """Concrete class that implements an interface to Microsoft Visual C++, 0173 as defined by the CCompiler abstract class.""" 0174 0175 compiler_type = 'msvc' 0176 0177 # Just set this so CCompiler's constructor doesn't barf. We currently 0178 # don't use the 'set_executables()' bureaucracy provided by CCompiler, 0179 # as it really isn't necessary for this sort of single-compiler class. 0180 # Would be nice to have a consistent interface with UnixCCompiler, 0181 # though, so it's worth thinking about. 0182 executables = {} 0183 0184 # Private class data (need to distinguish C from C++ source for compiler) 0185 _c_extensions = ['.c'] 0186 _cpp_extensions = ['.cc', '.cpp', '.cxx'] 0187 _rc_extensions = ['.rc'] 0188 _mc_extensions = ['.mc'] 0189 0190 # Needed for the filename generation methods provided by the 0191 # base class, CCompiler. 0192 src_extensions = (_c_extensions + _cpp_extensions + 0193 _rc_extensions + _mc_extensions) 0194 res_extension = '.res' 0195 obj_extension = '.obj' 0196 static_lib_extension = '.lib' 0197 shared_lib_extension = '.dll' 0198 static_lib_format = shared_lib_format = '%s%s' 0199 exe_extension = '.exe' 0200 0201 def __init__ (self, verbose=0, dry_run=0, force=0): 0202 CCompiler.__init__ (self, verbose, dry_run, force) 0203 self.__version = get_build_version() 0204 if self.__version >= 7: 0205 self.__root = r"Software\Microsoft\VisualStudio" 0206 self.__macros = MacroExpander(self.__version) 0207 else: 0208 self.__root = r"Software\Microsoft\Devstudio" 0209 self.__paths = self.get_msvc_paths("path") 0210 0211 if len (self.__paths) == 0: 0212 raise DistutilsPlatformError, \ 0213 ("Python was built with version %s of Visual Studio, " 0214 "and extensions need to be built with the same " 0215 "version of the compiler, but it isn't installed." % self.__version) 0216 0217 self.cc = self.find_exe("cl.exe") 0218 self.linker = self.find_exe("link.exe") 0219 self.lib = self.find_exe("lib.exe") 0220 self.rc = self.find_exe("rc.exe") # resource compiler 0221 self.mc = self.find_exe("mc.exe") # message compiler 0222 self.set_path_env_var('lib') 0223 self.set_path_env_var('include') 0224 0225 # extend the MSVC path with the current path 0226 try: 0227 for p in string.split(os.environ['path'], ';'): 0228 self.__paths.append(p) 0229 except KeyError: 0230 pass 0231 os.environ['path'] = string.join(self.__paths, ';') 0232 0233 self.preprocess_options = None 0234 self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GX' , 0235 '/DNDEBUG'] 0236 self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GX', 0237 '/Z7', '/D_DEBUG'] 0238 0239 self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO'] 0240 self.ldflags_shared_debug = [ 0241 '/DLL', '/nologo', '/INCREMENTAL:no', '/pdb:None', '/DEBUG' 0242 ] 0243 self.ldflags_static = [ '/nologo'] 0244 0245 0246 # -- Worker methods ------------------------------------------------ 0247 0248 def object_filenames (self, 0249 source_filenames, 0250 strip_dir=0, 0251 output_dir=''): 0252 # Copied from ccompiler.py, extended to return .res as 'object'-file 0253 # for .rc input file 0254 if output_dir is None: output_dir = '' 0255 obj_names = [] 0256 for src_name in source_filenames: 0257 (base, ext) = os.path.splitext (src_name) 0258 if ext not in self.src_extensions: 0259 # Better to raise an exception instead of silently continuing 0260 # and later complain about sources and targets having 0261 # different lengths 0262 raise CompileError ("Don't know how to compile %s" % src_name) 0263 if strip_dir: 0264 base = os.path.basename (base) 0265 if ext in self._rc_extensions: 0266 obj_names.append (os.path.join (output_dir, 0267 base + self.res_extension)) 0268 elif ext in self._mc_extensions: 0269 obj_names.append (os.path.join (output_dir, 0270 base + self.res_extension)) 0271 else: 0272 obj_names.append (os.path.join (output_dir, 0273 base + self.obj_extension)) 0274 return obj_names 0275 0276 # object_filenames () 0277 0278 0279 def compile(self, sources, 0280 output_dir=None, macros=None, include_dirs=None, debug=0, 0281 extra_preargs=None, extra_postargs=None, depends=None): 0282 0283 macros, objects, extra_postargs, pp_opts, build = \ 0284 self._setup_compile(output_dir, macros, include_dirs, sources, 0285 depends, extra_postargs) 0286 0287 compile_opts = extra_preargs or [] 0288 compile_opts.append ('/c') 0289 if debug: 0290 compile_opts.extend(self.compile_options_debug) 0291 else: 0292 compile_opts.extend(self.compile_options) 0293 0294 for obj in objects: 0295 try: 0296 src, ext = build[obj] 0297 except KeyError: 0298 continue 0299 if debug: 0300 # pass the full pathname to MSVC in debug mode, 0301 # this allows the debugger to find the source file 0302 # without asking the user to browse for it 0303 src = os.path.abspath(src) 0304 0305 if ext in self._c_extensions: 0306 input_opt = "/Tc" + src 0307 elif ext in self._cpp_extensions: 0308 input_opt = "/Tp" + src 0309 elif ext in self._rc_extensions: 0310 # compile .RC to .RES file 0311 input_opt = src 0312 output_opt = "/fo" + obj 0313 try: 0314 self.spawn ([self.rc] + pp_opts + 0315 [output_opt] + [input_opt]) 0316 except DistutilsExecError, msg: 0317 raise CompileError, msg 0318 continue 0319 elif ext in self._mc_extensions: 0320 0321 # Compile .MC to .RC file to .RES file. 0322 # * '-h dir' specifies the directory for the 0323 # generated include file 0324 # * '-r dir' specifies the target directory of the 0325 # generated RC file and the binary message resource 0326 # it includes 0327 # 0328 # For now (since there are no options to change this), 0329 # we use the source-directory for the include file and 0330 # the build directory for the RC file and message 0331 # resources. This works at least for win32all. 0332 0333 h_dir = os.path.dirname (src) 0334 rc_dir = os.path.dirname (obj) 0335 try: 0336 # first compile .MC to .RC and .H file 0337 self.spawn ([self.mc] + 0338 ['-h', h_dir, '-r', rc_dir] + [src]) 0339 base, _ = os.path.splitext (os.path.basename (src)) 0340 rc_file = os.path.join (rc_dir, base + '.rc') 0341 # then compile .RC to .RES file 0342 self.spawn ([self.rc] + 0343 ["/fo" + obj] + [rc_file]) 0344 0345 except DistutilsExecError, msg: 0346 raise CompileError, msg 0347 continue 0348 else: 0349 # how to handle this file? 0350 raise CompileError ( 0351 "Don't know how to compile %s to %s" % \ 0352 (src, obj)) 0353 0354 output_opt = "/Fo" + obj 0355 try: 0356 self.spawn ([self.cc] + compile_opts + pp_opts + 0357 [input_opt, output_opt] + 0358 extra_postargs) 0359 except DistutilsExecError, msg: 0360 raise CompileError, msg 0361 0362 return objects 0363 0364 # compile () 0365 0366 0367 def create_static_lib (self, 0368 objects, 0369 output_libname, 0370 output_dir=None, 0371 debug=0, 0372 target_lang=None): 0373 0374 (objects, output_dir) = self._fix_object_args (objects, output_dir) 0375 output_filename = \ 0376 self.library_filename (output_libname, output_dir=output_dir) 0377 0378 if self._need_link (objects, output_filename): 0379 lib_args = objects + ['/OUT:' + output_filename] 0380 if debug: 0381 pass # XXX what goes here? 0382 try: 0383 self.spawn ([self.lib] + lib_args) 0384 except DistutilsExecError, msg: 0385 raise LibError, msg 0386 0387 else: 0388 log.debug("skipping %s (up-to-date)", output_filename) 0389 0390 # create_static_lib () 0391 0392 def link (self, 0393 target_desc, 0394 objects, 0395 output_filename, 0396 output_dir=None, 0397 libraries=None, 0398 library_dirs=None, 0399 runtime_library_dirs=None, 0400 export_symbols=None, 0401 debug=0, 0402 extra_preargs=None, 0403 extra_postargs=None, 0404 build_temp=None, 0405 target_lang=None): 0406 0407 (objects, output_dir) = self._fix_object_args (objects, output_dir) 0408 (libraries, library_dirs, runtime_library_dirs) = \ 0409 self._fix_lib_args (libraries, library_dirs, runtime_library_dirs) 0410 0411 if runtime_library_dirs: 0412 self.warn ("I don't know what to do with 'runtime_library_dirs': " 0413 + str (runtime_library_dirs)) 0414 0415 lib_opts = gen_lib_options (self, 0416 library_dirs, runtime_library_dirs, 0417 libraries) 0418 if output_dir is not None: 0419 output_filename = os.path.join (output_dir, output_filename) 0420 0421 if self._need_link (objects, output_filename): 0422 0423 if target_desc == CCompiler.EXECUTABLE: 0424 if debug: 0425 ldflags = self.ldflags_shared_debug[1:] 0426 else: 0427 ldflags = self.ldflags_shared[1:] 0428 else: 0429 if debug: 0430 ldflags = self.ldflags_shared_debug 0431 else: 0432 ldflags = self.ldflags_shared 0433 0434 export_opts = [] 0435 for sym in (export_symbols or []): 0436 export_opts.append("/EXPORT:" + sym) 0437 0438 ld_args = (ldflags + lib_opts + export_opts + 0439 objects + ['/OUT:' + output_filename]) 0440 0441 # The MSVC linker generates .lib and .exp files, which cannot be 0442 # suppressed by any linker switches. The .lib files may even be 0443 # needed! Make sure they are generated in the temporary build 0444 # directory. Since they have different names for debug and release 0445 # builds, they can go into the same directory. 0446 if export_symbols is not None: 0447 (dll_name, dll_ext) = os.path.splitext( 0448 os.path.basename(output_filename)) 0449 implib_file = os.path.join( 0450 os.path.dirname(objects[0]), 0451 self.library_filename(dll_name)) 0452 ld_args.append ('/IMPLIB:' + implib_file) 0453 0454 if extra_preargs: 0455 ld_args[:0] = extra_preargs 0456 if extra_postargs: 0457 ld_args.extend(extra_postargs) 0458 0459 self.mkpath (os.path.dirname (output_filename)) 0460 try: 0461 self.spawn ([self.linker] + ld_args) 0462 except DistutilsExecError, msg: 0463 raise LinkError, msg 0464 0465 else: 0466 log.debug("skipping %s (up-to-date)", output_filename) 0467 0468 # link () 0469 0470 0471 # -- Miscellaneous methods ----------------------------------------- 0472 # These are all used by the 'gen_lib_options() function, in 0473 # ccompiler.py. 0474 0475 def library_dir_option (self, dir): 0476 return "/LIBPATH:" + dir 0477 0478 def runtime_library_dir_option (self, dir): 0479 raise DistutilsPlatformError, \ 0480 "don't know how to set runtime library search path for MSVC++" 0481 0482 def library_option (self, lib): 0483 return self.library_filename (lib) 0484 0485 0486 def find_library_file (self, dirs, lib, debug=0): 0487 # Prefer a debugging library if found (and requested), but deal 0488 # with it if we don't have one. 0489 if debug: 0490 try_names = [lib + "_d", lib] 0491 else: 0492 try_names = [lib] 0493 for dir in dirs: 0494 for name in try_names: 0495 libfile = os.path.join(dir, self.library_filename (name)) 0496 if os.path.exists(libfile): 0497 return libfile 0498 else: 0499 # Oops, didn't find it in *any* of 'dirs' 0500 return None 0501 0502 # find_library_file () 0503 0504 # Helper methods for using the MSVC registry settings 0505 0506 def find_exe(self, exe): 0507 """Return path to an MSVC executable program. 0508 0509 Tries to find the program in several places: first, one of the 0510 MSVC program search paths from the registry; next, the directories 0511 in the PATH environment variable. If any of those work, return an 0512 absolute path that is known to exist. If none of them work, just 0513 return the original program name, 'exe'. 0514 """ 0515 0516 for p in self.__paths: 0517 fn = os.path.join(os.path.abspath(p), exe) 0518 if os.path.isfile(fn): 0519 return fn 0520 0521 # didn't find it; try existing path 0522 for p in string.split(os.environ['Path'],';'): 0523 fn = os.path.join(os.path.abspath(p),exe) 0524 if os.path.isfile(fn): 0525 return fn 0526 0527 return exe 0528 0529 def get_msvc_paths(self, path, platform='x86'): 0530 """Get a list of devstudio directories (include, lib or path). 0531 0532 Return a list of strings. The list will be empty if unable to 0533 access the registry or appropriate registry keys not found. 0534 """ 0535 0536 if not _can_read_reg: 0537 return [] 0538 0539 path = path + " dirs" 0540 if self.__version >= 7: 0541 key = (r"%s\%0.1f\VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories" 0542 % (self.__root, self.__version)) 0543 else: 0544 key = (r"%s\6.0\Build System\Components\Platforms" 0545 r"\Win32 (%s)\Directories" % (self.__root, platform)) 0546 0547 for base in HKEYS: 0548 d = read_values(base, key) 0549 if d: 0550 if self.__version >= 7: 0551 return string.split(self.__macros.sub(d[path]), ";") 0552 else: 0553 return string.split(d[path], ";") 0554 # MSVC 6 seems to create the registry entries we need only when 0555 # the GUI is run. 0556 if self.__version == 6: 0557 for base in HKEYS: 0558 if read_values(base, r"%s\6.0" % self.__root) is not None: 0559 self.warn("It seems you have Visual Studio 6 installed, " 0560 "but the expected registry settings are not present.\n" 0561 "You must at least run the Visual Studio GUI once " 0562 "so that these entries are created.") 0563 break 0564 return [] 0565 0566 def set_path_env_var(self, name): 0567 """Set environment variable 'name' to an MSVC path type value. 0568 0569 This is equivalent to a SET command prior to execution of spawned 0570 commands. 0571 """ 0572 0573 if name == "lib": 0574 p = self.get_msvc_paths("library") 0575 else: 0576 p = self.get_msvc_paths(name) 0577 if p: 0578 os.environ[name] = string.join(p, ';') 0579
Generated by PyXR 0.9.4