blob: cf4be0dc43167c5f8955ee537a110a8b65ade671 [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 Ward1b9c6f72000-02-08 02:39:44 +000018def _devstudio_versions():
19 "Get a list of devstudio versions"
20 try:
21 import win32api
22 import win32con
23 except ImportError:
24 return None
25
26 K = 'Software\\Microsoft\\Devstudio'
27 L = []
28 for base in (win32con.HKEY_CLASSES_ROOT,win32con.HKEY_LOCAL_MACHINE,win32con.HKEY_CURRENT_USER,win32con.HKEY_USERS):
29 try:
30 k = win32api.RegOpenKeyEx(base,K)
31 i = 0
32 while 1:
33 try:
34 p = win32api.RegEnumKey(k,i)
35 if p[0] in '123456789' and p not in L:
36 L.append(p)
37 except win32api.error:
38 break
39 i = i + 1
40 except win32api.error:
41 pass
42 L.sort()
43 L.reverse()
44 return L
45
46def _msvc_get_paths(path, vNum='6.0', platform='x86'):
47 "Get a devstudio path (include, lib or path)"
48 try:
49 import win32api
50 import win32con
51 except ImportError:
52 return None
53
54 L = []
55 if path=='lib': path= 'Library'
56 path = string.upper(path + ' Dirs')
57 K = 'Software\\Microsoft\\Devstudio\\%s\\Build System\\Components\\Platforms\\Win32 (%s)\\Directories' \
58 % (vNum,platform)
59 for base in (win32con.HKEY_CLASSES_ROOT,win32con.HKEY_LOCAL_MACHINE,win32con.HKEY_CURRENT_USER,win32con.HKEY_USERS):
60 try:
61 k = win32api.RegOpenKeyEx(base,K)
62 i = 0
63 while 1:
64 try:
65 (p,v,t) = win32api.RegEnumValue(k,i)
66 if string.upper(p)==path:
67 V = string.split(v,';')
68 for v in V:
69 if v=='' or v in L: continue
70 L.append(v)
71 break
72 i = i + 1
73 except win32api.error:
74 break
75 except win32api.error:
76 pass
77 return L
78
79def _find_exe(exe):
80 for v in _devstudio_versions():
81 for p in _msvc_get_paths('path',v):
82 fn=os.path.join(os.path.abspath(p),exe)
83 if os.path.isfile(fn): return fn
84
85 #didn't find it; try existing path
86 try:
87 for p in string.split(os.environ['Path'],';'):
88 fn=os.path.join(os.path.abspath(p),exe)
89 if os.path.isfile(fn): return fn
90 except:
91 pass
92 return exe #last desperate hope
93
94def _find_SET(n):
95 for v in _devstudio_versions():
96 p=_msvc_get_paths(n,v)
97 if p!=[]: return p
98 return []
99
100def _do_SET(n):
101 p=_find_SET(n)
102 if p!=[]: os.environ[n]=string.join(p,';')
Greg Warddbd12761999-08-29 18:15:07 +0000103
Greg Ward3d50b901999-09-08 02:36:01 +0000104class MSVCCompiler (CCompiler) :
105 """Concrete class that implements an interface to Microsoft Visual C++,
106 as defined by the CCompiler abstract class."""
Greg Warddbd12761999-08-29 18:15:07 +0000107
Greg Warddf178f91999-09-29 12:29:10 +0000108 compiler_type = 'msvc'
109
Greg Warddbd12761999-08-29 18:15:07 +0000110 def __init__ (self,
111 verbose=0,
Greg Wardc74138d1999-10-03 20:47:52 +0000112 dry_run=0,
113 force=0):
Greg Warddbd12761999-08-29 18:15:07 +0000114
Greg Wardc74138d1999-10-03 20:47:52 +0000115 CCompiler.__init__ (self, verbose, dry_run, force)
Greg Warddbd12761999-08-29 18:15:07 +0000116
Greg Warddbd12761999-08-29 18:15:07 +0000117 # XXX This is a nasty dependency to add on something otherwise
Greg Ward3d50b901999-09-08 02:36:01 +0000118 # pretty clean. move it to build_ext under an nt specific part.
119 # shared libraries need to link against python15.lib
Greg Warddbd12761999-08-29 18:15:07 +0000120 self.add_library ( "python" + sys.version[0] + sys.version[2] )
121 self.add_library_dir( os.path.join( sys.exec_prefix, 'libs' ) )
122
Greg Ward1b9c6f72000-02-08 02:39:44 +0000123 self.cc = _find_exe("cl.exe")
124 self.link = _find_exe("link.exe")
125 _do_SET('lib')
126 _do_SET('include')
127 path=_find_SET('path')
128 try:
129 for p in string.split(os.environ['path'],';'):
130 path.append(p)
131 except KeyError:
132 pass
133 os.environ['path'] = string.join(path,';')
Greg Warddbd12761999-08-29 18:15:07 +0000134 self.preprocess_options = None
Greg Ward01f52152000-01-17 21:57:17 +0000135 self.compile_options = [ '/nologo', '/Ox', '/MD' ]
Greg Warddbd12761999-08-29 18:15:07 +0000136
Greg Ward1b9c6f72000-02-08 02:39:44 +0000137 self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO']
Greg Warddbd12761999-08-29 18:15:07 +0000138 self.ldflags_static = [ '/nologo']
139
Greg Warddbd12761999-08-29 18:15:07 +0000140
141 # -- Worker methods ------------------------------------------------
142 # (must be implemented by subclasses)
143
144 _c_extensions = [ '.c' ]
Greg Ward3d50b901999-09-08 02:36:01 +0000145 _cpp_extensions = [ '.cc', '.cpp' ]
Greg Warddbd12761999-08-29 18:15:07 +0000146
147 _obj_ext = '.obj'
Greg Ward3d50b901999-09-08 02:36:01 +0000148 _exe_ext = '.exe'
Greg Warddbd12761999-08-29 18:15:07 +0000149 _shared_lib_ext = '.dll'
150 _static_lib_ext = '.lib'
Greg Warddf178f91999-09-29 12:29:10 +0000151
152 # XXX the 'output_dir' parameter is ignored by the methods in this
153 # class! I just put it in to be consistent with CCompiler and
154 # UnixCCompiler, but someone who actually knows Visual C++ will
155 # have to make it work...
Greg Warddbd12761999-08-29 18:15:07 +0000156
157 def compile (self,
158 sources,
Greg Warddf178f91999-09-29 12:29:10 +0000159 output_dir=None,
Greg Warddbd12761999-08-29 18:15:07 +0000160 macros=None,
Greg Ward0bdd90a1999-12-12 17:19:58 +0000161 include_dirs=None,
Greg Ward386b8442000-02-09 02:18:39 +0000162 debug=0,
Greg Warddf178f91999-09-29 12:29:10 +0000163 extra_preargs=None,
164 extra_postargs=None):
Greg Warddbd12761999-08-29 18:15:07 +0000165
166 if macros is None:
167 macros = []
Greg Ward0bdd90a1999-12-12 17:19:58 +0000168 if include_dirs is None:
169 include_dirs = []
Greg Warddbd12761999-08-29 18:15:07 +0000170
171 objectFiles = []
172
Greg Ward0bdd90a1999-12-12 17:19:58 +0000173 base_pp_opts = \
174 gen_preprocess_options (self.macros + macros,
175 self.include_dirs + include_dirs)
Greg Warddbd12761999-08-29 18:15:07 +0000176
177 base_pp_opts.append('/c')
178
179 for srcFile in sources:
180 base,ext = os.path.splitext(srcFile)
181 objFile = base + ".obj"
182
183 if ext in self._c_extensions:
184 fileOpt = "/Tc"
185 elif ext in self._cpp_extensions:
186 fileOpt = "/Tp"
187
188 inputOpt = fileOpt + srcFile
189 outputOpt = "/Fo" + objFile
190
Greg Warddf178f91999-09-29 12:29:10 +0000191 cc_args = self.compile_options + \
192 base_pp_opts + \
193 [outputOpt, inputOpt]
Greg Ward386b8442000-02-09 02:18:39 +0000194 if debug:
195 pass # XXX what goes here?
Greg Warddf178f91999-09-29 12:29:10 +0000196 if extra_preargs:
197 cc_args[:0] = extra_preargs
198 if extra_postargs:
199 cc_args.extend (extra_postargs)
Greg Warddbd12761999-08-29 18:15:07 +0000200
Greg Warddf178f91999-09-29 12:29:10 +0000201 self.spawn ([self.cc] + cc_args)
Greg Warddbd12761999-08-29 18:15:07 +0000202 objectFiles.append( objFile )
Greg Warddbd12761999-08-29 18:15:07 +0000203 return objectFiles
Greg Ward3d50b901999-09-08 02:36:01 +0000204
205
Greg Ward386b8442000-02-09 02:18:39 +0000206 # XXX the signature of this method is different from CCompiler and
207 # UnixCCompiler -- but those extra parameters (libraries, library_dirs)
208 # are actually used. So: are they really *needed*, or can they be
209 # ditched? If needed, the CCompiler API will have to change...
Greg Warddbd12761999-08-29 18:15:07 +0000210 def link_static_lib (self,
211 objects,
212 output_libname,
Greg Warddf178f91999-09-29 12:29:10 +0000213 output_dir=None,
Greg Warddbd12761999-08-29 18:15:07 +0000214 libraries=None,
Greg Warddf178f91999-09-29 12:29:10 +0000215 library_dirs=None,
Greg Ward386b8442000-02-09 02:18:39 +0000216 debug=0,
Greg Warddf178f91999-09-29 12:29:10 +0000217 extra_preargs=None,
218 extra_postargs=None):
Greg Warddbd12761999-08-29 18:15:07 +0000219
Greg Warddbd12761999-08-29 18:15:07 +0000220 if libraries is None:
221 libraries = []
222 if library_dirs is None:
223 library_dirs = []
Greg Warddbd12761999-08-29 18:15:07 +0000224
Greg Ward3d50b901999-09-08 02:36:01 +0000225 lib_opts = gen_lib_options (self.libraries + libraries,
226 self.library_dirs + library_dirs,
227 "%s.lib", "/LIBPATH:%s")
Greg Warddbd12761999-08-29 18:15:07 +0000228
Greg Warddbd12761999-08-29 18:15:07 +0000229 ld_args = self.ldflags_static + lib_opts + \
230 objects + ['/OUT:' + output_filename]
Greg Ward386b8442000-02-09 02:18:39 +0000231 if debug:
232 pass # XXX what goes here?
Greg Warddf178f91999-09-29 12:29:10 +0000233 if extra_preargs:
234 ld_args[:0] = extra_preargs
235 if extra_postargs:
236 ld_args.extend (extra_postargs)
Greg Warddbd12761999-08-29 18:15:07 +0000237
238 self.spawn ( [ self.link ] + ld_args )
239
240
241 def link_shared_lib (self,
242 objects,
243 output_libname,
Greg Warddf178f91999-09-29 12:29:10 +0000244 output_dir=None,
Greg Warddbd12761999-08-29 18:15:07 +0000245 libraries=None,
246 library_dirs=None,
Greg Ward386b8442000-02-09 02:18:39 +0000247 debug=0,
Greg Warddf178f91999-09-29 12:29:10 +0000248 extra_preargs=None,
249 extra_postargs=None):
250
Greg Warddbd12761999-08-29 18:15:07 +0000251 # XXX should we sanity check the library name? (eg. no
252 # slashes)
Greg Warddf178f91999-09-29 12:29:10 +0000253 self.link_shared_object (objects,
254 self.shared_library_name(output_libname))
Greg Warddbd12761999-08-29 18:15:07 +0000255
256 def link_shared_object (self,
257 objects,
258 output_filename,
Greg Warddf178f91999-09-29 12:29:10 +0000259 output_dir=None,
Greg Warddbd12761999-08-29 18:15:07 +0000260 libraries=None,
261 library_dirs=None,
Greg Warddf178f91999-09-29 12:29:10 +0000262 extra_preargs=None,
263 extra_postargs=None):
Greg Warddbd12761999-08-29 18:15:07 +0000264 """Link a bunch of stuff together to create a shared object
265 file. Much like 'link_shared_lib()', except the output
266 filename is explicitly supplied as 'output_filename'."""
267 if libraries is None:
268 libraries = []
269 if library_dirs is None:
270 library_dirs = []
Greg Warddbd12761999-08-29 18:15:07 +0000271
Greg Wardc74138d1999-10-03 20:47:52 +0000272 lib_opts = gen_lib_options (self,
273 self.library_dirs + library_dirs,
274 self.libraries + libraries)
Greg Warddbd12761999-08-29 18:15:07 +0000275
Greg Warddbd12761999-08-29 18:15:07 +0000276 ld_args = self.ldflags_shared + lib_opts + \
277 objects + ['/OUT:' + output_filename]
Greg Ward386b8442000-02-09 02:18:39 +0000278 if debug:
279 pass # XXX what goes here?
Greg Warddf178f91999-09-29 12:29:10 +0000280 if extra_preargs:
281 ld_args[:0] = extra_preargs
282 if extra_postargs:
283 ld_args.extend (extra_postargs)
Greg Warddbd12761999-08-29 18:15:07 +0000284
285 self.spawn ( [ self.link ] + ld_args )
286
287
288 # -- Filename mangling methods -------------------------------------
289
290 def _change_extensions( self, filenames, newExtension ):
291 object_filenames = []
292
293 for srcFile in filenames:
294 base,ext = os.path.splitext( srcFile )
295 # XXX should we strip off any existing path?
296 object_filenames.append( base + newExtension )
297
298 return object_filenames
299
300 def object_filenames (self, source_filenames):
301 """Return the list of object filenames corresponding to each
302 specified source filename."""
303 return self._change_extensions( source_filenames, self._obj_ext )
304
305 def shared_object_filename (self, source_filename):
306 """Return the shared object filename corresponding to a
307 specified source filename."""
308 return self._change_extensions( source_filenames, self._shared_lib_ext )
309
310 def library_filename (self, libname):
311 """Return the static library filename corresponding to the
312 specified library name."""
Greg Wardc8a95c82000-01-17 18:00:04 +0000313 return "%s%s" %( libname, self._static_lib_ext )
Greg Warddbd12761999-08-29 18:15:07 +0000314
315 def shared_library_filename (self, libname):
316 """Return the shared library filename corresponding to the
317 specified library name."""
Greg Wardc8a95c82000-01-17 18:00:04 +0000318 return "%s%s" %( libname, self._shared_lib_ext )
Greg Warddbd12761999-08-29 18:15:07 +0000319
Greg Wardc74138d1999-10-03 20:47:52 +0000320
321 def library_dir_option (self, dir):
322 return "/LIBPATH:" + dir
323
324 def library_option (self, lib):
325 return self.library_filename (lib)
326
327
328 def find_library_file (self, dirs, lib):
329
330 for dir in dirs:
331 libfile = os.path.join (dir, self.library_filename (lib))
332 if os.path.exists (libfile):
333 return libfile
334
335 else:
336 # Oops, didn't find it in *any* of 'dirs'
337 return None
338
339 # find_library_file ()
340
Greg Warddbd12761999-08-29 18:15:07 +0000341# class MSVCCompiler