blob: b38aadbece5e178327ac68f0abceae4139544170 [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
Greg Ward7642f5c2000-03-31 16:47:40 +000020_can_read_reg = 0
21try:
22 import winreg
Greg Ward7642f5c2000-03-31 16:47:40 +000023 _can_read_reg = 1
Greg Ward1027e3f2000-03-31 16:53:42 +000024 hkey_mod = winreg # module that provides HKEY_* stuff
25 reg_mod = winreg # provides other registry stuff
Greg Ward7642f5c2000-03-31 16:47:40 +000026except ImportError:
27 try:
28 import win32api
29 import win32con
Greg Ward7642f5c2000-03-31 16:47:40 +000030 _can_read_reg = 1
Greg Ward1027e3f2000-03-31 16:53:42 +000031 hkey_mod = win32con
32 reg_mod = win32api
Greg Ward7642f5c2000-03-31 16:47:40 +000033 except ImportError:
34 pass
Greg Ward1027e3f2000-03-31 16:53:42 +000035
36if _can_read_reg:
37 HKEY_CLASSES_ROOT = hkey_mod.HKEY_CLASSES_ROOT
38 HKEY_LOCAL_MACHINE = hkey_mod.HKEY_LOCAL_MACHINE
39 HKEY_CURRENT_USER = hkey_mod.HKEY_CURRENT_USER
40 HKEY_USERS = hkey_mod.HKEY_USERS
41 RegOpenKeyEx = reg_mod.RegOpenKeyEx
42 RegEnumKey = reg_mod.RegEnumKey
43 RegEnumValue = reg_mod.RegEnumValue
44 RegError = reg_mod.error
45 _can_read_reg = 1
46
Greg Ward7642f5c2000-03-31 16:47:40 +000047
48
Greg Ward62e33932000-02-10 02:52:42 +000049def get_devstudio_versions ():
Greg Ward62e33932000-02-10 02:52:42 +000050 """Get list of devstudio versions from the Windows registry. Return a
Greg Ward69988092000-02-11 02:47:15 +000051 list of strings containing version numbers; the list will be
Greg Ward62e33932000-02-10 02:52:42 +000052 empty if we were unable to access the registry (eg. couldn't import
53 a registry-access module) or the appropriate registry keys weren't
Greg Ward69988092000-02-11 02:47:15 +000054 found."""
55
Greg Ward7642f5c2000-03-31 16:47:40 +000056 if not _can_read_reg:
Greg Ward62e33932000-02-10 02:52:42 +000057 return []
Greg Ward1b9c6f72000-02-08 02:39:44 +000058
59 K = 'Software\\Microsoft\\Devstudio'
60 L = []
Greg Ward1027e3f2000-03-31 16:53:42 +000061 for base in (HKEY_CLASSES_ROOT,
62 HKEY_LOCAL_MACHINE,
63 HKEY_CURRENT_USER,
64 HKEY_USERS):
Greg Ward1b9c6f72000-02-08 02:39:44 +000065 try:
Greg Ward1027e3f2000-03-31 16:53:42 +000066 k = RegOpenKeyEx(base,K)
Greg Ward1b9c6f72000-02-08 02:39:44 +000067 i = 0
68 while 1:
69 try:
Greg Ward1027e3f2000-03-31 16:53:42 +000070 p = RegEnumKey(k,i)
Greg Ward1b9c6f72000-02-08 02:39:44 +000071 if p[0] in '123456789' and p not in L:
72 L.append(p)
Greg Ward1027e3f2000-03-31 16:53:42 +000073 except RegError:
Greg Ward1b9c6f72000-02-08 02:39:44 +000074 break
75 i = i + 1
Greg Ward1027e3f2000-03-31 16:53:42 +000076 except RegError:
Greg Ward1b9c6f72000-02-08 02:39:44 +000077 pass
78 L.sort()
79 L.reverse()
80 return L
81
Greg Ward62e33932000-02-10 02:52:42 +000082# get_devstudio_versions ()
83
84
85def get_msvc_paths (path, version='6.0', platform='x86'):
Greg Ward69988092000-02-11 02:47:15 +000086 """Get a list of devstudio directories (include, lib or path). Return
87 a list of strings; will be empty list if unable to access the
88 registry or appropriate registry keys not found."""
89
Greg Ward7642f5c2000-03-31 16:47:40 +000090 if not _can_read_reg:
Greg Ward69988092000-02-11 02:47:15 +000091 return []
Greg Ward1b9c6f72000-02-08 02:39:44 +000092
93 L = []
Greg Ward62e33932000-02-10 02:52:42 +000094 if path=='lib':
95 path= 'Library'
Greg Ward1b9c6f72000-02-08 02:39:44 +000096 path = string.upper(path + ' Dirs')
Greg Ward62e33932000-02-10 02:52:42 +000097 K = ('Software\\Microsoft\\Devstudio\\%s\\' +
98 'Build System\\Components\\Platforms\\Win32 (%s)\\Directories') % \
99 (version,platform)
Greg Ward1027e3f2000-03-31 16:53:42 +0000100 for base in (HKEY_CLASSES_ROOT,
101 HKEY_LOCAL_MACHINE,
102 HKEY_CURRENT_USER,
103 HKEY_USERS):
Greg Ward1b9c6f72000-02-08 02:39:44 +0000104 try:
Greg Ward1027e3f2000-03-31 16:53:42 +0000105 k = RegOpenKeyEx(base,K)
Greg Ward1b9c6f72000-02-08 02:39:44 +0000106 i = 0
107 while 1:
108 try:
Greg Ward1027e3f2000-03-31 16:53:42 +0000109 (p,v,t) = RegEnumValue(k,i)
Greg Ward62e33932000-02-10 02:52:42 +0000110 if string.upper(p) == path:
Greg Ward1b9c6f72000-02-08 02:39:44 +0000111 V = string.split(v,';')
112 for v in V:
Greg Ward62e33932000-02-10 02:52:42 +0000113 if v == '' or v in L: continue
Greg Ward1b9c6f72000-02-08 02:39:44 +0000114 L.append(v)
115 break
116 i = i + 1
Greg Ward1027e3f2000-03-31 16:53:42 +0000117 except RegError:
Greg Ward1b9c6f72000-02-08 02:39:44 +0000118 break
Greg Ward1027e3f2000-03-31 16:53:42 +0000119 except RegError:
Greg Ward1b9c6f72000-02-08 02:39:44 +0000120 pass
121 return L
122
Greg Ward62e33932000-02-10 02:52:42 +0000123# get_msvc_paths()
124
125
Greg Ward69988092000-02-11 02:47:15 +0000126def find_exe (exe, version_number):
127 """Try to find an MSVC executable program 'exe' (from version
128 'version_number' of MSVC) in several places: first, one of the MSVC
129 program search paths from the registry; next, the directories in the
130 PATH environment variable. If any of those work, return an absolute
131 path that is known to exist. If none of them work, just return the
132 original program name, 'exe'."""
Greg Ward1b9c6f72000-02-08 02:39:44 +0000133
Greg Ward69988092000-02-11 02:47:15 +0000134 for p in get_msvc_paths ('path', version_number):
135 fn = os.path.join (os.path.abspath(p), exe)
136 if os.path.isfile(fn):
137 return fn
138
139 # didn't find it; try existing path
140 for p in string.split (os.environ['Path'],';'):
141 fn = os.path.join(os.path.abspath(p),exe)
142 if os.path.isfile(fn):
143 return fn
144
145 return exe # last desperate hope
Greg Ward1b9c6f72000-02-08 02:39:44 +0000146
Greg Ward62e33932000-02-10 02:52:42 +0000147
Greg Ward5de8cee2000-02-11 02:52:39 +0000148def set_path_env_var (name, version_number):
149 """Set environment variable 'name' to an MSVC path type value obtained
150 from 'get_msvc_paths()'. This is equivalent to a SET command prior
151 to execution of spawned commands."""
Greg Ward69988092000-02-11 02:47:15 +0000152
Greg Ward5de8cee2000-02-11 02:52:39 +0000153 p = get_msvc_paths (name, version_number)
Greg Ward62e33932000-02-10 02:52:42 +0000154 if p:
Greg Ward5de8cee2000-02-11 02:52:39 +0000155 os.environ[name] = string.join (p,';')
Greg Ward62e33932000-02-10 02:52:42 +0000156
Greg Warddbd12761999-08-29 18:15:07 +0000157
Greg Ward3d50b901999-09-08 02:36:01 +0000158class MSVCCompiler (CCompiler) :
159 """Concrete class that implements an interface to Microsoft Visual C++,
160 as defined by the CCompiler abstract class."""
Greg Warddbd12761999-08-29 18:15:07 +0000161
Greg Warddf178f91999-09-29 12:29:10 +0000162 compiler_type = 'msvc'
163
Greg Ward32c4a8a2000-03-06 03:40:29 +0000164 # Private class data (need to distinguish C from C++ source for compiler)
165 _c_extensions = ['.c']
166 _cpp_extensions = ['.cc','.cpp']
167
168 # Needed for the filename generation methods provided by the
169 # base class, CCompiler.
170 src_extensions = _c_extensions + _cpp_extensions
171 obj_extension = '.obj'
172 static_lib_extension = '.lib'
173 shared_lib_extension = '.dll'
174 static_lib_format = shared_lib_format = '%s%s'
175 exe_extension = '.exe'
176
177
Greg Warddbd12761999-08-29 18:15:07 +0000178 def __init__ (self,
179 verbose=0,
Greg Wardc74138d1999-10-03 20:47:52 +0000180 dry_run=0,
181 force=0):
Greg Warddbd12761999-08-29 18:15:07 +0000182
Greg Wardc74138d1999-10-03 20:47:52 +0000183 CCompiler.__init__ (self, verbose, dry_run, force)
Greg Ward5de8cee2000-02-11 02:52:39 +0000184 versions = get_devstudio_versions ()
Greg Ward69988092000-02-11 02:47:15 +0000185
Greg Ward5de8cee2000-02-11 02:52:39 +0000186 if versions:
187 version = versions[0] # highest version
Greg Ward69988092000-02-11 02:47:15 +0000188
Greg Ward41b4dd62000-03-29 04:13:00 +0000189 self.cc = find_exe("cl.exe", version)
190 self.link = find_exe("link.exe", version)
191 self.lib = find_exe("lib.exe", version)
Greg Ward5de8cee2000-02-11 02:52:39 +0000192 set_path_env_var ('lib', version)
193 set_path_env_var ('include', version)
194 path=get_msvc_paths('path', version)
Greg Ward69988092000-02-11 02:47:15 +0000195 try:
196 for p in string.split(os.environ['path'],';'):
197 path.append(p)
198 except KeyError:
199 pass
200 os.environ['path'] = string.join(path,';')
201 else:
202 # devstudio not found in the registry
203 self.cc = "cl.exe"
204 self.link = "link.exe"
Greg Ward09fc5422000-03-10 01:49:26 +0000205 self.lib = "lib.exe"
Greg Ward69988092000-02-11 02:47:15 +0000206
Greg Warddbd12761999-08-29 18:15:07 +0000207 self.preprocess_options = None
Greg Ward69988092000-02-11 02:47:15 +0000208 self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3' ]
Greg Ward32c4a8a2000-03-06 03:40:29 +0000209 self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/Z7', '/D_DEBUG']
Greg Warddbd12761999-08-29 18:15:07 +0000210
Greg Ward1b9c6f72000-02-08 02:39:44 +0000211 self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO']
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000212 self.ldflags_shared_debug = [
213 '/DLL', '/nologo', '/INCREMENTAL:no', '/pdb:None', '/DEBUG'
214 ]
Greg Warddbd12761999-08-29 18:15:07 +0000215 self.ldflags_static = [ '/nologo']
216
Greg Warddbd12761999-08-29 18:15:07 +0000217
218 # -- Worker methods ------------------------------------------------
Greg Warddbd12761999-08-29 18:15:07 +0000219
Greg Warddbd12761999-08-29 18:15:07 +0000220 def compile (self,
221 sources,
Greg Warddf178f91999-09-29 12:29:10 +0000222 output_dir=None,
Greg Warddbd12761999-08-29 18:15:07 +0000223 macros=None,
Greg Ward0bdd90a1999-12-12 17:19:58 +0000224 include_dirs=None,
Greg Ward386b8442000-02-09 02:18:39 +0000225 debug=0,
Greg Warddf178f91999-09-29 12:29:10 +0000226 extra_preargs=None,
227 extra_postargs=None):
Greg Warddbd12761999-08-29 18:15:07 +0000228
Greg Ward32c4a8a2000-03-06 03:40:29 +0000229 (output_dir, macros, include_dirs) = \
230 self._fix_compile_args (output_dir, macros, include_dirs)
231 (objects, skip_sources) = self._prep_compile (sources, output_dir)
Greg Warddbd12761999-08-29 18:15:07 +0000232
Greg Ward32c4a8a2000-03-06 03:40:29 +0000233 if extra_postargs is None:
234 extra_postargs = []
Greg Warddbd12761999-08-29 18:15:07 +0000235
Greg Ward32c4a8a2000-03-06 03:40:29 +0000236 pp_opts = gen_preprocess_options (macros, include_dirs)
237 compile_opts = extra_preargs or []
238 compile_opts.append ('/c')
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000239 if debug:
Greg Ward32c4a8a2000-03-06 03:40:29 +0000240 compile_opts.extend (self.compile_options_debug)
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000241 else:
Greg Ward32c4a8a2000-03-06 03:40:29 +0000242 compile_opts.extend (self.compile_options)
Greg Warddbd12761999-08-29 18:15:07 +0000243
Greg Ward32c4a8a2000-03-06 03:40:29 +0000244 for i in range (len (sources)):
245 src = sources[i] ; obj = objects[i]
246 ext = (os.path.splitext (src))[1]
Greg Warddbd12761999-08-29 18:15:07 +0000247
Greg Ward32c4a8a2000-03-06 03:40:29 +0000248 if skip_sources[src]:
249 self.announce ("skipping %s (%s up-to-date)" % (src, obj))
250 else:
251 if ext in self._c_extensions:
252 input_opt = "/Tc" + src
253 elif ext in self._cpp_extensions:
254 input_opt = "/Tp" + src
Greg Warddbd12761999-08-29 18:15:07 +0000255
Greg Ward32c4a8a2000-03-06 03:40:29 +0000256 output_opt = "/Fo" + obj
Greg Warddbd12761999-08-29 18:15:07 +0000257
Greg Ward32c4a8a2000-03-06 03:40:29 +0000258 self.mkpath (os.path.dirname (obj))
259 self.spawn ([self.cc] + compile_opts + pp_opts +
260 [input_opt, output_opt] +
261 extra_postargs)
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000262
Greg Ward32c4a8a2000-03-06 03:40:29 +0000263 return objects
Greg Warddbd12761999-08-29 18:15:07 +0000264
Greg Ward32c4a8a2000-03-06 03:40:29 +0000265 # compile ()
Greg Ward3d50b901999-09-08 02:36:01 +0000266
267
Greg Ward09fc5422000-03-10 01:49:26 +0000268 def create_static_lib (self,
269 objects,
270 output_libname,
271 output_dir=None,
272 debug=0,
273 extra_preargs=None,
274 extra_postargs=None):
Greg Warddbd12761999-08-29 18:15:07 +0000275
Greg Ward2f557a22000-03-26 21:42:28 +0000276 (objects, output_dir) = self._fix_object_args (objects, output_dir)
Greg Ward32c4a8a2000-03-06 03:40:29 +0000277 output_filename = \
278 self.library_filename (output_libname, output_dir=output_dir)
Greg Warddbd12761999-08-29 18:15:07 +0000279
Greg Ward32c4a8a2000-03-06 03:40:29 +0000280 if self._need_link (objects, output_filename):
Greg Ward09fc5422000-03-10 01:49:26 +0000281 lib_args = objects + ['/OUT:' + output_filename]
Greg Ward32c4a8a2000-03-06 03:40:29 +0000282 if debug:
283 pass # XXX what goes here?
284 if extra_preargs:
Greg Ward09fc5422000-03-10 01:49:26 +0000285 lib_args[:0] = extra_preargs
Greg Ward32c4a8a2000-03-06 03:40:29 +0000286 if extra_postargs:
Greg Ward09fc5422000-03-10 01:49:26 +0000287 lib_args.extend (extra_postargs)
Greg Ward32c4a8a2000-03-06 03:40:29 +0000288 self.spawn ([self.link] + ld_args)
289 else:
290 self.announce ("skipping %s (up-to-date)" % output_filename)
Greg Warddbd12761999-08-29 18:15:07 +0000291
Greg Ward09fc5422000-03-10 01:49:26 +0000292 # create_static_lib ()
Greg Warddbd12761999-08-29 18:15:07 +0000293
294
295 def link_shared_lib (self,
296 objects,
297 output_libname,
Greg Warddf178f91999-09-29 12:29:10 +0000298 output_dir=None,
Greg Warddbd12761999-08-29 18:15:07 +0000299 libraries=None,
300 library_dirs=None,
Greg Ward2f557a22000-03-26 21:42:28 +0000301 runtime_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 Warddf178f91999-09-29 12:29:10 +0000306 self.link_shared_object (objects,
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000307 self.shared_library_name(output_libname),
308 output_dir=output_dir,
309 libraries=libraries,
310 library_dirs=library_dirs,
311 debug=debug,
312 extra_preargs=extra_preargs,
313 extra_postargs=extra_postargs)
314
Greg Warddbd12761999-08-29 18:15:07 +0000315
316 def link_shared_object (self,
317 objects,
318 output_filename,
Greg Warddf178f91999-09-29 12:29:10 +0000319 output_dir=None,
Greg Warddbd12761999-08-29 18:15:07 +0000320 libraries=None,
321 library_dirs=None,
Greg Ward2f557a22000-03-26 21:42:28 +0000322 runtime_library_dirs=None,
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000323 debug=0,
Greg Warddf178f91999-09-29 12:29:10 +0000324 extra_preargs=None,
325 extra_postargs=None):
Greg Ward32c4a8a2000-03-06 03:40:29 +0000326
Greg Ward2f557a22000-03-26 21:42:28 +0000327 (objects, output_dir) = self._fix_object_args (objects, output_dir)
328 (libraries, library_dirs, runtime_library_dirs) = \
329 self._fix_lib_args (libraries, library_dirs, runtime_library_dirs)
330
331 if self.runtime_library_dirs:
332 self.warn ("I don't know what to do with 'runtime_library_dirs': "
333 + str (runtime_library_dirs))
Greg Warddbd12761999-08-29 18:15:07 +0000334
Greg Wardd03f88a2000-03-18 15:19:51 +0000335 lib_opts = gen_lib_options (self,
Greg Ward2f557a22000-03-26 21:42:28 +0000336 library_dirs, runtime_library_dirs,
Greg Wardd03f88a2000-03-18 15:19:51 +0000337 libraries)
Greg Ward32c4a8a2000-03-06 03:40:29 +0000338 if type (output_dir) not in (StringType, NoneType):
339 raise TypeError, "'output_dir' must be a string or None"
340 if output_dir is not None:
341 output_filename = os.path.join (output_dir, output_filename)
Greg Warddbd12761999-08-29 18:15:07 +0000342
Greg Ward32c4a8a2000-03-06 03:40:29 +0000343 if self._need_link (objects, output_filename):
344
345 if debug:
346 ldflags = self.ldflags_shared_debug
Greg Ward32c4a8a2000-03-06 03:40:29 +0000347 else:
348 ldflags = self.ldflags_shared
349
350 ld_args = ldflags + lib_opts + \
351 objects + ['/OUT:' + output_filename]
352
353 if extra_preargs:
354 ld_args[:0] = extra_preargs
355 if extra_postargs:
356 ld_args.extend (extra_postargs)
357
358 self.mkpath (os.path.dirname (output_filename))
359 self.spawn ([self.link] + ld_args)
360
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000361 else:
Greg Ward32c4a8a2000-03-06 03:40:29 +0000362 self.announce ("skipping %s (up-to-date)" % output_filename)
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000363
Greg Ward32c4a8a2000-03-06 03:40:29 +0000364 # link_shared_object ()
365
Greg Ward4ba9b2e2000-02-10 02:15:52 +0000366
Greg Ward32c4a8a2000-03-06 03:40:29 +0000367 # -- Miscellaneous methods -----------------------------------------
368 # These are all used by the 'gen_lib_options() function, in
369 # ccompiler.py.
Greg Wardc74138d1999-10-03 20:47:52 +0000370
371 def library_dir_option (self, dir):
372 return "/LIBPATH:" + dir
373
Greg Wardd03f88a2000-03-18 15:19:51 +0000374 def runtime_library_dir_option (self, dir):
375 raise DistutilsPlatformError, \
376 "don't know how to set runtime library search path for MSVC++"
377
Greg Wardc74138d1999-10-03 20:47:52 +0000378 def library_option (self, lib):
379 return self.library_filename (lib)
380
381
382 def find_library_file (self, dirs, lib):
383
384 for dir in dirs:
385 libfile = os.path.join (dir, self.library_filename (lib))
386 if os.path.exists (libfile):
387 return libfile
388
389 else:
390 # Oops, didn't find it in *any* of 'dirs'
391 return None
392
393 # find_library_file ()
394
Greg Warddbd12761999-08-29 18:15:07 +0000395# class MSVCCompiler