source: python/trunk/Lib/distutils/msvccompiler.py@ 383

Last change on this file since 383 was 2, checked in by Yuri Dario, 15 years ago

Initial import for vendor code.

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