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