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