blob: 2828711e7b76bb8adc220788dfdb607c8d2e3229 [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 Ward5de8cee2000-02-11 02:52:39 +0000161 versions = get_devstudio_versions ()
Greg Ward69988092000-02-11 02:47:15 +0000162
Greg Ward5de8cee2000-02-11 02:52:39 +0000163 if versions:
164 version = versions[0] # highest version
Greg Ward69988092000-02-11 02:47:15 +0000165
Greg Ward41b4dd62000-03-29 04:13:00 +0000166 self.cc = find_exe("cl.exe", version)
167 self.link = find_exe("link.exe", version)
168 self.lib = find_exe("lib.exe", version)
Greg Ward5de8cee2000-02-11 02:52:39 +0000169 set_path_env_var ('lib', version)
170 set_path_env_var ('include', version)
171 path=get_msvc_paths('path', version)
Greg Ward69988092000-02-11 02:47:15 +0000172 try:
173 for p in string.split(os.environ['path'],';'):
174 path.append(p)
175 except KeyError:
176 pass
177 os.environ['path'] = string.join(path,';')
178 else:
179 # devstudio not found in the registry
180 self.cc = "cl.exe"
181 self.link = "link.exe"
Greg Ward09fc5422000-03-10 01:49:26 +0000182 self.lib = "lib.exe"
Greg Ward69988092000-02-11 02:47:15 +0000183
Greg Warddbd12761999-08-29 18:15:07 +0000184 self.preprocess_options = None
Greg Ward69988092000-02-11 02:47:15 +0000185 self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3' ]
Greg Ward32c4a8a2000-03-06 03:40:29 +0000186 self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/Z7', '/D_DEBUG']
Greg Warddbd12761999-08-29 18:15:07 +0000187
Greg Ward1b9c6f72000-02-08 02:39:44 +0000188 self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO']
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000189 self.ldflags_shared_debug = [
190 '/DLL', '/nologo', '/INCREMENTAL:no', '/pdb:None', '/DEBUG'
191 ]
Greg Warddbd12761999-08-29 18:15:07 +0000192 self.ldflags_static = [ '/nologo']
193
Greg Warddbd12761999-08-29 18:15:07 +0000194
195 # -- Worker methods ------------------------------------------------
Greg Warddbd12761999-08-29 18:15:07 +0000196
Greg Warddbd12761999-08-29 18:15:07 +0000197 def compile (self,
198 sources,
Greg Warddf178f91999-09-29 12:29:10 +0000199 output_dir=None,
Greg Warddbd12761999-08-29 18:15:07 +0000200 macros=None,
Greg Ward0bdd90a1999-12-12 17:19:58 +0000201 include_dirs=None,
Greg Ward386b8442000-02-09 02:18:39 +0000202 debug=0,
Greg Warddf178f91999-09-29 12:29:10 +0000203 extra_preargs=None,
204 extra_postargs=None):
Greg Warddbd12761999-08-29 18:15:07 +0000205
Greg Ward32c4a8a2000-03-06 03:40:29 +0000206 (output_dir, macros, include_dirs) = \
207 self._fix_compile_args (output_dir, macros, include_dirs)
208 (objects, skip_sources) = self._prep_compile (sources, output_dir)
Greg Warddbd12761999-08-29 18:15:07 +0000209
Greg Ward32c4a8a2000-03-06 03:40:29 +0000210 if extra_postargs is None:
211 extra_postargs = []
Greg Warddbd12761999-08-29 18:15:07 +0000212
Greg Ward32c4a8a2000-03-06 03:40:29 +0000213 pp_opts = gen_preprocess_options (macros, include_dirs)
214 compile_opts = extra_preargs or []
215 compile_opts.append ('/c')
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000216 if debug:
Greg Ward32c4a8a2000-03-06 03:40:29 +0000217 compile_opts.extend (self.compile_options_debug)
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000218 else:
Greg Ward32c4a8a2000-03-06 03:40:29 +0000219 compile_opts.extend (self.compile_options)
Greg Warddbd12761999-08-29 18:15:07 +0000220
Greg Ward32c4a8a2000-03-06 03:40:29 +0000221 for i in range (len (sources)):
222 src = sources[i] ; obj = objects[i]
223 ext = (os.path.splitext (src))[1]
Greg Warddbd12761999-08-29 18:15:07 +0000224
Greg Ward32c4a8a2000-03-06 03:40:29 +0000225 if skip_sources[src]:
226 self.announce ("skipping %s (%s up-to-date)" % (src, obj))
227 else:
228 if ext in self._c_extensions:
229 input_opt = "/Tc" + src
230 elif ext in self._cpp_extensions:
231 input_opt = "/Tp" + src
Greg Warddbd12761999-08-29 18:15:07 +0000232
Greg Ward32c4a8a2000-03-06 03:40:29 +0000233 output_opt = "/Fo" + obj
Greg Warddbd12761999-08-29 18:15:07 +0000234
Greg Ward32c4a8a2000-03-06 03:40:29 +0000235 self.mkpath (os.path.dirname (obj))
236 self.spawn ([self.cc] + compile_opts + pp_opts +
237 [input_opt, output_opt] +
238 extra_postargs)
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000239
Greg Ward32c4a8a2000-03-06 03:40:29 +0000240 return objects
Greg Warddbd12761999-08-29 18:15:07 +0000241
Greg Ward32c4a8a2000-03-06 03:40:29 +0000242 # compile ()
Greg Ward3d50b901999-09-08 02:36:01 +0000243
244
Greg Ward09fc5422000-03-10 01:49:26 +0000245 def create_static_lib (self,
246 objects,
247 output_libname,
248 output_dir=None,
249 debug=0,
250 extra_preargs=None,
251 extra_postargs=None):
Greg Warddbd12761999-08-29 18:15:07 +0000252
Greg Ward2f557a22000-03-26 21:42:28 +0000253 (objects, output_dir) = self._fix_object_args (objects, output_dir)
Greg Ward32c4a8a2000-03-06 03:40:29 +0000254 output_filename = \
255 self.library_filename (output_libname, output_dir=output_dir)
Greg Warddbd12761999-08-29 18:15:07 +0000256
Greg Ward32c4a8a2000-03-06 03:40:29 +0000257 if self._need_link (objects, output_filename):
Greg Ward09fc5422000-03-10 01:49:26 +0000258 lib_args = objects + ['/OUT:' + output_filename]
Greg Ward32c4a8a2000-03-06 03:40:29 +0000259 if debug:
260 pass # XXX what goes here?
261 if extra_preargs:
Greg Ward09fc5422000-03-10 01:49:26 +0000262 lib_args[:0] = extra_preargs
Greg Ward32c4a8a2000-03-06 03:40:29 +0000263 if extra_postargs:
Greg Ward09fc5422000-03-10 01:49:26 +0000264 lib_args.extend (extra_postargs)
Greg Ward32c4a8a2000-03-06 03:40:29 +0000265 self.spawn ([self.link] + ld_args)
266 else:
267 self.announce ("skipping %s (up-to-date)" % output_filename)
Greg Warddbd12761999-08-29 18:15:07 +0000268
Greg Ward09fc5422000-03-10 01:49:26 +0000269 # create_static_lib ()
Greg Warddbd12761999-08-29 18:15:07 +0000270
271
272 def link_shared_lib (self,
273 objects,
274 output_libname,
Greg Warddf178f91999-09-29 12:29:10 +0000275 output_dir=None,
Greg Warddbd12761999-08-29 18:15:07 +0000276 libraries=None,
277 library_dirs=None,
Greg Ward2f557a22000-03-26 21:42:28 +0000278 runtime_library_dirs=None,
Greg Ward386b8442000-02-09 02:18:39 +0000279 debug=0,
Greg Warddf178f91999-09-29 12:29:10 +0000280 extra_preargs=None,
281 extra_postargs=None):
282
Greg Warddf178f91999-09-29 12:29:10 +0000283 self.link_shared_object (objects,
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000284 self.shared_library_name(output_libname),
285 output_dir=output_dir,
286 libraries=libraries,
287 library_dirs=library_dirs,
288 debug=debug,
289 extra_preargs=extra_preargs,
290 extra_postargs=extra_postargs)
291
Greg Warddbd12761999-08-29 18:15:07 +0000292
293 def link_shared_object (self,
294 objects,
295 output_filename,
Greg Warddf178f91999-09-29 12:29:10 +0000296 output_dir=None,
Greg Warddbd12761999-08-29 18:15:07 +0000297 libraries=None,
298 library_dirs=None,
Greg Ward2f557a22000-03-26 21:42:28 +0000299 runtime_library_dirs=None,
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000300 debug=0,
Greg Warddf178f91999-09-29 12:29:10 +0000301 extra_preargs=None,
302 extra_postargs=None):
Greg Ward32c4a8a2000-03-06 03:40:29 +0000303
Greg Ward2f557a22000-03-26 21:42:28 +0000304 (objects, output_dir) = self._fix_object_args (objects, output_dir)
305 (libraries, library_dirs, runtime_library_dirs) = \
306 self._fix_lib_args (libraries, library_dirs, runtime_library_dirs)
307
308 if self.runtime_library_dirs:
309 self.warn ("I don't know what to do with 'runtime_library_dirs': "
310 + str (runtime_library_dirs))
Greg Warddbd12761999-08-29 18:15:07 +0000311
Greg Wardd03f88a2000-03-18 15:19:51 +0000312 lib_opts = gen_lib_options (self,
Greg Ward2f557a22000-03-26 21:42:28 +0000313 library_dirs, runtime_library_dirs,
Greg Wardd03f88a2000-03-18 15:19:51 +0000314 libraries)
Greg Ward32c4a8a2000-03-06 03:40:29 +0000315 if type (output_dir) not in (StringType, NoneType):
316 raise TypeError, "'output_dir' must be a string or None"
317 if output_dir is not None:
318 output_filename = os.path.join (output_dir, output_filename)
Greg Warddbd12761999-08-29 18:15:07 +0000319
Greg Ward32c4a8a2000-03-06 03:40:29 +0000320 if self._need_link (objects, output_filename):
321
322 if debug:
323 ldflags = self.ldflags_shared_debug
Greg Ward32c4a8a2000-03-06 03:40:29 +0000324 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
Greg Wardd03f88a2000-03-18 15:19:51 +0000351 def runtime_library_dir_option (self, dir):
352 raise DistutilsPlatformError, \
353 "don't know how to set runtime library search path for MSVC++"
354
Greg Wardc74138d1999-10-03 20:47:52 +0000355 def library_option (self, lib):
356 return self.library_filename (lib)
357
358
359 def find_library_file (self, dirs, lib):
360
361 for dir in dirs:
362 libfile = os.path.join (dir, self.library_filename (lib))
363 if os.path.exists (libfile):
364 return libfile
365
366 else:
367 # Oops, didn't find it in *any* of 'dirs'
368 return None
369
370 # find_library_file ()
371
Greg Warddbd12761999-08-29 18:15:07 +0000372# class MSVCCompiler