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