blob: 2dd8dc10ca3c9a7148e40b52716d0dbf3628e40b [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#
Greg Ward3ce77fd2000-03-02 01:49:45 +00009__revision__ = "$Id$"
Greg Warddbd12761999-08-29 18:15:07 +000010
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 Ward5de8cee2000-02-11 02:52:39 +0000124def set_path_env_var (name, version_number):
125 """Set environment variable 'name' to an MSVC path type value obtained
126 from 'get_msvc_paths()'. This is equivalent to a SET command prior
127 to execution of spawned commands."""
Greg Ward69988092000-02-11 02:47:15 +0000128
Greg Ward5de8cee2000-02-11 02:52:39 +0000129 p = get_msvc_paths (name, version_number)
Greg Ward62e33932000-02-10 02:52:42 +0000130 if p:
Greg Ward5de8cee2000-02-11 02:52:39 +0000131 os.environ[name] = string.join (p,';')
Greg Ward62e33932000-02-10 02:52:42 +0000132
Greg Warddbd12761999-08-29 18:15:07 +0000133
Greg Ward3d50b901999-09-08 02:36:01 +0000134class MSVCCompiler (CCompiler) :
135 """Concrete class that implements an interface to Microsoft Visual C++,
136 as defined by the CCompiler abstract class."""
Greg Warddbd12761999-08-29 18:15:07 +0000137
Greg Warddf178f91999-09-29 12:29:10 +0000138 compiler_type = 'msvc'
139
Greg Warddbd12761999-08-29 18:15:07 +0000140 def __init__ (self,
141 verbose=0,
Greg Wardc74138d1999-10-03 20:47:52 +0000142 dry_run=0,
143 force=0):
Greg Warddbd12761999-08-29 18:15:07 +0000144
Greg Wardc74138d1999-10-03 20:47:52 +0000145 CCompiler.__init__ (self, verbose, dry_run, force)
Greg Warddbd12761999-08-29 18:15:07 +0000146
Greg Warddbd12761999-08-29 18:15:07 +0000147 self.add_library_dir( os.path.join( sys.exec_prefix, 'libs' ) )
148
Greg Ward5de8cee2000-02-11 02:52:39 +0000149 versions = get_devstudio_versions ()
Greg Ward69988092000-02-11 02:47:15 +0000150
Greg Ward5de8cee2000-02-11 02:52:39 +0000151 if versions:
152 version = versions[0] # highest version
Greg Ward69988092000-02-11 02:47:15 +0000153
Greg Ward5de8cee2000-02-11 02:52:39 +0000154 self.cc = _find_exe("cl.exe", version)
155 self.link = _find_exe("link.exe", version)
156 set_path_env_var ('lib', version)
157 set_path_env_var ('include', version)
158 path=get_msvc_paths('path', version)
Greg Ward69988092000-02-11 02:47:15 +0000159 try:
160 for p in string.split(os.environ['path'],';'):
161 path.append(p)
162 except KeyError:
163 pass
164 os.environ['path'] = string.join(path,';')
165 else:
166 # devstudio not found in the registry
167 self.cc = "cl.exe"
168 self.link = "link.exe"
169
Greg Warddbd12761999-08-29 18:15:07 +0000170 self.preprocess_options = None
Greg Ward69988092000-02-11 02:47:15 +0000171 self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3' ]
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000172 self.compile_options_debug = [
Greg Ward69988092000-02-11 02:47:15 +0000173 '/nologo', '/Od', '/MDd', '/W3', '/Z7', '/D_DEBUG'
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000174 ]
Greg Warddbd12761999-08-29 18:15:07 +0000175
Greg Ward1b9c6f72000-02-08 02:39:44 +0000176 self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO']
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000177 self.ldflags_shared_debug = [
178 '/DLL', '/nologo', '/INCREMENTAL:no', '/pdb:None', '/DEBUG'
179 ]
Greg Warddbd12761999-08-29 18:15:07 +0000180 self.ldflags_static = [ '/nologo']
181
Greg Warddbd12761999-08-29 18:15:07 +0000182
183 # -- Worker methods ------------------------------------------------
184 # (must be implemented by subclasses)
185
186 _c_extensions = [ '.c' ]
Greg Ward3d50b901999-09-08 02:36:01 +0000187 _cpp_extensions = [ '.cc', '.cpp' ]
Greg Warddbd12761999-08-29 18:15:07 +0000188
189 _obj_ext = '.obj'
Greg Ward3d50b901999-09-08 02:36:01 +0000190 _exe_ext = '.exe'
Greg Warddbd12761999-08-29 18:15:07 +0000191 _shared_lib_ext = '.dll'
192 _static_lib_ext = '.lib'
Greg Warddf178f91999-09-29 12:29:10 +0000193
194 # XXX the 'output_dir' parameter is ignored by the methods in this
195 # class! I just put it in to be consistent with CCompiler and
196 # UnixCCompiler, but someone who actually knows Visual C++ will
197 # have to make it work...
Greg Warddbd12761999-08-29 18:15:07 +0000198
199 def compile (self,
200 sources,
Greg Warddf178f91999-09-29 12:29:10 +0000201 output_dir=None,
Greg Warddbd12761999-08-29 18:15:07 +0000202 macros=None,
Greg Ward0bdd90a1999-12-12 17:19:58 +0000203 include_dirs=None,
Greg Ward386b8442000-02-09 02:18:39 +0000204 debug=0,
Greg Warddf178f91999-09-29 12:29:10 +0000205 extra_preargs=None,
206 extra_postargs=None):
Greg Warddbd12761999-08-29 18:15:07 +0000207
208 if macros is None:
209 macros = []
Greg Ward0bdd90a1999-12-12 17:19:58 +0000210 if include_dirs is None:
211 include_dirs = []
Greg Warddbd12761999-08-29 18:15:07 +0000212
213 objectFiles = []
214
Greg Ward0bdd90a1999-12-12 17:19:58 +0000215 base_pp_opts = \
216 gen_preprocess_options (self.macros + macros,
217 self.include_dirs + include_dirs)
Greg Warddbd12761999-08-29 18:15:07 +0000218
219 base_pp_opts.append('/c')
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000220
221 if debug:
222 compile_options = self.compile_options_debug
223 else:
224 compile_options = self.compile_options
Greg Warddbd12761999-08-29 18:15:07 +0000225
226 for srcFile in sources:
227 base,ext = os.path.splitext(srcFile)
228 objFile = base + ".obj"
229
230 if ext in self._c_extensions:
231 fileOpt = "/Tc"
232 elif ext in self._cpp_extensions:
233 fileOpt = "/Tp"
234
235 inputOpt = fileOpt + srcFile
236 outputOpt = "/Fo" + objFile
237
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000238 cc_args = compile_options + \
Greg Warddf178f91999-09-29 12:29:10 +0000239 base_pp_opts + \
240 [outputOpt, inputOpt]
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000241
Greg Warddf178f91999-09-29 12:29:10 +0000242 if extra_preargs:
243 cc_args[:0] = extra_preargs
244 if extra_postargs:
245 cc_args.extend (extra_postargs)
Greg Warddbd12761999-08-29 18:15:07 +0000246
Greg Warddf178f91999-09-29 12:29:10 +0000247 self.spawn ([self.cc] + cc_args)
Greg Warddbd12761999-08-29 18:15:07 +0000248 objectFiles.append( objFile )
Greg Warddbd12761999-08-29 18:15:07 +0000249 return objectFiles
Greg Ward3d50b901999-09-08 02:36:01 +0000250
251
Greg Ward386b8442000-02-09 02:18:39 +0000252 # XXX the signature of this method is different from CCompiler and
253 # UnixCCompiler -- but those extra parameters (libraries, library_dirs)
254 # are actually used. So: are they really *needed*, or can they be
255 # ditched? If needed, the CCompiler API will have to change...
Greg Warddbd12761999-08-29 18:15:07 +0000256 def link_static_lib (self,
257 objects,
258 output_libname,
Greg Warddf178f91999-09-29 12:29:10 +0000259 output_dir=None,
Greg Warddbd12761999-08-29 18:15:07 +0000260 libraries=None,
Greg Warddf178f91999-09-29 12:29:10 +0000261 library_dirs=None,
Greg Ward386b8442000-02-09 02:18:39 +0000262 debug=0,
Greg Warddf178f91999-09-29 12:29:10 +0000263 extra_preargs=None,
264 extra_postargs=None):
Greg Warddbd12761999-08-29 18:15:07 +0000265
Greg Warddbd12761999-08-29 18:15:07 +0000266 if libraries is None:
267 libraries = []
268 if library_dirs is None:
269 library_dirs = []
Greg Warddbd12761999-08-29 18:15:07 +0000270
Greg Ward3d50b901999-09-08 02:36:01 +0000271 lib_opts = gen_lib_options (self.libraries + libraries,
272 self.library_dirs + library_dirs,
273 "%s.lib", "/LIBPATH:%s")
Greg Warddbd12761999-08-29 18:15:07 +0000274
Greg Warddbd12761999-08-29 18:15:07 +0000275 ld_args = self.ldflags_static + lib_opts + \
276 objects + ['/OUT:' + output_filename]
Greg Ward386b8442000-02-09 02:18:39 +0000277 if debug:
278 pass # XXX what goes here?
Greg Warddf178f91999-09-29 12:29:10 +0000279 if extra_preargs:
280 ld_args[:0] = extra_preargs
281 if extra_postargs:
282 ld_args.extend (extra_postargs)
Greg Warddbd12761999-08-29 18:15:07 +0000283
284 self.spawn ( [ self.link ] + ld_args )
285
286
287 def link_shared_lib (self,
288 objects,
289 output_libname,
Greg Warddf178f91999-09-29 12:29:10 +0000290 output_dir=None,
Greg Warddbd12761999-08-29 18:15:07 +0000291 libraries=None,
292 library_dirs=None,
Greg Ward386b8442000-02-09 02:18:39 +0000293 debug=0,
Greg Warddf178f91999-09-29 12:29:10 +0000294 extra_preargs=None,
295 extra_postargs=None):
296
Greg Warddbd12761999-08-29 18:15:07 +0000297 # XXX should we sanity check the library name? (eg. no
298 # slashes)
Greg Warddf178f91999-09-29 12:29:10 +0000299 self.link_shared_object (objects,
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000300 self.shared_library_name(output_libname),
301 output_dir=output_dir,
302 libraries=libraries,
303 library_dirs=library_dirs,
304 debug=debug,
305 extra_preargs=extra_preargs,
306 extra_postargs=extra_postargs)
307
Greg Warddbd12761999-08-29 18:15:07 +0000308
309 def link_shared_object (self,
310 objects,
311 output_filename,
Greg Warddf178f91999-09-29 12:29:10 +0000312 output_dir=None,
Greg Warddbd12761999-08-29 18:15:07 +0000313 libraries=None,
314 library_dirs=None,
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000315 debug=0,
Greg Warddf178f91999-09-29 12:29:10 +0000316 extra_preargs=None,
317 extra_postargs=None):
Greg Warddbd12761999-08-29 18:15:07 +0000318 """Link a bunch of stuff together to create a shared object
319 file. Much like 'link_shared_lib()', except the output
320 filename is explicitly supplied as 'output_filename'."""
321 if libraries is None:
322 libraries = []
323 if library_dirs is None:
324 library_dirs = []
Greg Warddbd12761999-08-29 18:15:07 +0000325
Greg Wardc74138d1999-10-03 20:47:52 +0000326 lib_opts = gen_lib_options (self,
327 self.library_dirs + library_dirs,
328 self.libraries + libraries)
Greg Warddbd12761999-08-29 18:15:07 +0000329
Greg Ward386b8442000-02-09 02:18:39 +0000330 if debug:
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000331 ldflags = self.ldflags_shared_debug
332 basename, ext = os.path.splitext (output_filename)
333 #XXX not sure this belongs here
334 # extensions in debug_mode are named 'module_d.pyd'
335 output_filename = basename + '_d' + ext
336 else:
337 ldflags = self.ldflags_shared
338
339 ld_args = ldflags + lib_opts + \
340 objects + ['/OUT:' + output_filename]
341
Greg Warddf178f91999-09-29 12:29:10 +0000342 if extra_preargs:
343 ld_args[:0] = extra_preargs
344 if extra_postargs:
345 ld_args.extend (extra_postargs)
Greg Warddbd12761999-08-29 18:15:07 +0000346
347 self.spawn ( [ self.link ] + ld_args )
348
349
350 # -- Filename mangling methods -------------------------------------
351
352 def _change_extensions( self, filenames, newExtension ):
353 object_filenames = []
354
355 for srcFile in filenames:
356 base,ext = os.path.splitext( srcFile )
357 # XXX should we strip off any existing path?
358 object_filenames.append( base + newExtension )
359
360 return object_filenames
361
362 def object_filenames (self, source_filenames):
363 """Return the list of object filenames corresponding to each
364 specified source filename."""
365 return self._change_extensions( source_filenames, self._obj_ext )
366
367 def shared_object_filename (self, source_filename):
368 """Return the shared object filename corresponding to a
369 specified source filename."""
370 return self._change_extensions( source_filenames, self._shared_lib_ext )
371
372 def library_filename (self, libname):
373 """Return the static library filename corresponding to the
374 specified library name."""
Greg Wardc8a95c82000-01-17 18:00:04 +0000375 return "%s%s" %( libname, self._static_lib_ext )
Greg Warddbd12761999-08-29 18:15:07 +0000376
377 def shared_library_filename (self, libname):
378 """Return the shared library filename corresponding to the
379 specified library name."""
Greg Wardc8a95c82000-01-17 18:00:04 +0000380 return "%s%s" %( libname, self._shared_lib_ext )
Greg Warddbd12761999-08-29 18:15:07 +0000381
Greg Wardc74138d1999-10-03 20:47:52 +0000382
383 def library_dir_option (self, dir):
384 return "/LIBPATH:" + dir
385
386 def library_option (self, lib):
387 return self.library_filename (lib)
388
389
390 def find_library_file (self, dirs, lib):
391
392 for dir in dirs:
393 libfile = os.path.join (dir, self.library_filename (lib))
394 if os.path.exists (libfile):
395 return libfile
396
397 else:
398 # Oops, didn't find it in *any* of 'dirs'
399 return None
400
401 # find_library_file ()
402
Greg Warddbd12761999-08-29 18:15:07 +0000403# class MSVCCompiler