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