blob: bf5257f1d6b7aca2f526d04ad55a05cde93ab283 [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
Greg Ward32c4a8a2000-03-06 03:40:29 +00008# hacked by Robin Becker and Thomas Heller to do a better job of
9# finding DevStudio (through the registry)
10
Greg Ward3ce77fd2000-03-02 01:49:45 +000011__revision__ = "$Id$"
Greg Warddbd12761999-08-29 18:15:07 +000012
Greg Ward32c4a8a2000-03-06 03:40:29 +000013import sys, os, string
14from types import *
Greg Warddbd12761999-08-29 18:15:07 +000015from distutils.errors import *
Greg Ward3d50b901999-09-08 02:36:01 +000016from distutils.ccompiler import \
17 CCompiler, gen_preprocess_options, gen_lib_options
Greg Warddbd12761999-08-29 18:15:07 +000018
Greg Ward62e33932000-02-10 02:52:42 +000019
20def get_devstudio_versions ():
Greg Ward62e33932000-02-10 02:52:42 +000021 """Get list of devstudio versions from the Windows registry. Return a
Greg Ward69988092000-02-11 02:47:15 +000022 list of strings containing version numbers; the list will be
Greg Ward62e33932000-02-10 02:52:42 +000023 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
Greg Ward69988092000-02-11 02:47:15 +000025 found."""
26
Greg Ward1b9c6f72000-02-08 02:39:44 +000027 try:
28 import win32api
29 import win32con
30 except ImportError:
Greg Ward62e33932000-02-10 02:52:42 +000031 return []
Greg Ward1b9c6f72000-02-08 02:39:44 +000032
33 K = 'Software\\Microsoft\\Devstudio'
34 L = []
Greg Ward62e33932000-02-10 02:52:42 +000035 for base in (win32con.HKEY_CLASSES_ROOT,
36 win32con.HKEY_LOCAL_MACHINE,
37 win32con.HKEY_CURRENT_USER,
38 win32con.HKEY_USERS):
Greg Ward1b9c6f72000-02-08 02:39:44 +000039 try:
40 k = win32api.RegOpenKeyEx(base,K)
41 i = 0
42 while 1:
43 try:
44 p = win32api.RegEnumKey(k,i)
45 if p[0] in '123456789' and p not in L:
46 L.append(p)
47 except win32api.error:
48 break
49 i = i + 1
50 except win32api.error:
51 pass
52 L.sort()
53 L.reverse()
54 return L
55
Greg Ward62e33932000-02-10 02:52:42 +000056# get_devstudio_versions ()
57
58
59def get_msvc_paths (path, version='6.0', platform='x86'):
Greg Ward69988092000-02-11 02:47:15 +000060 """Get a list of devstudio directories (include, lib or path). Return
61 a list of strings; will be empty list if unable to access the
62 registry or appropriate registry keys not found."""
63
Greg Ward1b9c6f72000-02-08 02:39:44 +000064 try:
65 import win32api
66 import win32con
67 except ImportError:
Greg Ward69988092000-02-11 02:47:15 +000068 return []
Greg Ward1b9c6f72000-02-08 02:39:44 +000069
70 L = []
Greg Ward62e33932000-02-10 02:52:42 +000071 if path=='lib':
72 path= 'Library'
Greg Ward1b9c6f72000-02-08 02:39:44 +000073 path = string.upper(path + ' Dirs')
Greg Ward62e33932000-02-10 02:52:42 +000074 K = ('Software\\Microsoft\\Devstudio\\%s\\' +
75 'Build System\\Components\\Platforms\\Win32 (%s)\\Directories') % \
76 (version,platform)
77 for base in (win32con.HKEY_CLASSES_ROOT,
78 win32con.HKEY_LOCAL_MACHINE,
79 win32con.HKEY_CURRENT_USER,
80 win32con.HKEY_USERS):
Greg Ward1b9c6f72000-02-08 02:39:44 +000081 try:
82 k = win32api.RegOpenKeyEx(base,K)
83 i = 0
84 while 1:
85 try:
86 (p,v,t) = win32api.RegEnumValue(k,i)
Greg Ward62e33932000-02-10 02:52:42 +000087 if string.upper(p) == path:
Greg Ward1b9c6f72000-02-08 02:39:44 +000088 V = string.split(v,';')
89 for v in V:
Greg Ward62e33932000-02-10 02:52:42 +000090 if v == '' or v in L: continue
Greg Ward1b9c6f72000-02-08 02:39:44 +000091 L.append(v)
92 break
93 i = i + 1
94 except win32api.error:
95 break
96 except win32api.error:
97 pass
98 return L
99
Greg Ward62e33932000-02-10 02:52:42 +0000100# get_msvc_paths()
101
102
Greg Ward69988092000-02-11 02:47:15 +0000103def find_exe (exe, version_number):
104 """Try to find an MSVC executable program 'exe' (from version
105 'version_number' of MSVC) in several places: first, one of the MSVC
106 program search paths from the registry; next, the directories in the
107 PATH environment variable. If any of those work, return an absolute
108 path that is known to exist. If none of them work, just return the
109 original program name, 'exe'."""
Greg Ward1b9c6f72000-02-08 02:39:44 +0000110
Greg Ward69988092000-02-11 02:47:15 +0000111 for p in get_msvc_paths ('path', version_number):
112 fn = os.path.join (os.path.abspath(p), exe)
113 if os.path.isfile(fn):
114 return fn
115
116 # didn't find it; try existing path
117 for p in string.split (os.environ['Path'],';'):
118 fn = os.path.join(os.path.abspath(p),exe)
119 if os.path.isfile(fn):
120 return fn
121
122 return exe # last desperate hope
Greg Ward1b9c6f72000-02-08 02:39:44 +0000123
Greg Ward62e33932000-02-10 02:52:42 +0000124
Greg Ward5de8cee2000-02-11 02:52:39 +0000125def set_path_env_var (name, version_number):
126 """Set environment variable 'name' to an MSVC path type value obtained
127 from 'get_msvc_paths()'. This is equivalent to a SET command prior
128 to execution of spawned commands."""
Greg Ward69988092000-02-11 02:47:15 +0000129
Greg Ward5de8cee2000-02-11 02:52:39 +0000130 p = get_msvc_paths (name, version_number)
Greg Ward62e33932000-02-10 02:52:42 +0000131 if p:
Greg Ward5de8cee2000-02-11 02:52:39 +0000132 os.environ[name] = string.join (p,';')
Greg Ward62e33932000-02-10 02:52:42 +0000133
Greg Warddbd12761999-08-29 18:15:07 +0000134
Greg Ward3d50b901999-09-08 02:36:01 +0000135class MSVCCompiler (CCompiler) :
136 """Concrete class that implements an interface to Microsoft Visual C++,
137 as defined by the CCompiler abstract class."""
Greg Warddbd12761999-08-29 18:15:07 +0000138
Greg Warddf178f91999-09-29 12:29:10 +0000139 compiler_type = 'msvc'
140
Greg Ward32c4a8a2000-03-06 03:40:29 +0000141 # Private class data (need to distinguish C from C++ source for compiler)
142 _c_extensions = ['.c']
143 _cpp_extensions = ['.cc','.cpp']
144
145 # Needed for the filename generation methods provided by the
146 # base class, CCompiler.
147 src_extensions = _c_extensions + _cpp_extensions
148 obj_extension = '.obj'
149 static_lib_extension = '.lib'
150 shared_lib_extension = '.dll'
151 static_lib_format = shared_lib_format = '%s%s'
152 exe_extension = '.exe'
153
154
Greg Warddbd12761999-08-29 18:15:07 +0000155 def __init__ (self,
156 verbose=0,
Greg Wardc74138d1999-10-03 20:47:52 +0000157 dry_run=0,
158 force=0):
Greg Warddbd12761999-08-29 18:15:07 +0000159
Greg Wardc74138d1999-10-03 20:47:52 +0000160 CCompiler.__init__ (self, verbose, dry_run, force)
Greg Warddbd12761999-08-29 18:15:07 +0000161
Greg Warddbd12761999-08-29 18:15:07 +0000162 self.add_library_dir( os.path.join( sys.exec_prefix, 'libs' ) )
163
Greg Ward5de8cee2000-02-11 02:52:39 +0000164 versions = get_devstudio_versions ()
Greg Ward69988092000-02-11 02:47:15 +0000165
Greg Ward5de8cee2000-02-11 02:52:39 +0000166 if versions:
167 version = versions[0] # highest version
Greg Ward69988092000-02-11 02:47:15 +0000168
Greg Ward5de8cee2000-02-11 02:52:39 +0000169 self.cc = _find_exe("cl.exe", version)
170 self.link = _find_exe("link.exe", version)
Greg Ward09fc5422000-03-10 01:49:26 +0000171 self.lib = _find_exe("lib.exe", version)
Greg Ward5de8cee2000-02-11 02:52:39 +0000172 set_path_env_var ('lib', version)
173 set_path_env_var ('include', version)
174 path=get_msvc_paths('path', version)
Greg Ward69988092000-02-11 02:47:15 +0000175 try:
176 for p in string.split(os.environ['path'],';'):
177 path.append(p)
178 except KeyError:
179 pass
180 os.environ['path'] = string.join(path,';')
181 else:
182 # devstudio not found in the registry
183 self.cc = "cl.exe"
184 self.link = "link.exe"
Greg Ward09fc5422000-03-10 01:49:26 +0000185 self.lib = "lib.exe"
Greg Ward69988092000-02-11 02:47:15 +0000186
Greg Warddbd12761999-08-29 18:15:07 +0000187 self.preprocess_options = None
Greg Ward69988092000-02-11 02:47:15 +0000188 self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3' ]
Greg Ward32c4a8a2000-03-06 03:40:29 +0000189 self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/Z7', '/D_DEBUG']
Greg Warddbd12761999-08-29 18:15:07 +0000190
Greg Ward1b9c6f72000-02-08 02:39:44 +0000191 self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO']
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000192 self.ldflags_shared_debug = [
193 '/DLL', '/nologo', '/INCREMENTAL:no', '/pdb:None', '/DEBUG'
194 ]
Greg Warddbd12761999-08-29 18:15:07 +0000195 self.ldflags_static = [ '/nologo']
196
Greg Warddbd12761999-08-29 18:15:07 +0000197
198 # -- Worker methods ------------------------------------------------
Greg Warddbd12761999-08-29 18:15:07 +0000199
Greg Warddbd12761999-08-29 18:15:07 +0000200 def compile (self,
201 sources,
Greg Warddf178f91999-09-29 12:29:10 +0000202 output_dir=None,
Greg Warddbd12761999-08-29 18:15:07 +0000203 macros=None,
Greg Ward0bdd90a1999-12-12 17:19:58 +0000204 include_dirs=None,
Greg Ward386b8442000-02-09 02:18:39 +0000205 debug=0,
Greg Warddf178f91999-09-29 12:29:10 +0000206 extra_preargs=None,
207 extra_postargs=None):
Greg Warddbd12761999-08-29 18:15:07 +0000208
Greg Ward32c4a8a2000-03-06 03:40:29 +0000209 (output_dir, macros, include_dirs) = \
210 self._fix_compile_args (output_dir, macros, include_dirs)
211 (objects, skip_sources) = self._prep_compile (sources, output_dir)
Greg Warddbd12761999-08-29 18:15:07 +0000212
Greg Ward32c4a8a2000-03-06 03:40:29 +0000213 if extra_postargs is None:
214 extra_postargs = []
Greg Warddbd12761999-08-29 18:15:07 +0000215
Greg Ward32c4a8a2000-03-06 03:40:29 +0000216 pp_opts = gen_preprocess_options (macros, include_dirs)
217 compile_opts = extra_preargs or []
218 compile_opts.append ('/c')
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000219 if debug:
Greg Ward32c4a8a2000-03-06 03:40:29 +0000220 compile_opts.extend (self.compile_options_debug)
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000221 else:
Greg Ward32c4a8a2000-03-06 03:40:29 +0000222 compile_opts.extend (self.compile_options)
Greg Warddbd12761999-08-29 18:15:07 +0000223
Greg Ward32c4a8a2000-03-06 03:40:29 +0000224 for i in range (len (sources)):
225 src = sources[i] ; obj = objects[i]
226 ext = (os.path.splitext (src))[1]
Greg Warddbd12761999-08-29 18:15:07 +0000227
Greg Ward32c4a8a2000-03-06 03:40:29 +0000228 if skip_sources[src]:
229 self.announce ("skipping %s (%s up-to-date)" % (src, obj))
230 else:
231 if ext in self._c_extensions:
232 input_opt = "/Tc" + src
233 elif ext in self._cpp_extensions:
234 input_opt = "/Tp" + src
Greg Warddbd12761999-08-29 18:15:07 +0000235
Greg Ward32c4a8a2000-03-06 03:40:29 +0000236 output_opt = "/Fo" + obj
Greg Warddbd12761999-08-29 18:15:07 +0000237
Greg Ward32c4a8a2000-03-06 03:40:29 +0000238 self.mkpath (os.path.dirname (obj))
239 self.spawn ([self.cc] + compile_opts + pp_opts +
240 [input_opt, output_opt] +
241 extra_postargs)
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000242
Greg Ward32c4a8a2000-03-06 03:40:29 +0000243 return objects
Greg Warddbd12761999-08-29 18:15:07 +0000244
Greg Ward32c4a8a2000-03-06 03:40:29 +0000245 # compile ()
Greg Ward3d50b901999-09-08 02:36:01 +0000246
247
Greg Ward09fc5422000-03-10 01:49:26 +0000248 def create_static_lib (self,
249 objects,
250 output_libname,
251 output_dir=None,
252 debug=0,
253 extra_preargs=None,
254 extra_postargs=None):
Greg Warddbd12761999-08-29 18:15:07 +0000255
Greg Ward09fc5422000-03-10 01:49:26 +0000256 (objects, output_dir) = \
257 self._fix_link_args (objects, output_dir, takes_libs=0)
Greg Ward32c4a8a2000-03-06 03:40:29 +0000258 output_filename = \
259 self.library_filename (output_libname, output_dir=output_dir)
Greg Warddbd12761999-08-29 18:15:07 +0000260
Greg Ward32c4a8a2000-03-06 03:40:29 +0000261 if self._need_link (objects, output_filename):
Greg Ward09fc5422000-03-10 01:49:26 +0000262 lib_args = objects + ['/OUT:' + output_filename]
Greg Ward32c4a8a2000-03-06 03:40:29 +0000263 if debug:
264 pass # XXX what goes here?
265 if extra_preargs:
Greg Ward09fc5422000-03-10 01:49:26 +0000266 lib_args[:0] = extra_preargs
Greg Ward32c4a8a2000-03-06 03:40:29 +0000267 if extra_postargs:
Greg Ward09fc5422000-03-10 01:49:26 +0000268 lib_args.extend (extra_postargs)
Greg Ward32c4a8a2000-03-06 03:40:29 +0000269 self.spawn ([self.link] + ld_args)
270 else:
271 self.announce ("skipping %s (up-to-date)" % output_filename)
Greg Warddbd12761999-08-29 18:15:07 +0000272
Greg Ward09fc5422000-03-10 01:49:26 +0000273 # create_static_lib ()
Greg Warddbd12761999-08-29 18:15:07 +0000274
275
276 def link_shared_lib (self,
277 objects,
278 output_libname,
Greg Warddf178f91999-09-29 12:29:10 +0000279 output_dir=None,
Greg Warddbd12761999-08-29 18:15:07 +0000280 libraries=None,
281 library_dirs=None,
Greg Ward386b8442000-02-09 02:18:39 +0000282 debug=0,
Greg Warddf178f91999-09-29 12:29:10 +0000283 extra_preargs=None,
284 extra_postargs=None):
285
Greg Warddf178f91999-09-29 12:29:10 +0000286 self.link_shared_object (objects,
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000287 self.shared_library_name(output_libname),
288 output_dir=output_dir,
289 libraries=libraries,
290 library_dirs=library_dirs,
291 debug=debug,
292 extra_preargs=extra_preargs,
293 extra_postargs=extra_postargs)
294
Greg Warddbd12761999-08-29 18:15:07 +0000295
296 def link_shared_object (self,
297 objects,
298 output_filename,
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 Ward4ba9b2e2000-02-10 02:15:52 +0000302 debug=0,
Greg Warddf178f91999-09-29 12:29:10 +0000303 extra_preargs=None,
304 extra_postargs=None):
Greg Ward32c4a8a2000-03-06 03:40:29 +0000305
306 (objects, output_dir, libraries, library_dirs) = \
307 self._fix_link_args (objects, output_dir, takes_libs=1,
308 libraries=libraries, library_dirs=library_dirs)
Greg Warddbd12761999-08-29 18:15:07 +0000309
Greg Ward32c4a8a2000-03-06 03:40:29 +0000310 lib_opts = gen_lib_options (self, library_dirs, libraries)
311 if type (output_dir) not in (StringType, NoneType):
312 raise TypeError, "'output_dir' must be a string or None"
313 if output_dir is not None:
314 output_filename = os.path.join (output_dir, output_filename)
Greg Warddbd12761999-08-29 18:15:07 +0000315
Greg Ward32c4a8a2000-03-06 03:40:29 +0000316 if self._need_link (objects, output_filename):
317
318 if debug:
319 ldflags = self.ldflags_shared_debug
320 # XXX not sure this belongs here
321 # extensions in debug_mode are named 'module_d.pyd'
322 basename, ext = os.path.splitext (output_filename)
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
330 if extra_preargs:
331 ld_args[:0] = extra_preargs
332 if extra_postargs:
333 ld_args.extend (extra_postargs)
334
335 self.mkpath (os.path.dirname (output_filename))
336 self.spawn ([self.link] + ld_args)
337
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000338 else:
Greg Ward32c4a8a2000-03-06 03:40:29 +0000339 self.announce ("skipping %s (up-to-date)" % output_filename)
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000340
Greg Ward32c4a8a2000-03-06 03:40:29 +0000341 # link_shared_object ()
342
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000343
Greg Ward32c4a8a2000-03-06 03:40:29 +0000344 # -- Miscellaneous methods -----------------------------------------
345 # These are all used by the 'gen_lib_options() function, in
346 # ccompiler.py.
Greg Wardc74138d1999-10-03 20:47:52 +0000347
348 def library_dir_option (self, dir):
349 return "/LIBPATH:" + dir
350
351 def library_option (self, lib):
352 return self.library_filename (lib)
353
354
355 def find_library_file (self, dirs, lib):
356
357 for dir in dirs:
358 libfile = os.path.join (dir, self.library_filename (lib))
359 if os.path.exists (libfile):
360 return libfile
361
362 else:
363 # Oops, didn't find it in *any* of 'dirs'
364 return None
365
366 # find_library_file ()
367
Greg Warddbd12761999-08-29 18:15:07 +0000368# class MSVCCompiler