blob: 90ebae0a5887bf9491d1108d4ff0d583ff89c241 [file] [log] [blame]
Greg Warddbd12761999-08-29 18:15:07 +00001"""distutils.ccompiler
2
3Contains MSVCCompiler, an implementation of the abstract CCompiler class
Greg Warddf178f91999-09-29 12:29:10 +00004for the Microsoft Visual Studio."""
Greg Warddbd12761999-08-29 18:15:07 +00005
6
7# created 1999/08/19, Perry Stoll
8#
9__rcsid__ = "$Id$"
10
11import os
12import sys
Greg Ward1b9c6f72000-02-08 02:39:44 +000013import string
Greg Warddbd12761999-08-29 18:15:07 +000014from distutils.errors import *
Greg Ward3d50b901999-09-08 02:36:01 +000015from distutils.ccompiler import \
16 CCompiler, gen_preprocess_options, gen_lib_options
Greg Warddbd12761999-08-29 18:15:07 +000017
Greg Ward62e33932000-02-10 02:52:42 +000018
19def get_devstudio_versions ():
20
21 """Get list of devstudio versions from the Windows registry. Return a
22 list of strings (???) containing version numbers; the list will be
23 empty if we were unable to access the registry (eg. couldn't import
24 a registry-access module) or the appropriate registry keys weren't
25 found. (XXX is this correct???)"""
Greg Ward1b9c6f72000-02-08 02:39:44 +000026 try:
27 import win32api
28 import win32con
29 except ImportError:
Greg Ward62e33932000-02-10 02:52:42 +000030 return []
Greg Ward1b9c6f72000-02-08 02:39:44 +000031
32 K = 'Software\\Microsoft\\Devstudio'
33 L = []
Greg Ward62e33932000-02-10 02:52:42 +000034 for base in (win32con.HKEY_CLASSES_ROOT,
35 win32con.HKEY_LOCAL_MACHINE,
36 win32con.HKEY_CURRENT_USER,
37 win32con.HKEY_USERS):
Greg Ward1b9c6f72000-02-08 02:39:44 +000038 try:
39 k = win32api.RegOpenKeyEx(base,K)
40 i = 0
41 while 1:
42 try:
43 p = win32api.RegEnumKey(k,i)
44 if p[0] in '123456789' and p not in L:
45 L.append(p)
46 except win32api.error:
47 break
48 i = i + 1
49 except win32api.error:
50 pass
51 L.sort()
52 L.reverse()
53 return L
54
Greg Ward62e33932000-02-10 02:52:42 +000055# get_devstudio_versions ()
56
57
58def get_msvc_paths (path, version='6.0', platform='x86'):
59 """Get a devstudio path (include, lib or path)."""
Greg Ward1b9c6f72000-02-08 02:39:44 +000060 try:
61 import win32api
62 import win32con
63 except ImportError:
64 return None
65
66 L = []
Greg Ward62e33932000-02-10 02:52:42 +000067 if path=='lib':
68 path= 'Library'
Greg Ward1b9c6f72000-02-08 02:39:44 +000069 path = string.upper(path + ' Dirs')
Greg Ward62e33932000-02-10 02:52:42 +000070 K = ('Software\\Microsoft\\Devstudio\\%s\\' +
71 'Build System\\Components\\Platforms\\Win32 (%s)\\Directories') % \
72 (version,platform)
73 for base in (win32con.HKEY_CLASSES_ROOT,
74 win32con.HKEY_LOCAL_MACHINE,
75 win32con.HKEY_CURRENT_USER,
76 win32con.HKEY_USERS):
Greg Ward1b9c6f72000-02-08 02:39:44 +000077 try:
78 k = win32api.RegOpenKeyEx(base,K)
79 i = 0
80 while 1:
81 try:
82 (p,v,t) = win32api.RegEnumValue(k,i)
Greg Ward62e33932000-02-10 02:52:42 +000083 if string.upper(p) == path:
Greg Ward1b9c6f72000-02-08 02:39:44 +000084 V = string.split(v,';')
85 for v in V:
Greg Ward62e33932000-02-10 02:52:42 +000086 if v == '' or v in L: continue
Greg Ward1b9c6f72000-02-08 02:39:44 +000087 L.append(v)
88 break
89 i = i + 1
90 except win32api.error:
91 break
92 except win32api.error:
93 pass
94 return L
95
Greg Ward62e33932000-02-10 02:52:42 +000096# get_msvc_paths()
97
98
Greg Ward1b9c6f72000-02-08 02:39:44 +000099def _find_exe(exe):
Greg Ward62e33932000-02-10 02:52:42 +0000100 for v in get_devstudio_versions():
101 for p in get_msvc_paths('path',v):
102 fn = os.path.join(os.path.abspath(p),exe)
103 if os.path.isfile(fn):
104 return fn
Greg Ward1b9c6f72000-02-08 02:39:44 +0000105
106 #didn't find it; try existing path
107 try:
108 for p in string.split(os.environ['Path'],';'):
109 fn=os.path.join(os.path.abspath(p),exe)
Greg Ward62e33932000-02-10 02:52:42 +0000110 if os.path.isfile(fn):
111 return fn
112 # XXX BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD !!!!!!!!!!!!!!!!
113 except: # XXX WHAT'S BEING CAUGHT HERE?!?!?
Greg Ward1b9c6f72000-02-08 02:39:44 +0000114 pass
115 return exe #last desperate hope
116
Greg Ward62e33932000-02-10 02:52:42 +0000117
Greg Ward1b9c6f72000-02-08 02:39:44 +0000118def _find_SET(n):
Greg Ward62e33932000-02-10 02:52:42 +0000119 for v in get_devstudio_versions():
120 p = get_msvc_paths(n,v)
121 if p:
122 return p
Greg Ward1b9c6f72000-02-08 02:39:44 +0000123 return []
124
Greg Ward62e33932000-02-10 02:52:42 +0000125
Greg Ward1b9c6f72000-02-08 02:39:44 +0000126def _do_SET(n):
Greg Ward62e33932000-02-10 02:52:42 +0000127 p = _find_SET(n)
128 if p:
129 os.environ[n] = string.join(p,';')
130
Greg Warddbd12761999-08-29 18:15:07 +0000131
Greg Ward3d50b901999-09-08 02:36:01 +0000132class MSVCCompiler (CCompiler) :
133 """Concrete class that implements an interface to Microsoft Visual C++,
134 as defined by the CCompiler abstract class."""
Greg Warddbd12761999-08-29 18:15:07 +0000135
Greg Warddf178f91999-09-29 12:29:10 +0000136 compiler_type = 'msvc'
137
Greg Warddbd12761999-08-29 18:15:07 +0000138 def __init__ (self,
139 verbose=0,
Greg Wardc74138d1999-10-03 20:47:52 +0000140 dry_run=0,
141 force=0):
Greg Warddbd12761999-08-29 18:15:07 +0000142
Greg Wardc74138d1999-10-03 20:47:52 +0000143 CCompiler.__init__ (self, verbose, dry_run, force)
Greg Warddbd12761999-08-29 18:15:07 +0000144
Greg Warddbd12761999-08-29 18:15:07 +0000145 self.add_library_dir( os.path.join( sys.exec_prefix, 'libs' ) )
146
Greg Ward1b9c6f72000-02-08 02:39:44 +0000147 self.cc = _find_exe("cl.exe")
148 self.link = _find_exe("link.exe")
149 _do_SET('lib')
150 _do_SET('include')
151 path=_find_SET('path')
152 try:
153 for p in string.split(os.environ['path'],';'):
154 path.append(p)
155 except KeyError:
156 pass
157 os.environ['path'] = string.join(path,';')
Greg Warddbd12761999-08-29 18:15:07 +0000158 self.preprocess_options = None
Greg Ward01f52152000-01-17 21:57:17 +0000159 self.compile_options = [ '/nologo', '/Ox', '/MD' ]
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000160 self.compile_options_debug = [
161 '/nologo', '/Od', '/MDd', '/Z7', '/D_DEBUG'
162 ]
Greg Warddbd12761999-08-29 18:15:07 +0000163
Greg Ward1b9c6f72000-02-08 02:39:44 +0000164 self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO']
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000165 self.ldflags_shared_debug = [
166 '/DLL', '/nologo', '/INCREMENTAL:no', '/pdb:None', '/DEBUG'
167 ]
Greg Warddbd12761999-08-29 18:15:07 +0000168 self.ldflags_static = [ '/nologo']
169
Greg Warddbd12761999-08-29 18:15:07 +0000170
171 # -- Worker methods ------------------------------------------------
172 # (must be implemented by subclasses)
173
174 _c_extensions = [ '.c' ]
Greg Ward3d50b901999-09-08 02:36:01 +0000175 _cpp_extensions = [ '.cc', '.cpp' ]
Greg Warddbd12761999-08-29 18:15:07 +0000176
177 _obj_ext = '.obj'
Greg Ward3d50b901999-09-08 02:36:01 +0000178 _exe_ext = '.exe'
Greg Warddbd12761999-08-29 18:15:07 +0000179 _shared_lib_ext = '.dll'
180 _static_lib_ext = '.lib'
Greg Warddf178f91999-09-29 12:29:10 +0000181
182 # XXX the 'output_dir' parameter is ignored by the methods in this
183 # class! I just put it in to be consistent with CCompiler and
184 # UnixCCompiler, but someone who actually knows Visual C++ will
185 # have to make it work...
Greg Warddbd12761999-08-29 18:15:07 +0000186
187 def compile (self,
188 sources,
Greg Warddf178f91999-09-29 12:29:10 +0000189 output_dir=None,
Greg Warddbd12761999-08-29 18:15:07 +0000190 macros=None,
Greg Ward0bdd90a1999-12-12 17:19:58 +0000191 include_dirs=None,
Greg Ward386b8442000-02-09 02:18:39 +0000192 debug=0,
Greg Warddf178f91999-09-29 12:29:10 +0000193 extra_preargs=None,
194 extra_postargs=None):
Greg Warddbd12761999-08-29 18:15:07 +0000195
196 if macros is None:
197 macros = []
Greg Ward0bdd90a1999-12-12 17:19:58 +0000198 if include_dirs is None:
199 include_dirs = []
Greg Warddbd12761999-08-29 18:15:07 +0000200
201 objectFiles = []
202
Greg Ward0bdd90a1999-12-12 17:19:58 +0000203 base_pp_opts = \
204 gen_preprocess_options (self.macros + macros,
205 self.include_dirs + include_dirs)
Greg Warddbd12761999-08-29 18:15:07 +0000206
207 base_pp_opts.append('/c')
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000208
209 if debug:
210 compile_options = self.compile_options_debug
211 else:
212 compile_options = self.compile_options
Greg Warddbd12761999-08-29 18:15:07 +0000213
214 for srcFile in sources:
215 base,ext = os.path.splitext(srcFile)
216 objFile = base + ".obj"
217
218 if ext in self._c_extensions:
219 fileOpt = "/Tc"
220 elif ext in self._cpp_extensions:
221 fileOpt = "/Tp"
222
223 inputOpt = fileOpt + srcFile
224 outputOpt = "/Fo" + objFile
225
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000226 cc_args = compile_options + \
Greg Warddf178f91999-09-29 12:29:10 +0000227 base_pp_opts + \
228 [outputOpt, inputOpt]
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000229
Greg Warddf178f91999-09-29 12:29:10 +0000230 if extra_preargs:
231 cc_args[:0] = extra_preargs
232 if extra_postargs:
233 cc_args.extend (extra_postargs)
Greg Warddbd12761999-08-29 18:15:07 +0000234
Greg Warddf178f91999-09-29 12:29:10 +0000235 self.spawn ([self.cc] + cc_args)
Greg Warddbd12761999-08-29 18:15:07 +0000236 objectFiles.append( objFile )
Greg Warddbd12761999-08-29 18:15:07 +0000237 return objectFiles
Greg Ward3d50b901999-09-08 02:36:01 +0000238
239
Greg Ward386b8442000-02-09 02:18:39 +0000240 # XXX the signature of this method is different from CCompiler and
241 # UnixCCompiler -- but those extra parameters (libraries, library_dirs)
242 # are actually used. So: are they really *needed*, or can they be
243 # ditched? If needed, the CCompiler API will have to change...
Greg Warddbd12761999-08-29 18:15:07 +0000244 def link_static_lib (self,
245 objects,
246 output_libname,
Greg Warddf178f91999-09-29 12:29:10 +0000247 output_dir=None,
Greg Warddbd12761999-08-29 18:15:07 +0000248 libraries=None,
Greg Warddf178f91999-09-29 12:29:10 +0000249 library_dirs=None,
Greg Ward386b8442000-02-09 02:18:39 +0000250 debug=0,
Greg Warddf178f91999-09-29 12:29:10 +0000251 extra_preargs=None,
252 extra_postargs=None):
Greg Warddbd12761999-08-29 18:15:07 +0000253
Greg Warddbd12761999-08-29 18:15:07 +0000254 if libraries is None:
255 libraries = []
256 if library_dirs is None:
257 library_dirs = []
Greg Warddbd12761999-08-29 18:15:07 +0000258
Greg Ward3d50b901999-09-08 02:36:01 +0000259 lib_opts = gen_lib_options (self.libraries + libraries,
260 self.library_dirs + library_dirs,
261 "%s.lib", "/LIBPATH:%s")
Greg Warddbd12761999-08-29 18:15:07 +0000262
Greg Warddbd12761999-08-29 18:15:07 +0000263 ld_args = self.ldflags_static + lib_opts + \
264 objects + ['/OUT:' + output_filename]
Greg Ward386b8442000-02-09 02:18:39 +0000265 if debug:
266 pass # XXX what goes here?
Greg Warddf178f91999-09-29 12:29:10 +0000267 if extra_preargs:
268 ld_args[:0] = extra_preargs
269 if extra_postargs:
270 ld_args.extend (extra_postargs)
Greg Warddbd12761999-08-29 18:15:07 +0000271
272 self.spawn ( [ self.link ] + ld_args )
273
274
275 def link_shared_lib (self,
276 objects,
277 output_libname,
Greg Warddf178f91999-09-29 12:29:10 +0000278 output_dir=None,
Greg Warddbd12761999-08-29 18:15:07 +0000279 libraries=None,
280 library_dirs=None,
Greg Ward386b8442000-02-09 02:18:39 +0000281 debug=0,
Greg Warddf178f91999-09-29 12:29:10 +0000282 extra_preargs=None,
283 extra_postargs=None):
284
Greg Warddbd12761999-08-29 18:15:07 +0000285 # XXX should we sanity check the library name? (eg. no
286 # slashes)
Greg Warddf178f91999-09-29 12:29:10 +0000287 self.link_shared_object (objects,
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000288 self.shared_library_name(output_libname),
289 output_dir=output_dir,
290 libraries=libraries,
291 library_dirs=library_dirs,
292 debug=debug,
293 extra_preargs=extra_preargs,
294 extra_postargs=extra_postargs)
295
Greg Warddbd12761999-08-29 18:15:07 +0000296
297 def link_shared_object (self,
298 objects,
299 output_filename,
Greg Warddf178f91999-09-29 12:29:10 +0000300 output_dir=None,
Greg Warddbd12761999-08-29 18:15:07 +0000301 libraries=None,
302 library_dirs=None,
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000303 debug=0,
Greg Warddf178f91999-09-29 12:29:10 +0000304 extra_preargs=None,
305 extra_postargs=None):
Greg Warddbd12761999-08-29 18:15:07 +0000306 """Link a bunch of stuff together to create a shared object
307 file. Much like 'link_shared_lib()', except the output
308 filename is explicitly supplied as 'output_filename'."""
309 if libraries is None:
310 libraries = []
311 if library_dirs is None:
312 library_dirs = []
Greg Warddbd12761999-08-29 18:15:07 +0000313
Greg Wardc74138d1999-10-03 20:47:52 +0000314 lib_opts = gen_lib_options (self,
315 self.library_dirs + library_dirs,
316 self.libraries + libraries)
Greg Warddbd12761999-08-29 18:15:07 +0000317
Greg Ward386b8442000-02-09 02:18:39 +0000318 if debug:
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000319 ldflags = self.ldflags_shared_debug
320 basename, ext = os.path.splitext (output_filename)
321 #XXX not sure this belongs here
322 # extensions in debug_mode are named 'module_d.pyd'
323 output_filename = basename + '_d' + ext
324 else:
325 ldflags = self.ldflags_shared
326
327 ld_args = ldflags + lib_opts + \
328 objects + ['/OUT:' + output_filename]
329
Greg Warddf178f91999-09-29 12:29:10 +0000330 if extra_preargs:
331 ld_args[:0] = extra_preargs
332 if extra_postargs:
333 ld_args.extend (extra_postargs)
Greg Warddbd12761999-08-29 18:15:07 +0000334
335 self.spawn ( [ self.link ] + ld_args )
336
337
338 # -- Filename mangling methods -------------------------------------
339
340 def _change_extensions( self, filenames, newExtension ):
341 object_filenames = []
342
343 for srcFile in filenames:
344 base,ext = os.path.splitext( srcFile )
345 # XXX should we strip off any existing path?
346 object_filenames.append( base + newExtension )
347
348 return object_filenames
349
350 def object_filenames (self, source_filenames):
351 """Return the list of object filenames corresponding to each
352 specified source filename."""
353 return self._change_extensions( source_filenames, self._obj_ext )
354
355 def shared_object_filename (self, source_filename):
356 """Return the shared object filename corresponding to a
357 specified source filename."""
358 return self._change_extensions( source_filenames, self._shared_lib_ext )
359
360 def library_filename (self, libname):
361 """Return the static library filename corresponding to the
362 specified library name."""
Greg Wardc8a95c82000-01-17 18:00:04 +0000363 return "%s%s" %( libname, self._static_lib_ext )
Greg Warddbd12761999-08-29 18:15:07 +0000364
365 def shared_library_filename (self, libname):
366 """Return the shared library filename corresponding to the
367 specified library name."""
Greg Wardc8a95c82000-01-17 18:00:04 +0000368 return "%s%s" %( libname, self._shared_lib_ext )
Greg Warddbd12761999-08-29 18:15:07 +0000369
Greg Wardc74138d1999-10-03 20:47:52 +0000370
371 def library_dir_option (self, dir):
372 return "/LIBPATH:" + dir
373
374 def library_option (self, lib):
375 return self.library_filename (lib)
376
377
378 def find_library_file (self, dirs, lib):
379
380 for dir in dirs:
381 libfile = os.path.join (dir, self.library_filename (lib))
382 if os.path.exists (libfile):
383 return libfile
384
385 else:
386 # Oops, didn't find it in *any* of 'dirs'
387 return None
388
389 # find_library_file ()
390
Greg Warddbd12761999-08-29 18:15:07 +0000391# class MSVCCompiler