blob: 3073aaea321fc3fe0e90cd3f0c7ae56ad9261502 [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 ():
Greg Ward62e33932000-02-10 02:52:42 +000020 """Get list of devstudio versions from the Windows registry. Return a
Greg Ward69988092000-02-11 02:47:15 +000021 list of strings containing version numbers; the list will be
Greg Ward62e33932000-02-10 02:52:42 +000022 empty if we were unable to access the registry (eg. couldn't import
23 a registry-access module) or the appropriate registry keys weren't
Greg Ward69988092000-02-11 02:47:15 +000024 found."""
25
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'):
Greg Ward69988092000-02-11 02:47:15 +000059 """Get a list of devstudio directories (include, lib or path). Return
60 a list of strings; will be empty list if unable to access the
61 registry or appropriate registry keys not found."""
62
Greg Ward1b9c6f72000-02-08 02:39:44 +000063 try:
64 import win32api
65 import win32con
66 except ImportError:
Greg Ward69988092000-02-11 02:47:15 +000067 return []
Greg Ward1b9c6f72000-02-08 02:39:44 +000068
69 L = []
Greg Ward62e33932000-02-10 02:52:42 +000070 if path=='lib':
71 path= 'Library'
Greg Ward1b9c6f72000-02-08 02:39:44 +000072 path = string.upper(path + ' Dirs')
Greg Ward62e33932000-02-10 02:52:42 +000073 K = ('Software\\Microsoft\\Devstudio\\%s\\' +
74 'Build System\\Components\\Platforms\\Win32 (%s)\\Directories') % \
75 (version,platform)
76 for base in (win32con.HKEY_CLASSES_ROOT,
77 win32con.HKEY_LOCAL_MACHINE,
78 win32con.HKEY_CURRENT_USER,
79 win32con.HKEY_USERS):
Greg Ward1b9c6f72000-02-08 02:39:44 +000080 try:
81 k = win32api.RegOpenKeyEx(base,K)
82 i = 0
83 while 1:
84 try:
85 (p,v,t) = win32api.RegEnumValue(k,i)
Greg Ward62e33932000-02-10 02:52:42 +000086 if string.upper(p) == path:
Greg Ward1b9c6f72000-02-08 02:39:44 +000087 V = string.split(v,';')
88 for v in V:
Greg Ward62e33932000-02-10 02:52:42 +000089 if v == '' or v in L: continue
Greg Ward1b9c6f72000-02-08 02:39:44 +000090 L.append(v)
91 break
92 i = i + 1
93 except win32api.error:
94 break
95 except win32api.error:
96 pass
97 return L
98
Greg Ward62e33932000-02-10 02:52:42 +000099# get_msvc_paths()
100
101
Greg Ward69988092000-02-11 02:47:15 +0000102def find_exe (exe, version_number):
103 """Try to find an MSVC executable program 'exe' (from version
104 'version_number' of MSVC) in several places: first, one of the MSVC
105 program search paths from the registry; next, the directories in the
106 PATH environment variable. If any of those work, return an absolute
107 path that is known to exist. If none of them work, just return the
108 original program name, 'exe'."""
Greg Ward1b9c6f72000-02-08 02:39:44 +0000109
Greg Ward69988092000-02-11 02:47:15 +0000110 for p in get_msvc_paths ('path', version_number):
111 fn = os.path.join (os.path.abspath(p), exe)
112 if os.path.isfile(fn):
113 return fn
114
115 # didn't find it; try existing path
116 for p in string.split (os.environ['Path'],';'):
117 fn = os.path.join(os.path.abspath(p),exe)
118 if os.path.isfile(fn):
119 return fn
120
121 return exe # last desperate hope
Greg Ward1b9c6f72000-02-08 02:39:44 +0000122
Greg Ward62e33932000-02-10 02:52:42 +0000123
Greg Ward69988092000-02-11 02:47:15 +0000124def _find_SET(name,version_number):
125 """looks up in the registry and returns a list of values suitable for
126 use in a SET command eg SET name=value. Normally the value will be a
127 ';' separated list similar to a path list.
128
129 name is the name of an MSVC path and version_number is a version_number
130 of an MSVC installation."""
131 return get_msvc_paths(name, version_number)
Greg Ward1b9c6f72000-02-08 02:39:44 +0000132
Greg Ward62e33932000-02-10 02:52:42 +0000133
Greg Ward69988092000-02-11 02:47:15 +0000134def _do_SET(name, version_number):
135 """sets os.environ[name] to an MSVC path type value obtained from
136 _find_SET. This is equivalent to a SET command prior to execution of
137 spawned commands."""
138 p=_find_SET(name, version_number)
Greg Ward62e33932000-02-10 02:52:42 +0000139 if p:
Greg Ward69988092000-02-11 02:47:15 +0000140 os.environ[name]=string.join(p,';')
Greg Ward62e33932000-02-10 02:52:42 +0000141
Greg Warddbd12761999-08-29 18:15:07 +0000142
Greg Ward3d50b901999-09-08 02:36:01 +0000143class MSVCCompiler (CCompiler) :
144 """Concrete class that implements an interface to Microsoft Visual C++,
145 as defined by the CCompiler abstract class."""
Greg Warddbd12761999-08-29 18:15:07 +0000146
Greg Warddf178f91999-09-29 12:29:10 +0000147 compiler_type = 'msvc'
148
Greg Warddbd12761999-08-29 18:15:07 +0000149 def __init__ (self,
150 verbose=0,
Greg Wardc74138d1999-10-03 20:47:52 +0000151 dry_run=0,
152 force=0):
Greg Warddbd12761999-08-29 18:15:07 +0000153
Greg Wardc74138d1999-10-03 20:47:52 +0000154 CCompiler.__init__ (self, verbose, dry_run, force)
Greg Warddbd12761999-08-29 18:15:07 +0000155
Greg Warddbd12761999-08-29 18:15:07 +0000156 self.add_library_dir( os.path.join( sys.exec_prefix, 'libs' ) )
157
Greg Ward69988092000-02-11 02:47:15 +0000158 vNum = get_devstudio_versions ()
159
160 if vNum:
161 vNum = vNum[0] # highest version
162
163 self.cc = _find_exe("cl.exe", vNum)
164 self.link = _find_exe("link.exe", vNum)
165 _do_SET('lib', vNum)
166 _do_SET('include', vNum)
167 path=_find_SET('path', vNum)
168 try:
169 for p in string.split(os.environ['path'],';'):
170 path.append(p)
171 except KeyError:
172 pass
173 os.environ['path'] = string.join(path,';')
174 else:
175 # devstudio not found in the registry
176 self.cc = "cl.exe"
177 self.link = "link.exe"
178
Greg Warddbd12761999-08-29 18:15:07 +0000179 self.preprocess_options = None
Greg Ward69988092000-02-11 02:47:15 +0000180 self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3' ]
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000181 self.compile_options_debug = [
Greg Ward69988092000-02-11 02:47:15 +0000182 '/nologo', '/Od', '/MDd', '/W3', '/Z7', '/D_DEBUG'
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000183 ]
Greg Warddbd12761999-08-29 18:15:07 +0000184
Greg Ward1b9c6f72000-02-08 02:39:44 +0000185 self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO']
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000186 self.ldflags_shared_debug = [
187 '/DLL', '/nologo', '/INCREMENTAL:no', '/pdb:None', '/DEBUG'
188 ]
Greg Warddbd12761999-08-29 18:15:07 +0000189 self.ldflags_static = [ '/nologo']
190
Greg Warddbd12761999-08-29 18:15:07 +0000191
192 # -- Worker methods ------------------------------------------------
193 # (must be implemented by subclasses)
194
195 _c_extensions = [ '.c' ]
Greg Ward3d50b901999-09-08 02:36:01 +0000196 _cpp_extensions = [ '.cc', '.cpp' ]
Greg Warddbd12761999-08-29 18:15:07 +0000197
198 _obj_ext = '.obj'
Greg Ward3d50b901999-09-08 02:36:01 +0000199 _exe_ext = '.exe'
Greg Warddbd12761999-08-29 18:15:07 +0000200 _shared_lib_ext = '.dll'
201 _static_lib_ext = '.lib'
Greg Warddf178f91999-09-29 12:29:10 +0000202
203 # XXX the 'output_dir' parameter is ignored by the methods in this
204 # class! I just put it in to be consistent with CCompiler and
205 # UnixCCompiler, but someone who actually knows Visual C++ will
206 # have to make it work...
Greg Warddbd12761999-08-29 18:15:07 +0000207
208 def compile (self,
209 sources,
Greg Warddf178f91999-09-29 12:29:10 +0000210 output_dir=None,
Greg Warddbd12761999-08-29 18:15:07 +0000211 macros=None,
Greg Ward0bdd90a1999-12-12 17:19:58 +0000212 include_dirs=None,
Greg Ward386b8442000-02-09 02:18:39 +0000213 debug=0,
Greg Warddf178f91999-09-29 12:29:10 +0000214 extra_preargs=None,
215 extra_postargs=None):
Greg Warddbd12761999-08-29 18:15:07 +0000216
217 if macros is None:
218 macros = []
Greg Ward0bdd90a1999-12-12 17:19:58 +0000219 if include_dirs is None:
220 include_dirs = []
Greg Warddbd12761999-08-29 18:15:07 +0000221
222 objectFiles = []
223
Greg Ward0bdd90a1999-12-12 17:19:58 +0000224 base_pp_opts = \
225 gen_preprocess_options (self.macros + macros,
226 self.include_dirs + include_dirs)
Greg Warddbd12761999-08-29 18:15:07 +0000227
228 base_pp_opts.append('/c')
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000229
230 if debug:
231 compile_options = self.compile_options_debug
232 else:
233 compile_options = self.compile_options
Greg Warddbd12761999-08-29 18:15:07 +0000234
235 for srcFile in sources:
236 base,ext = os.path.splitext(srcFile)
237 objFile = base + ".obj"
238
239 if ext in self._c_extensions:
240 fileOpt = "/Tc"
241 elif ext in self._cpp_extensions:
242 fileOpt = "/Tp"
243
244 inputOpt = fileOpt + srcFile
245 outputOpt = "/Fo" + objFile
246
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000247 cc_args = compile_options + \
Greg Warddf178f91999-09-29 12:29:10 +0000248 base_pp_opts + \
249 [outputOpt, inputOpt]
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000250
Greg Warddf178f91999-09-29 12:29:10 +0000251 if extra_preargs:
252 cc_args[:0] = extra_preargs
253 if extra_postargs:
254 cc_args.extend (extra_postargs)
Greg Warddbd12761999-08-29 18:15:07 +0000255
Greg Warddf178f91999-09-29 12:29:10 +0000256 self.spawn ([self.cc] + cc_args)
Greg Warddbd12761999-08-29 18:15:07 +0000257 objectFiles.append( objFile )
Greg Warddbd12761999-08-29 18:15:07 +0000258 return objectFiles
Greg Ward3d50b901999-09-08 02:36:01 +0000259
260
Greg Ward386b8442000-02-09 02:18:39 +0000261 # XXX the signature of this method is different from CCompiler and
262 # UnixCCompiler -- but those extra parameters (libraries, library_dirs)
263 # are actually used. So: are they really *needed*, or can they be
264 # ditched? If needed, the CCompiler API will have to change...
Greg Warddbd12761999-08-29 18:15:07 +0000265 def link_static_lib (self,
266 objects,
267 output_libname,
Greg Warddf178f91999-09-29 12:29:10 +0000268 output_dir=None,
Greg Warddbd12761999-08-29 18:15:07 +0000269 libraries=None,
Greg Warddf178f91999-09-29 12:29:10 +0000270 library_dirs=None,
Greg Ward386b8442000-02-09 02:18:39 +0000271 debug=0,
Greg Warddf178f91999-09-29 12:29:10 +0000272 extra_preargs=None,
273 extra_postargs=None):
Greg Warddbd12761999-08-29 18:15:07 +0000274
Greg Warddbd12761999-08-29 18:15:07 +0000275 if libraries is None:
276 libraries = []
277 if library_dirs is None:
278 library_dirs = []
Greg Warddbd12761999-08-29 18:15:07 +0000279
Greg Ward3d50b901999-09-08 02:36:01 +0000280 lib_opts = gen_lib_options (self.libraries + libraries,
281 self.library_dirs + library_dirs,
282 "%s.lib", "/LIBPATH:%s")
Greg Warddbd12761999-08-29 18:15:07 +0000283
Greg Warddbd12761999-08-29 18:15:07 +0000284 ld_args = self.ldflags_static + lib_opts + \
285 objects + ['/OUT:' + output_filename]
Greg Ward386b8442000-02-09 02:18:39 +0000286 if debug:
287 pass # XXX what goes here?
Greg Warddf178f91999-09-29 12:29:10 +0000288 if extra_preargs:
289 ld_args[:0] = extra_preargs
290 if extra_postargs:
291 ld_args.extend (extra_postargs)
Greg Warddbd12761999-08-29 18:15:07 +0000292
293 self.spawn ( [ self.link ] + ld_args )
294
295
296 def link_shared_lib (self,
297 objects,
298 output_libname,
Greg Warddf178f91999-09-29 12:29:10 +0000299 output_dir=None,
Greg Warddbd12761999-08-29 18:15:07 +0000300 libraries=None,
301 library_dirs=None,
Greg Ward386b8442000-02-09 02:18:39 +0000302 debug=0,
Greg Warddf178f91999-09-29 12:29:10 +0000303 extra_preargs=None,
304 extra_postargs=None):
305
Greg Warddbd12761999-08-29 18:15:07 +0000306 # XXX should we sanity check the library name? (eg. no
307 # slashes)
Greg Warddf178f91999-09-29 12:29:10 +0000308 self.link_shared_object (objects,
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000309 self.shared_library_name(output_libname),
310 output_dir=output_dir,
311 libraries=libraries,
312 library_dirs=library_dirs,
313 debug=debug,
314 extra_preargs=extra_preargs,
315 extra_postargs=extra_postargs)
316
Greg Warddbd12761999-08-29 18:15:07 +0000317
318 def link_shared_object (self,
319 objects,
320 output_filename,
Greg Warddf178f91999-09-29 12:29:10 +0000321 output_dir=None,
Greg Warddbd12761999-08-29 18:15:07 +0000322 libraries=None,
323 library_dirs=None,
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000324 debug=0,
Greg Warddf178f91999-09-29 12:29:10 +0000325 extra_preargs=None,
326 extra_postargs=None):
Greg Warddbd12761999-08-29 18:15:07 +0000327 """Link a bunch of stuff together to create a shared object
328 file. Much like 'link_shared_lib()', except the output
329 filename is explicitly supplied as 'output_filename'."""
330 if libraries is None:
331 libraries = []
332 if library_dirs is None:
333 library_dirs = []
Greg Warddbd12761999-08-29 18:15:07 +0000334
Greg Wardc74138d1999-10-03 20:47:52 +0000335 lib_opts = gen_lib_options (self,
336 self.library_dirs + library_dirs,
337 self.libraries + libraries)
Greg Warddbd12761999-08-29 18:15:07 +0000338
Greg Ward386b8442000-02-09 02:18:39 +0000339 if debug:
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000340 ldflags = self.ldflags_shared_debug
341 basename, ext = os.path.splitext (output_filename)
342 #XXX not sure this belongs here
343 # extensions in debug_mode are named 'module_d.pyd'
344 output_filename = basename + '_d' + ext
345 else:
346 ldflags = self.ldflags_shared
347
348 ld_args = ldflags + lib_opts + \
349 objects + ['/OUT:' + output_filename]
350
Greg Warddf178f91999-09-29 12:29:10 +0000351 if extra_preargs:
352 ld_args[:0] = extra_preargs
353 if extra_postargs:
354 ld_args.extend (extra_postargs)
Greg Warddbd12761999-08-29 18:15:07 +0000355
356 self.spawn ( [ self.link ] + ld_args )
357
358
359 # -- Filename mangling methods -------------------------------------
360
361 def _change_extensions( self, filenames, newExtension ):
362 object_filenames = []
363
364 for srcFile in filenames:
365 base,ext = os.path.splitext( srcFile )
366 # XXX should we strip off any existing path?
367 object_filenames.append( base + newExtension )
368
369 return object_filenames
370
371 def object_filenames (self, source_filenames):
372 """Return the list of object filenames corresponding to each
373 specified source filename."""
374 return self._change_extensions( source_filenames, self._obj_ext )
375
376 def shared_object_filename (self, source_filename):
377 """Return the shared object filename corresponding to a
378 specified source filename."""
379 return self._change_extensions( source_filenames, self._shared_lib_ext )
380
381 def library_filename (self, libname):
382 """Return the static library filename corresponding to the
383 specified library name."""
Greg Wardc8a95c82000-01-17 18:00:04 +0000384 return "%s%s" %( libname, self._static_lib_ext )
Greg Warddbd12761999-08-29 18:15:07 +0000385
386 def shared_library_filename (self, libname):
387 """Return the shared library filename corresponding to the
388 specified library name."""
Greg Wardc8a95c82000-01-17 18:00:04 +0000389 return "%s%s" %( libname, self._shared_lib_ext )
Greg Warddbd12761999-08-29 18:15:07 +0000390
Greg Wardc74138d1999-10-03 20:47:52 +0000391
392 def library_dir_option (self, dir):
393 return "/LIBPATH:" + dir
394
395 def library_option (self, lib):
396 return self.library_filename (lib)
397
398
399 def find_library_file (self, dirs, lib):
400
401 for dir in dirs:
402 libfile = os.path.join (dir, self.library_filename (lib))
403 if os.path.exists (libfile):
404 return libfile
405
406 else:
407 # Oops, didn't find it in *any* of 'dirs'
408 return None
409
410 # find_library_file ()
411
Greg Warddbd12761999-08-29 18:15:07 +0000412# class MSVCCompiler