Use full package paths in imports.
[python/dscho.git] / Lib / distutils / msvccompiler.py
blob65b114353e8c2231a4a528cc138b4cc08bd64aba
1 """distutils.msvccompiler
3 Contains MSVCCompiler, an implementation of the abstract CCompiler class
4 for the Microsoft Visual Studio."""
7 # created 1999/08/19, 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 types import *
15 from distutils.errors import \
16 DistutilsExecError, DistutilsPlatformError, \
17 CompileError, LibError, LinkError
18 from distutils.ccompiler import \
19 CCompiler, gen_preprocess_options, 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 pass
49 if _can_read_reg:
50 HKEY_CLASSES_ROOT = hkey_mod.HKEY_CLASSES_ROOT
51 HKEY_LOCAL_MACHINE = hkey_mod.HKEY_LOCAL_MACHINE
52 HKEY_CURRENT_USER = hkey_mod.HKEY_CURRENT_USER
53 HKEY_USERS = hkey_mod.HKEY_USERS
57 def get_devstudio_versions ():
58 """Get list of devstudio versions from the Windows registry. Return a
59 list of strings containing version numbers; the list will be
60 empty if we were unable to access the registry (eg. couldn't import
61 a registry-access module) or the appropriate registry keys weren't
62 found."""
64 if not _can_read_reg:
65 return []
67 K = 'Software\\Microsoft\\Devstudio'
68 L = []
69 for base in (HKEY_CLASSES_ROOT,
70 HKEY_LOCAL_MACHINE,
71 HKEY_CURRENT_USER,
72 HKEY_USERS):
73 try:
74 k = RegOpenKeyEx(base,K)
75 i = 0
76 while 1:
77 try:
78 p = RegEnumKey(k,i)
79 if p[0] in '123456789' and p not in L:
80 L.append(p)
81 except RegError:
82 break
83 i = i + 1
84 except RegError:
85 pass
86 L.sort()
87 L.reverse()
88 return L
90 # get_devstudio_versions ()
93 def get_msvc_paths (path, version='6.0', platform='x86'):
94 """Get a list of devstudio directories (include, lib or path). Return
95 a list of strings; will be empty list if unable to access the
96 registry or appropriate registry keys not found."""
98 if not _can_read_reg:
99 return []
101 L = []
102 if path=='lib':
103 path= 'Library'
104 path = string.upper(path + ' Dirs')
105 K = ('Software\\Microsoft\\Devstudio\\%s\\' +
106 'Build System\\Components\\Platforms\\Win32 (%s)\\Directories') % \
107 (version,platform)
108 for base in (HKEY_CLASSES_ROOT,
109 HKEY_LOCAL_MACHINE,
110 HKEY_CURRENT_USER,
111 HKEY_USERS):
112 try:
113 k = RegOpenKeyEx(base,K)
114 i = 0
115 while 1:
116 try:
117 (p,v,t) = RegEnumValue(k,i)
118 if string.upper(p) == path:
119 V = string.split(v,';')
120 for v in V:
121 if hasattr(v, "encode"):
122 try:
123 v = v.encode("mbcs")
124 except UnicodeError:
125 pass
126 if v == '' or v in L: continue
127 L.append(v)
128 break
129 i = i + 1
130 except RegError:
131 break
132 except RegError:
133 pass
134 return L
136 # get_msvc_paths()
139 def find_exe (exe, version_number):
140 """Try to find an MSVC executable program 'exe' (from version
141 'version_number' of MSVC) in several places: first, one of the MSVC
142 program search paths from the registry; next, the directories in the
143 PATH environment variable. If any of those work, return an absolute
144 path that is known to exist. If none of them work, just return the
145 original program name, 'exe'."""
147 for p in get_msvc_paths ('path', version_number):
148 fn = os.path.join (os.path.abspath(p), exe)
149 if os.path.isfile(fn):
150 return fn
152 # didn't find it; try existing path
153 for p in string.split (os.environ['Path'],';'):
154 fn = os.path.join(os.path.abspath(p),exe)
155 if os.path.isfile(fn):
156 return fn
158 return exe # last desperate hope
161 def set_path_env_var (name, version_number):
162 """Set environment variable 'name' to an MSVC path type value obtained
163 from 'get_msvc_paths()'. This is equivalent to a SET command prior
164 to execution of spawned commands."""
166 p = get_msvc_paths (name, version_number)
167 if p:
168 os.environ[name] = string.join (p,';')
171 class MSVCCompiler (CCompiler) :
172 """Concrete class that implements an interface to Microsoft Visual C++,
173 as defined by the CCompiler abstract class."""
175 compiler_type = 'msvc'
177 # Just set this so CCompiler's constructor doesn't barf. We currently
178 # don't use the 'set_executables()' bureaucracy provided by CCompiler,
179 # as it really isn't necessary for this sort of single-compiler class.
180 # Would be nice to have a consistent interface with UnixCCompiler,
181 # though, so it's worth thinking about.
182 executables = {}
184 # Private class data (need to distinguish C from C++ source for compiler)
185 _c_extensions = ['.c']
186 _cpp_extensions = ['.cc', '.cpp', '.cxx']
187 _rc_extensions = ['.rc']
188 _mc_extensions = ['.mc']
190 # Needed for the filename generation methods provided by the
191 # base class, CCompiler.
192 src_extensions = (_c_extensions + _cpp_extensions +
193 _rc_extensions + _mc_extensions)
194 res_extension = '.res'
195 obj_extension = '.obj'
196 static_lib_extension = '.lib'
197 shared_lib_extension = '.dll'
198 static_lib_format = shared_lib_format = '%s%s'
199 exe_extension = '.exe'
202 def __init__ (self,
203 verbose=0,
204 dry_run=0,
205 force=0):
207 CCompiler.__init__ (self, verbose, dry_run, force)
208 versions = get_devstudio_versions ()
210 if versions:
211 version = versions[0] # highest version
213 self.cc = find_exe("cl.exe", version)
214 self.linker = find_exe("link.exe", version)
215 self.lib = find_exe("lib.exe", version)
216 self.rc = find_exe("rc.exe", version) # resource compiler
217 self.mc = find_exe("mc.exe", version) # message compiler
218 set_path_env_var ('lib', version)
219 set_path_env_var ('include', version)
220 path=get_msvc_paths('path', version)
221 try:
222 for p in string.split(os.environ['path'],';'):
223 path.append(p)
224 except KeyError:
225 pass
226 os.environ['path'] = string.join(path,';')
227 else:
228 # devstudio not found in the registry
229 self.cc = "cl.exe"
230 self.linker = "link.exe"
231 self.lib = "lib.exe"
232 self.rc = "rc.exe"
233 self.mc = "mc.exe"
235 self.preprocess_options = None
236 self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GX' ,
237 '/DNDEBUG']
238 self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GX',
239 '/Z7', '/D_DEBUG']
241 self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO']
242 self.ldflags_shared_debug = [
243 '/DLL', '/nologo', '/INCREMENTAL:no', '/pdb:None', '/DEBUG'
245 self.ldflags_static = [ '/nologo']
248 # -- Worker methods ------------------------------------------------
250 def object_filenames (self,
251 source_filenames,
252 strip_dir=0,
253 output_dir=''):
254 # Copied from ccompiler.py, extended to return .res as 'object'-file
255 # for .rc input file
256 if output_dir is None: output_dir = ''
257 obj_names = []
258 for src_name in source_filenames:
259 (base, ext) = os.path.splitext (src_name)
260 if ext not in self.src_extensions:
261 # Better to raise an exception instead of silently continuing
262 # and later complain about sources and targets having
263 # different lengths
264 raise CompileError ("Don't know how to compile %s" % src_name)
265 if strip_dir:
266 base = os.path.basename (base)
267 if ext in self._rc_extensions:
268 obj_names.append (os.path.join (output_dir,
269 base + self.res_extension))
270 elif ext in self._mc_extensions:
271 obj_names.append (os.path.join (output_dir,
272 base + self.res_extension))
273 else:
274 obj_names.append (os.path.join (output_dir,
275 base + self.obj_extension))
276 return obj_names
278 # object_filenames ()
281 def compile(self, sources,
282 output_dir=None, macros=None, include_dirs=None, debug=0,
283 extra_preargs=None, extra_postargs=None, depends=None):
285 macros, objects, extra_postargs, pp_opts, build = \
286 self._setup_compile(output_dir, macros, include_dirs, sources,
287 depends, extra_postargs)
289 compile_opts = extra_preargs or []
290 compile_opts.append ('/c')
291 if debug:
292 compile_opts.extend(self.compile_options_debug)
293 else:
294 compile_opts.extend(self.compile_options)
296 for obj, (src, ext) in build.items():
297 if debug:
298 # pass the full pathname to MSVC in debug mode,
299 # this allows the debugger to find the source file
300 # without asking the user to browse for it
301 src = os.path.abspath(src)
303 if ext in self._c_extensions:
304 input_opt = "/Tc" + src
305 elif ext in self._cpp_extensions:
306 input_opt = "/Tp" + src
307 elif ext in self._rc_extensions:
308 # compile .RC to .RES file
309 input_opt = src
310 output_opt = "/fo" + obj
311 try:
312 self.spawn ([self.rc] +
313 [output_opt] + [input_opt])
314 except DistutilsExecError, msg:
315 raise CompileError, msg
316 continue
317 elif ext in self._mc_extensions:
319 # Compile .MC to .RC file to .RES file.
320 # * '-h dir' specifies the directory for the
321 # generated include file
322 # * '-r dir' specifies the target directory of the
323 # generated RC file and the binary message resource
324 # it includes
326 # For now (since there are no options to change this),
327 # we use the source-directory for the include file and
328 # the build directory for the RC file and message
329 # resources. This works at least for win32all.
331 h_dir = os.path.dirname (src)
332 rc_dir = os.path.dirname (obj)
333 try:
334 # first compile .MC to .RC and .H file
335 self.spawn ([self.mc] +
336 ['-h', h_dir, '-r', rc_dir] + [src])
337 base, _ = os.path.splitext (os.path.basename (src))
338 rc_file = os.path.join (rc_dir, base + '.rc')
339 # then compile .RC to .RES file
340 self.spawn ([self.rc] +
341 ["/fo" + obj] + [rc_file])
343 except DistutilsExecError, msg:
344 raise CompileError, msg
345 continue
346 else:
347 # how to handle this file?
348 raise CompileError (
349 "Don't know how to compile %s to %s" % \
350 (src, obj))
352 output_opt = "/Fo" + obj
353 try:
354 self.spawn ([self.cc] + compile_opts + pp_opts +
355 [input_opt, output_opt] +
356 extra_postargs)
357 except DistutilsExecError, msg:
358 raise CompileError, msg
360 return objects
362 # compile ()
365 def create_static_lib (self,
366 objects,
367 output_libname,
368 output_dir=None,
369 debug=0,
370 extra_preargs=None,
371 extra_postargs=None):
373 (objects, output_dir) = self._fix_object_args (objects, output_dir)
374 output_filename = \
375 self.library_filename (output_libname, output_dir=output_dir)
377 if self._need_link (objects, output_filename):
378 lib_args = objects + ['/OUT:' + output_filename]
379 if debug:
380 pass # XXX what goes here?
381 if extra_preargs:
382 lib_args[:0] = extra_preargs
383 if extra_postargs:
384 lib_args.extend (extra_postargs)
385 try:
386 self.spawn ([self.lib] + lib_args)
387 except DistutilsExecError, msg:
388 raise LibError, msg
390 else:
391 log.debug("skipping %s (up-to-date)", output_filename)
393 # create_static_lib ()
395 def link (self,
396 target_desc,
397 objects,
398 output_filename,
399 output_dir=None,
400 libraries=None,
401 library_dirs=None,
402 runtime_library_dirs=None,
403 export_symbols=None,
404 debug=0,
405 extra_preargs=None,
406 extra_postargs=None,
407 build_temp=None):
409 (objects, output_dir) = self._fix_object_args (objects, output_dir)
410 (libraries, library_dirs, runtime_library_dirs) = \
411 self._fix_lib_args (libraries, library_dirs, runtime_library_dirs)
413 if runtime_library_dirs:
414 self.warn ("I don't know what to do with 'runtime_library_dirs': "
415 + str (runtime_library_dirs))
417 lib_opts = gen_lib_options (self,
418 library_dirs, runtime_library_dirs,
419 libraries)
420 if output_dir is not None:
421 output_filename = os.path.join (output_dir, output_filename)
423 if self._need_link (objects, output_filename):
425 if target_desc == CCompiler.EXECUTABLE:
426 if debug:
427 ldflags = self.ldflags_shared_debug[1:]
428 else:
429 ldflags = self.ldflags_shared[1:]
430 else:
431 if debug:
432 ldflags = self.ldflags_shared_debug
433 else:
434 ldflags = self.ldflags_shared
436 export_opts = []
437 for sym in (export_symbols or []):
438 export_opts.append("/EXPORT:" + sym)
440 ld_args = (ldflags + lib_opts + export_opts +
441 objects + ['/OUT:' + output_filename])
443 # The MSVC linker generates .lib and .exp files, which cannot be
444 # suppressed by any linker switches. The .lib files may even be
445 # needed! Make sure they are generated in the temporary build
446 # directory. Since they have different names for debug and release
447 # builds, they can go into the same directory.
448 if export_symbols is not None:
449 (dll_name, dll_ext) = os.path.splitext(
450 os.path.basename(output_filename))
451 implib_file = os.path.join(
452 os.path.dirname(objects[0]),
453 self.library_filename(dll_name))
454 ld_args.append ('/IMPLIB:' + implib_file)
456 if extra_preargs:
457 ld_args[:0] = extra_preargs
458 if extra_postargs:
459 ld_args.extend(extra_postargs)
461 self.mkpath (os.path.dirname (output_filename))
462 try:
463 self.spawn ([self.linker] + ld_args)
464 except DistutilsExecError, msg:
465 raise LinkError, msg
467 else:
468 log.debug("skipping %s (up-to-date)", output_filename)
470 # link ()
473 # -- Miscellaneous methods -----------------------------------------
474 # These are all used by the 'gen_lib_options() function, in
475 # ccompiler.py.
477 def library_dir_option (self, dir):
478 return "/LIBPATH:" + dir
480 def runtime_library_dir_option (self, dir):
481 raise DistutilsPlatformError, \
482 "don't know how to set runtime library search path for MSVC++"
484 def library_option (self, lib):
485 return self.library_filename (lib)
488 def find_library_file (self, dirs, lib, debug=0):
489 # Prefer a debugging library if found (and requested), but deal
490 # with it if we don't have one.
491 if debug:
492 try_names = [lib + "_d", lib]
493 else:
494 try_names = [lib]
495 for dir in dirs:
496 for name in try_names:
497 libfile = os.path.join(dir, self.library_filename (name))
498 if os.path.exists(libfile):
499 return libfile
500 else:
501 # Oops, didn't find it in *any* of 'dirs'
502 return None
504 # find_library_file ()
506 # class MSVCCompiler