0001 """distutils.bcppcompiler 0002 0003 Contains BorlandCCompiler, an implementation of the abstract CCompiler class 0004 for the Borland C++ compiler. 0005 """ 0006 0007 # This implementation by Lyle Johnson, based on the original msvccompiler.py 0008 # module and using the directions originally published by Gordon Williams. 0009 0010 # XXX looks like there's a LOT of overlap between these two classes: 0011 # someone should sit down and factor out the common code as 0012 # WindowsCCompiler! --GPW 0013 0014 # This module should be kept compatible with Python 1.5.2. 0015 0016 __revision__ = "$Id: bcppcompiler.py,v 1.17 2004/07/18 06:14:42 tim_one Exp $" 0017 0018 0019 import sys, os 0020 from distutils.errors import \ 0021 DistutilsExecError, DistutilsPlatformError, \ 0022 CompileError, LibError, LinkError, UnknownFileError 0023 from distutils.ccompiler import \ 0024 CCompiler, gen_preprocess_options, gen_lib_options 0025 from distutils.file_util import write_file 0026 from distutils.dep_util import newer 0027 from distutils import log 0028 0029 class BCPPCompiler(CCompiler) : 0030 """Concrete class that implements an interface to the Borland C/C++ 0031 compiler, as defined by the CCompiler abstract class. 0032 """ 0033 0034 compiler_type = 'bcpp' 0035 0036 # Just set this so CCompiler's constructor doesn't barf. We currently 0037 # don't use the 'set_executables()' bureaucracy provided by CCompiler, 0038 # as it really isn't necessary for this sort of single-compiler class. 0039 # Would be nice to have a consistent interface with UnixCCompiler, 0040 # though, so it's worth thinking about. 0041 executables = {} 0042 0043 # Private class data (need to distinguish C from C++ source for compiler) 0044 _c_extensions = ['.c'] 0045 _cpp_extensions = ['.cc', '.cpp', '.cxx'] 0046 0047 # Needed for the filename generation methods provided by the 0048 # base class, CCompiler. 0049 src_extensions = _c_extensions + _cpp_extensions 0050 obj_extension = '.obj' 0051 static_lib_extension = '.lib' 0052 shared_lib_extension = '.dll' 0053 static_lib_format = shared_lib_format = '%s%s' 0054 exe_extension = '.exe' 0055 0056 0057 def __init__ (self, 0058 verbose=0, 0059 dry_run=0, 0060 force=0): 0061 0062 CCompiler.__init__ (self, verbose, dry_run, force) 0063 0064 # These executables are assumed to all be in the path. 0065 # Borland doesn't seem to use any special registry settings to 0066 # indicate their installation locations. 0067 0068 self.cc = "bcc32.exe" 0069 self.linker = "ilink32.exe" 0070 self.lib = "tlib.exe" 0071 0072 self.preprocess_options = None 0073 self.compile_options = ['/tWM', '/O2', '/q', '/g0'] 0074 self.compile_options_debug = ['/tWM', '/Od', '/q', '/g0'] 0075 0076 self.ldflags_shared = ['/Tpd', '/Gn', '/q', '/x'] 0077 self.ldflags_shared_debug = ['/Tpd', '/Gn', '/q', '/x'] 0078 self.ldflags_static = [] 0079 self.ldflags_exe = ['/Gn', '/q', '/x'] 0080 self.ldflags_exe_debug = ['/Gn', '/q', '/x','/r'] 0081 0082 0083 # -- Worker methods ------------------------------------------------ 0084 0085 def compile(self, sources, 0086 output_dir=None, macros=None, include_dirs=None, debug=0, 0087 extra_preargs=None, extra_postargs=None, depends=None): 0088 0089 macros, objects, extra_postargs, pp_opts, build = \ 0090 self._setup_compile(output_dir, macros, include_dirs, sources, 0091 depends, extra_postargs) 0092 compile_opts = extra_preargs or [] 0093 compile_opts.append ('-c') 0094 if debug: 0095 compile_opts.extend (self.compile_options_debug) 0096 else: 0097 compile_opts.extend (self.compile_options) 0098 0099 for obj in objects: 0100 try: 0101 src, ext = build[obj] 0102 except KeyError: 0103 continue 0104 # XXX why do the normpath here? 0105 src = os.path.normpath(src) 0106 obj = os.path.normpath(obj) 0107 # XXX _setup_compile() did a mkpath() too but before the normpath. 0108 # Is it possible to skip the normpath? 0109 self.mkpath(os.path.dirname(obj)) 0110 0111 if ext == '.res': 0112 # This is already a binary file -- skip it. 0113 continue # the 'for' loop 0114 if ext == '.rc': 0115 # This needs to be compiled to a .res file -- do it now. 0116 try: 0117 self.spawn (["brcc32", "-fo", obj, src]) 0118 except DistutilsExecError, msg: 0119 raise CompileError, msg 0120 continue # the 'for' loop 0121 0122 # The next two are both for the real compiler. 0123 if ext in self._c_extensions: 0124 input_opt = "" 0125 elif ext in self._cpp_extensions: 0126 input_opt = "-P" 0127 else: 0128 # Unknown file type -- no extra options. The compiler 0129 # will probably fail, but let it just in case this is a 0130 # file the compiler recognizes even if we don't. 0131 input_opt = "" 0132 0133 output_opt = "-o" + obj 0134 0135 # Compiler command line syntax is: "bcc32 [options] file(s)". 0136 # Note that the source file names must appear at the end of 0137 # the command line. 0138 try: 0139 self.spawn ([self.cc] + compile_opts + pp_opts + 0140 [input_opt, output_opt] + 0141 extra_postargs + [src]) 0142 except DistutilsExecError, msg: 0143 raise CompileError, msg 0144 0145 return objects 0146 0147 # compile () 0148 0149 0150 def create_static_lib (self, 0151 objects, 0152 output_libname, 0153 output_dir=None, 0154 debug=0, 0155 target_lang=None): 0156 0157 (objects, output_dir) = self._fix_object_args (objects, output_dir) 0158 output_filename = \ 0159 self.library_filename (output_libname, output_dir=output_dir) 0160 0161 if self._need_link (objects, output_filename): 0162 lib_args = [output_filename, '/u'] + objects 0163 if debug: 0164 pass # XXX what goes here? 0165 try: 0166 self.spawn ([self.lib] + lib_args) 0167 except DistutilsExecError, msg: 0168 raise LibError, msg 0169 else: 0170 log.debug("skipping %s (up-to-date)", output_filename) 0171 0172 # create_static_lib () 0173 0174 0175 def link (self, 0176 target_desc, 0177 objects, 0178 output_filename, 0179 output_dir=None, 0180 libraries=None, 0181 library_dirs=None, 0182 runtime_library_dirs=None, 0183 export_symbols=None, 0184 debug=0, 0185 extra_preargs=None, 0186 extra_postargs=None, 0187 build_temp=None, 0188 target_lang=None): 0189 0190 # XXX this ignores 'build_temp'! should follow the lead of 0191 # msvccompiler.py 0192 0193 (objects, output_dir) = self._fix_object_args (objects, output_dir) 0194 (libraries, library_dirs, runtime_library_dirs) = \ 0195 self._fix_lib_args (libraries, library_dirs, runtime_library_dirs) 0196 0197 if runtime_library_dirs: 0198 log.warn("I don't know what to do with 'runtime_library_dirs': %s", 0199 str(runtime_library_dirs)) 0200 0201 if output_dir is not None: 0202 output_filename = os.path.join (output_dir, output_filename) 0203 0204 if self._need_link (objects, output_filename): 0205 0206 # Figure out linker args based on type of target. 0207 if target_desc == CCompiler.EXECUTABLE: 0208 startup_obj = 'c0w32' 0209 if debug: 0210 ld_args = self.ldflags_exe_debug[:] 0211 else: 0212 ld_args = self.ldflags_exe[:] 0213 else: 0214 startup_obj = 'c0d32' 0215 if debug: 0216 ld_args = self.ldflags_shared_debug[:] 0217 else: 0218 ld_args = self.ldflags_shared[:] 0219 0220 0221 # Create a temporary exports file for use by the linker 0222 if export_symbols is None: 0223 def_file = '' 0224 else: 0225 head, tail = os.path.split (output_filename) 0226 modname, ext = os.path.splitext (tail) 0227 temp_dir = os.path.dirname(objects[0]) # preserve tree structure 0228 def_file = os.path.join (temp_dir, '%s.def' % modname) 0229 contents = ['EXPORTS'] 0230 for sym in (export_symbols or []): 0231 contents.append(' %s=_%s' % (sym, sym)) 0232 self.execute(write_file, (def_file, contents), 0233 "writing %s" % def_file) 0234 0235 # Borland C++ has problems with '/' in paths 0236 objects2 = map(os.path.normpath, objects) 0237 # split objects in .obj and .res files 0238 # Borland C++ needs them at different positions in the command line 0239 objects = [startup_obj] 0240 resources = [] 0241 for file in objects2: 0242 (base, ext) = os.path.splitext(os.path.normcase(file)) 0243 if ext == '.res': 0244 resources.append(file) 0245 else: 0246 objects.append(file) 0247 0248 0249 for l in library_dirs: 0250 ld_args.append("/L%s" % os.path.normpath(l)) 0251 ld_args.append("/L.") # we sometimes use relative paths 0252 0253 # list of object files 0254 ld_args.extend(objects) 0255 0256 # XXX the command-line syntax for Borland C++ is a bit wonky; 0257 # certain filenames are jammed together in one big string, but 0258 # comma-delimited. This doesn't mesh too well with the 0259 # Unix-centric attitude (with a DOS/Windows quoting hack) of 0260 # 'spawn()', so constructing the argument list is a bit 0261 # awkward. Note that doing the obvious thing and jamming all 0262 # the filenames and commas into one argument would be wrong, 0263 # because 'spawn()' would quote any filenames with spaces in 0264 # them. Arghghh!. Apparently it works fine as coded... 0265 0266 # name of dll/exe file 0267 ld_args.extend([',',output_filename]) 0268 # no map file and start libraries 0269 ld_args.append(',,') 0270 0271 for lib in libraries: 0272 # see if we find it and if there is a bcpp specific lib 0273 # (xxx_bcpp.lib) 0274 libfile = self.find_library_file(library_dirs, lib, debug) 0275 if libfile is None: 0276 ld_args.append(lib) 0277 # probably a BCPP internal library -- don't warn 0278 else: 0279 # full name which prefers bcpp_xxx.lib over xxx.lib 0280 ld_args.append(libfile) 0281 0282 # some default libraries 0283 ld_args.append ('import32') 0284 ld_args.append ('cw32mt') 0285 0286 # def file for export symbols 0287 ld_args.extend([',',def_file]) 0288 # add resource files 0289 ld_args.append(',') 0290 ld_args.extend(resources) 0291 0292 0293 if extra_preargs: 0294 ld_args[:0] = extra_preargs 0295 if extra_postargs: 0296 ld_args.extend(extra_postargs) 0297 0298 self.mkpath (os.path.dirname (output_filename)) 0299 try: 0300 self.spawn ([self.linker] + ld_args) 0301 except DistutilsExecError, msg: 0302 raise LinkError, msg 0303 0304 else: 0305 log.debug("skipping %s (up-to-date)", output_filename) 0306 0307 # link () 0308 0309 # -- Miscellaneous methods ----------------------------------------- 0310 0311 0312 def find_library_file (self, dirs, lib, debug=0): 0313 # List of effective library names to try, in order of preference: 0314 # xxx_bcpp.lib is better than xxx.lib 0315 # and xxx_d.lib is better than xxx.lib if debug is set 0316 # 0317 # The "_bcpp" suffix is to handle a Python installation for people 0318 # with multiple compilers (primarily Distutils hackers, I suspect 0319 # ;-). The idea is they'd have one static library for each 0320 # compiler they care about, since (almost?) every Windows compiler 0321 # seems to have a different format for static libraries. 0322 if debug: 0323 dlib = (lib + "_d") 0324 try_names = (dlib + "_bcpp", lib + "_bcpp", dlib, lib) 0325 else: 0326 try_names = (lib + "_bcpp", lib) 0327 0328 for dir in dirs: 0329 for name in try_names: 0330 libfile = os.path.join(dir, self.library_filename(name)) 0331 if os.path.exists(libfile): 0332 return libfile 0333 else: 0334 # Oops, didn't find it in *any* of 'dirs' 0335 return None 0336 0337 # overwrite the one from CCompiler to support rc and res-files 0338 def object_filenames (self, 0339 source_filenames, 0340 strip_dir=0, 0341 output_dir=''): 0342 if output_dir is None: output_dir = '' 0343 obj_names = [] 0344 for src_name in source_filenames: 0345 # use normcase to make sure '.rc' is really '.rc' and not '.RC' 0346 (base, ext) = os.path.splitext (os.path.normcase(src_name)) 0347 if ext not in (self.src_extensions + ['.rc','.res']): 0348 raise UnknownFileError, \ 0349 "unknown file type '%s' (from '%s')" % \ 0350 (ext, src_name) 0351 if strip_dir: 0352 base = os.path.basename (base) 0353 if ext == '.res': 0354 # these can go unchanged 0355 obj_names.append (os.path.join (output_dir, base + ext)) 0356 elif ext == '.rc': 0357 # these need to be compiled to .res-files 0358 obj_names.append (os.path.join (output_dir, base + '.res')) 0359 else: 0360 obj_names.append (os.path.join (output_dir, 0361 base + self.obj_extension)) 0362 return obj_names 0363 0364 # object_filenames () 0365 0366 def preprocess (self, 0367 source, 0368 output_file=None, 0369 macros=None, 0370 include_dirs=None, 0371 extra_preargs=None, 0372 extra_postargs=None): 0373 0374 (_, macros, include_dirs) = \ 0375 self._fix_compile_args(None, macros, include_dirs) 0376 pp_opts = gen_preprocess_options(macros, include_dirs) 0377 pp_args = ['cpp32.exe'] + pp_opts 0378 if output_file is not None: 0379 pp_args.append('-o' + output_file) 0380 if extra_preargs: 0381 pp_args[:0] = extra_preargs 0382 if extra_postargs: 0383 pp_args.extend(extra_postargs) 0384 pp_args.append(source) 0385 0386 # We need to preprocess: either we're being forced to, or the 0387 # source file is newer than the target (or the target doesn't 0388 # exist). 0389 if self.force or output_file is None or newer(source, output_file): 0390 if output_file: 0391 self.mkpath(os.path.dirname(output_file)) 0392 try: 0393 self.spawn(pp_args) 0394 except DistutilsExecError, msg: 0395 print msg 0396 raise CompileError, msg 0397 0398 # preprocess() 0399
Generated by PyXR 0.9.4