1 """distutils.bcppcompiler
3 Contains BorlandCCompiler, an implementation of the abstract CCompiler class
4 for the Borland C++ compiler.
7 # This implementation by Lyle Johnson, based on the original msvccompiler.py
8 # module and using the directions originally published by Gordon Williams.
10 # XXX looks like there's a LOT of overlap between these two classes:
11 # someone should sit down and factor out the common code as
12 # WindowsCCompiler! --GPW
18 from distutils
.errors
import \
19 DistutilsExecError
, DistutilsPlatformError
, \
20 CompileError
, LibError
, LinkError
, UnknownFileError
21 from distutils
.ccompiler
import \
22 CCompiler
, gen_preprocess_options
, gen_lib_options
23 from distutils
.file_util
import write_file
24 from distutils
.dep_util
import newer
26 class BCPPCompiler(CCompiler
) :
27 """Concrete class that implements an interface to the Borland C/C++
28 compiler, as defined by the CCompiler abstract class.
31 compiler_type
= 'bcpp'
33 # Just set this so CCompiler's constructor doesn't barf. We currently
34 # don't use the 'set_executables()' bureaucracy provided by CCompiler,
35 # as it really isn't necessary for this sort of single-compiler class.
36 # Would be nice to have a consistent interface with UnixCCompiler,
37 # though, so it's worth thinking about.
40 # Private class data (need to distinguish C from C++ source for compiler)
41 _c_extensions
= ['.c']
42 _cpp_extensions
= ['.cc', '.cpp', '.cxx']
44 # Needed for the filename generation methods provided by the
45 # base class, CCompiler.
46 src_extensions
= _c_extensions
+ _cpp_extensions
47 obj_extension
= '.obj'
48 static_lib_extension
= '.lib'
49 shared_lib_extension
= '.dll'
50 static_lib_format
= shared_lib_format
= '%s%s'
51 exe_extension
= '.exe'
59 CCompiler
.__init
__ (self
, verbose
, dry_run
, force
)
61 # These executables are assumed to all be in the path.
62 # Borland doesn't seem to use any special registry settings to
63 # indicate their installation locations.
66 self
.linker
= "ilink32.exe"
69 self
.preprocess_options
= None
70 self
.compile_options
= ['/tWM', '/O2', '/q', '/g0']
71 self
.compile_options_debug
= ['/tWM', '/Od', '/q', '/g0']
73 self
.ldflags_shared
= ['/Tpd', '/Gn', '/q', '/x']
74 self
.ldflags_shared_debug
= ['/Tpd', '/Gn', '/q', '/x']
75 self
.ldflags_static
= []
76 self
.ldflags_exe
= ['/Gn', '/q', '/x']
77 self
.ldflags_exe_debug
= ['/Gn', '/q', '/x','/r']
80 # -- Worker methods ------------------------------------------------
91 (output_dir
, macros
, include_dirs
) = \
92 self
._fix
_compile
_args
(output_dir
, macros
, include_dirs
)
93 (objects
, skip_sources
) = self
._prep
_compile
(sources
, output_dir
)
95 if extra_postargs
is None:
98 pp_opts
= gen_preprocess_options (macros
, include_dirs
)
99 compile_opts
= extra_preargs
or []
100 compile_opts
.append ('-c')
102 compile_opts
.extend (self
.compile_options_debug
)
104 compile_opts
.extend (self
.compile_options
)
106 for i
in range (len (sources
)):
107 src
= sources
[i
] ; obj
= objects
[i
]
108 ext
= (os
.path
.splitext (src
))[1]
110 if skip_sources
[src
]:
111 self
.announce ("skipping %s (%s up-to-date)" % (src
, obj
))
113 src
= os
.path
.normpath(src
)
114 obj
= os
.path
.normpath(obj
)
115 self
.mkpath(os
.path
.dirname(obj
))
118 # This is already a binary file -- skip it.
119 continue # the 'for' loop
121 # This needs to be compiled to a .res file -- do it now.
123 self
.spawn (["brcc32", "-fo", obj
, src
])
124 except DistutilsExecError
, msg
:
125 raise CompileError
, msg
126 continue # the 'for' loop
128 # The next two are both for the real compiler.
129 if ext
in self
._c
_extensions
:
131 elif ext
in self
._cpp
_extensions
:
134 # Unknown file type -- no extra options. The compiler
135 # will probably fail, but let it just in case this is a
136 # file the compiler recognizes even if we don't.
139 output_opt
= "-o" + obj
141 # Compiler command line syntax is: "bcc32 [options] file(s)".
142 # Note that the source file names must appear at the end of
145 self
.spawn ([self
.cc
] + compile_opts
+ pp_opts
+
146 [input_opt
, output_opt
] +
147 extra_postargs
+ [src
])
148 except DistutilsExecError
, msg
:
149 raise CompileError
, msg
156 def create_static_lib (self
,
162 extra_postargs
=None):
164 (objects
, output_dir
) = self
._fix
_object
_args
(objects
, output_dir
)
166 self
.library_filename (output_libname
, output_dir
=output_dir
)
168 if self
._need
_link
(objects
, output_filename
):
169 lib_args
= [output_filename
, '/u'] + objects
171 pass # XXX what goes here?
173 lib_args
[:0] = extra_preargs
175 lib_args
.extend (extra_postargs
)
177 self
.spawn ([self
.lib
] + lib_args
)
178 except DistutilsExecError
, msg
:
181 self
.announce ("skipping %s (up-to-date)" % output_filename
)
183 # create_static_lib ()
193 runtime_library_dirs
=None,
200 # XXX this ignores 'build_temp'! should follow the lead of
203 (objects
, output_dir
) = self
._fix
_object
_args
(objects
, output_dir
)
204 (libraries
, library_dirs
, runtime_library_dirs
) = \
205 self
._fix
_lib
_args
(libraries
, library_dirs
, runtime_library_dirs
)
207 if runtime_library_dirs
:
208 self
.warn ("I don't know what to do with 'runtime_library_dirs': "
209 + str (runtime_library_dirs
))
211 if output_dir
is not None:
212 output_filename
= os
.path
.join (output_dir
, output_filename
)
214 if self
._need
_link
(objects
, output_filename
):
216 # Figure out linker args based on type of target.
217 if target_desc
== CCompiler
.EXECUTABLE
:
218 startup_obj
= 'c0w32'
220 ld_args
= self
.ldflags_exe_debug
[:]
222 ld_args
= self
.ldflags_exe
[:]
224 startup_obj
= 'c0d32'
226 ld_args
= self
.ldflags_shared_debug
[:]
228 ld_args
= self
.ldflags_shared
[:]
231 # Create a temporary exports file for use by the linker
232 if export_symbols
is None:
235 head
, tail
= os
.path
.split (output_filename
)
236 modname
, ext
= os
.path
.splitext (tail
)
237 temp_dir
= os
.path
.dirname(objects
[0]) # preserve tree structure
238 def_file
= os
.path
.join (temp_dir
, '%s.def' % modname
)
239 contents
= ['EXPORTS']
240 for sym
in (export_symbols
or []):
241 contents
.append(' %s=_%s' % (sym
, sym
))
242 self
.execute(write_file
, (def_file
, contents
),
243 "writing %s" % def_file
)
245 # Borland C++ has problems with '/' in paths
246 objects2
= map(os
.path
.normpath
, objects
)
247 # split objects in .obj and .res files
248 # Borland C++ needs them at different positions in the command line
249 objects
= [startup_obj
]
251 for file in objects2
:
252 (base
, ext
) = os
.path
.splitext(os
.path
.normcase(file))
254 resources
.append(file)
259 for l
in library_dirs
:
260 ld_args
.append("/L%s" % os
.path
.normpath(l
))
261 ld_args
.append("/L.") # we sometimes use relative paths
263 # list of object files
264 ld_args
.extend(objects
)
266 # XXX the command-line syntax for Borland C++ is a bit wonky;
267 # certain filenames are jammed together in one big string, but
268 # comma-delimited. This doesn't mesh too well with the
269 # Unix-centric attitude (with a DOS/Windows quoting hack) of
270 # 'spawn()', so constructing the argument list is a bit
271 # awkward. Note that doing the obvious thing and jamming all
272 # the filenames and commas into one argument would be wrong,
273 # because 'spawn()' would quote any filenames with spaces in
274 # them. Arghghh!. Apparently it works fine as coded...
276 # name of dll/exe file
277 ld_args
.extend([',',output_filename
])
278 # no map file and start libraries
281 for lib
in libraries
:
282 # see if we find it and if there is a bcpp specific lib
284 libfile
= self
.find_library_file(library_dirs
, lib
, debug
)
287 # probably a BCPP internal library -- don't warn
288 # self.warn('library %s not found.' % lib)
290 # full name which prefers bcpp_xxx.lib over xxx.lib
291 ld_args
.append(libfile
)
293 # some default libraries
294 ld_args
.append ('import32')
295 ld_args
.append ('cw32mt')
297 # def file for export symbols
298 ld_args
.extend([',',def_file
])
301 ld_args
.extend(resources
)
305 ld_args
[:0] = extra_preargs
307 ld_args
.extend(extra_postargs
)
309 self
.mkpath (os
.path
.dirname (output_filename
))
311 self
.spawn ([self
.linker
] + ld_args
)
312 except DistutilsExecError
, msg
:
316 self
.announce ("skipping %s (up-to-date)" % output_filename
)
320 # -- Miscellaneous methods -----------------------------------------
323 def find_library_file (self
, dirs
, lib
, debug
=0):
324 # List of effective library names to try, in order of preference:
325 # xxx_bcpp.lib is better than xxx.lib
326 # and xxx_d.lib is better than xxx.lib if debug is set
328 # The "_bcpp" suffix is to handle a Python installation for people
329 # with multiple compilers (primarily Distutils hackers, I suspect
330 # ;-). The idea is they'd have one static library for each
331 # compiler they care about, since (almost?) every Windows compiler
332 # seems to have a different format for static libraries.
335 try_names
= (dlib
+ "_bcpp", lib
+ "_bcpp", dlib
, lib
)
337 try_names
= (lib
+ "_bcpp", lib
)
340 for name
in try_names
:
341 libfile
= os
.path
.join(dir, self
.library_filename(name
))
342 if os
.path
.exists(libfile
):
345 # Oops, didn't find it in *any* of 'dirs'
348 # overwrite the one from CCompiler to support rc and res-files
349 def object_filenames (self
,
353 if output_dir
is None: output_dir
= ''
355 for src_name
in source_filenames
:
356 # use normcase to make sure '.rc' is really '.rc' and not '.RC'
357 (base
, ext
) = os
.path
.splitext (os
.path
.normcase(src_name
))
358 if ext
not in (self
.src_extensions
+ ['.rc','.res']):
359 raise UnknownFileError
, \
360 "unknown file type '%s' (from '%s')" % \
363 base
= os
.path
.basename (base
)
365 # these can go unchanged
366 obj_names
.append (os
.path
.join (output_dir
, base
+ ext
))
368 # these need to be compiled to .res-files
369 obj_names
.append (os
.path
.join (output_dir
, base
+ '.res'))
371 obj_names
.append (os
.path
.join (output_dir
,
372 base
+ self
.obj_extension
))
375 # object_filenames ()
377 def preprocess (self
,
383 extra_postargs
=None):
385 (_
, macros
, include_dirs
) = \
386 self
._fix
_compile
_args
(None, macros
, include_dirs
)
387 pp_opts
= gen_preprocess_options(macros
, include_dirs
)
388 pp_args
= ['cpp32.exe'] + pp_opts
389 if output_file
is not None:
390 pp_args
.append('-o' + output_file
)
392 pp_args
[:0] = extra_preargs
394 pp_args
.extend(extra_postargs
)
395 pp_args
.append(source
)
397 # We need to preprocess: either we're being forced to, or the
398 # source file is newer than the target (or the target doesn't
400 if self
.force
or output_file
is None or newer(source
, output_file
):
402 self
.mkpath(os
.path
.dirname(output_file
))
405 except DistutilsExecError
, msg
:
407 raise CompileError
, msg