]>
git.saurik.com Git - wxWidgets.git/blob - wxPython/distutils/bcppcompiler.py
   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 
  14 # This module should be kept compatible with Python 1.5.2. 
  20 from distutils
.errors 
import \
 
  21      DistutilsExecError
, DistutilsPlatformError
, \
 
  22      CompileError
, LibError
, LinkError
, UnknownFileError
 
  23 from distutils
.ccompiler 
import \
 
  24      CCompiler
, gen_preprocess_options
, gen_lib_options
 
  25 from distutils
.file_util 
import write_file
 
  26 from distutils
.dep_util 
import newer
 
  27 from distutils 
import log
 
  29 class BCPPCompiler(CCompiler
) : 
  30     """Concrete class that implements an interface to the Borland C/C++ 
  31     compiler, as defined by the CCompiler abstract class. 
  34     compiler_type 
= 'bcpp' 
  36     # Just set this so CCompiler's constructor doesn't barf.  We currently 
  37     # don't use the 'set_executables()' bureaucracy provided by CCompiler, 
  38     # as it really isn't necessary for this sort of single-compiler class. 
  39     # Would be nice to have a consistent interface with UnixCCompiler, 
  40     # though, so it's worth thinking about. 
  43     # Private class data (need to distinguish C from C++ source for compiler) 
  44     _c_extensions 
= ['.c'] 
  45     _cpp_extensions 
= ['.cc', '.cpp', '.cxx'] 
  47     # Needed for the filename generation methods provided by the 
  48     # base class, CCompiler. 
  49     src_extensions 
= _c_extensions 
+ _cpp_extensions
 
  50     obj_extension 
= '.obj' 
  51     static_lib_extension 
= '.lib' 
  52     shared_lib_extension 
= '.dll' 
  53     static_lib_format 
= shared_lib_format 
= '%s%s' 
  54     exe_extension 
= '.exe' 
  62         CCompiler
.__init
__ (self
, verbose
, dry_run
, force
) 
  64         # These executables are assumed to all be in the path. 
  65         # Borland doesn't seem to use any special registry settings to 
  66         # indicate their installation locations. 
  69         self
.linker 
= "ilink32.exe" 
  72         self
.preprocess_options 
= None 
  73         self
.compile_options 
= ['/tWM', '/O2', '/q', '/g0'] 
  74         self
.compile_options_debug 
= ['/tWM', '/Od', '/q', '/g0'] 
  76         self
.ldflags_shared 
= ['/Tpd', '/Gn', '/q', '/x'] 
  77         self
.ldflags_shared_debug 
= ['/Tpd', '/Gn', '/q', '/x'] 
  78         self
.ldflags_static 
= [] 
  79         self
.ldflags_exe 
= ['/Gn', '/q', '/x'] 
  80         self
.ldflags_exe_debug 
= ['/Gn', '/q', '/x','/r'] 
  83     # -- Worker methods ------------------------------------------------ 
  85     def compile(self
, sources
, 
  86                 output_dir
=None, macros
=None, include_dirs
=None, debug
=0, 
  87                 extra_preargs
=None, extra_postargs
=None, depends
=None): 
  89         macros
, objects
, extra_postargs
, pp_opts
, build 
= \
 
  90                 self
._setup
_compile
(output_dir
, macros
, include_dirs
, sources
, 
  91                                     depends
, extra_postargs
) 
  92         compile_opts 
= extra_preargs 
or [] 
  93         compile_opts
.append ('-c') 
  95             compile_opts
.extend (self
.compile_options_debug
) 
  97             compile_opts
.extend (self
.compile_options
) 
  99         for obj
, (src
, ext
) in build
.items(): 
 100             # XXX why do the normpath here? 
 101             src 
= os
.path
.normpath(src
) 
 102             obj 
= os
.path
.normpath(obj
) 
 103             # XXX _setup_compile() did a mkpath() too but before the normpath. 
 104             # Is it possible to skip the normpath? 
 105             self
.mkpath(os
.path
.dirname(obj
)) 
 108                 # This is already a binary file -- skip it. 
 109                 continue # the 'for' loop 
 111                 # This needs to be compiled to a .res file -- do it now. 
 113                     self
.spawn (["brcc32", "-fo", obj
, src
]) 
 114                 except DistutilsExecError
, msg
: 
 115                     raise CompileError
, msg
 
 116                 continue # the 'for' loop 
 118             # The next two are both for the real compiler. 
 119             if ext 
in self
._c
_extensions
: 
 121             elif ext 
in self
._cpp
_extensions
: 
 124                 # Unknown file type -- no extra options.  The compiler 
 125                 # will probably fail, but let it just in case this is a 
 126                 # file the compiler recognizes even if we don't. 
 129             output_opt 
= "-o" + obj
 
 131             # Compiler command line syntax is: "bcc32 [options] file(s)". 
 132             # Note that the source file names must appear at the end of 
 135                 self
.spawn ([self
.cc
] + compile_opts 
+ pp_opts 
+ 
 136                             [input_opt
, output_opt
] + 
 137                             extra_postargs 
+ [src
]) 
 138             except DistutilsExecError
, msg
: 
 139                 raise CompileError
, msg
 
 146     def create_static_lib (self
, 
 153         (objects
, output_dir
) = self
._fix
_object
_args 
(objects
, output_dir
) 
 155             self
.library_filename (output_libname
, output_dir
=output_dir
) 
 157         if self
._need
_link 
(objects
, output_filename
): 
 158             lib_args 
= [output_filename
, '/u'] + objects
 
 160                 pass                    # XXX what goes here? 
 162                 self
.spawn ([self
.lib
] + lib_args
) 
 163             except DistutilsExecError
, msg
: 
 166             log
.debug("skipping %s (up-to-date)", output_filename
) 
 168     # create_static_lib () 
 178               runtime_library_dirs
=None, 
 186         # XXX this ignores 'build_temp'!  should follow the lead of 
 189         (objects
, output_dir
) = self
._fix
_object
_args 
(objects
, output_dir
) 
 190         (libraries
, library_dirs
, runtime_library_dirs
) = \
 
 191             self
._fix
_lib
_args 
(libraries
, library_dirs
, runtime_library_dirs
) 
 193         if runtime_library_dirs
: 
 194             log
.warn("I don't know what to do with 'runtime_library_dirs': %s", 
 195                      str(runtime_library_dirs
)) 
 197         if output_dir 
is not None: 
 198             output_filename 
= os
.path
.join (output_dir
, output_filename
) 
 200         if self
._need
_link 
(objects
, output_filename
): 
 202             # Figure out linker args based on type of target. 
 203             if target_desc 
== CCompiler
.EXECUTABLE
: 
 204                 startup_obj 
= 'c0w32' 
 206                     ld_args 
= self
.ldflags_exe_debug
[:] 
 208                     ld_args 
= self
.ldflags_exe
[:] 
 210                 startup_obj 
= 'c0d32' 
 212                     ld_args 
= self
.ldflags_shared_debug
[:] 
 214                     ld_args 
= self
.ldflags_shared
[:] 
 217             # Create a temporary exports file for use by the linker 
 218             if export_symbols 
is None: 
 221                 head
, tail 
= os
.path
.split (output_filename
) 
 222                 modname
, ext 
= os
.path
.splitext (tail
) 
 223                 temp_dir 
= os
.path
.dirname(objects
[0]) # preserve tree structure 
 224                 def_file 
= os
.path
.join (temp_dir
, '%s.def' % modname
) 
 225                 contents 
= ['EXPORTS'] 
 226                 for sym 
in (export_symbols 
or []): 
 227                     contents
.append('  %s=_%s' % (sym
, sym
)) 
 228                 self
.execute(write_file
, (def_file
, contents
), 
 229                              "writing %s" % def_file
) 
 231             # Borland C++ has problems with '/' in paths 
 232             objects2 
= map(os
.path
.normpath
, objects
) 
 233             # split objects in .obj and .res files 
 234             # Borland C++ needs them at different positions in the command line 
 235             objects 
= [startup_obj
] 
 237             for file in objects2
: 
 238                 (base
, ext
) = os
.path
.splitext(os
.path
.normcase(file)) 
 240                     resources
.append(file) 
 245             for l 
in library_dirs
: 
 246                 ld_args
.append("/L%s" % os
.path
.normpath(l
)) 
 247             ld_args
.append("/L.") # we sometimes use relative paths 
 249             # list of object files 
 250             ld_args
.extend(objects
) 
 252             # XXX the command-line syntax for Borland C++ is a bit wonky; 
 253             # certain filenames are jammed together in one big string, but 
 254             # comma-delimited.  This doesn't mesh too well with the 
 255             # Unix-centric attitude (with a DOS/Windows quoting hack) of 
 256             # 'spawn()', so constructing the argument list is a bit 
 257             # awkward.  Note that doing the obvious thing and jamming all 
 258             # the filenames and commas into one argument would be wrong, 
 259             # because 'spawn()' would quote any filenames with spaces in 
 260             # them.  Arghghh!.  Apparently it works fine as coded... 
 262             # name of dll/exe file 
 263             ld_args
.extend([',',output_filename
]) 
 264             # no map file and start libraries 
 267             for lib 
in libraries
: 
 268                 # see if we find it and if there is a bcpp specific lib 
 270                 libfile 
= self
.find_library_file(library_dirs
, lib
, debug
) 
 273                     # probably a BCPP internal library -- don't warn 
 275                     # full name which prefers bcpp_xxx.lib over xxx.lib 
 276                     ld_args
.append(libfile
) 
 278             # some default libraries 
 279             ld_args
.append ('import32') 
 280             ld_args
.append ('cw32mt') 
 282             # def file for export symbols 
 283             ld_args
.extend([',',def_file
]) 
 286             ld_args
.extend(resources
) 
 290                 ld_args
[:0] = extra_preargs
 
 292                 ld_args
.extend(extra_postargs
) 
 294             self
.mkpath (os
.path
.dirname (output_filename
)) 
 296                 self
.spawn ([self
.linker
] + ld_args
) 
 297             except DistutilsExecError
, msg
: 
 301             log
.debug("skipping %s (up-to-date)", output_filename
) 
 305     # -- Miscellaneous methods ----------------------------------------- 
 308     def find_library_file (self
, dirs
, lib
, debug
=0): 
 309         # List of effective library names to try, in order of preference: 
 310         # xxx_bcpp.lib is better than xxx.lib 
 311         # and xxx_d.lib is better than xxx.lib if debug is set 
 313         # The "_bcpp" suffix is to handle a Python installation for people 
 314         # with multiple compilers (primarily Distutils hackers, I suspect 
 315         # ;-).  The idea is they'd have one static library for each 
 316         # compiler they care about, since (almost?) every Windows compiler 
 317         # seems to have a different format for static libraries. 
 320             try_names 
= (dlib 
+ "_bcpp", lib 
+ "_bcpp", dlib
, lib
) 
 322             try_names 
= (lib 
+ "_bcpp", lib
) 
 325             for name 
in try_names
: 
 326                 libfile 
= os
.path
.join(dir, self
.library_filename(name
)) 
 327                 if os
.path
.exists(libfile
): 
 330             # Oops, didn't find it in *any* of 'dirs' 
 333     # overwrite the one from CCompiler to support rc and res-files 
 334     def object_filenames (self
, 
 338         if output_dir 
is None: output_dir 
= '' 
 340         for src_name 
in source_filenames
: 
 341             # use normcase to make sure '.rc' is really '.rc' and not '.RC' 
 342             (base
, ext
) = os
.path
.splitext (os
.path
.normcase(src_name
)) 
 343             if ext 
not in (self
.src_extensions 
+ ['.rc','.res']): 
 344                 raise UnknownFileError
, \
 
 345                       "unknown file type '%s' (from '%s')" % \
 
 348                 base 
= os
.path
.basename (base
) 
 350                 # these can go unchanged 
 351                 obj_names
.append (os
.path
.join (output_dir
, base 
+ ext
)) 
 353                 # these need to be compiled to .res-files 
 354                 obj_names
.append (os
.path
.join (output_dir
, base 
+ '.res')) 
 356                 obj_names
.append (os
.path
.join (output_dir
, 
 357                                             base 
+ self
.obj_extension
)) 
 360     # object_filenames () 
 362     def preprocess (self
, 
 368                     extra_postargs
=None): 
 370         (_
, macros
, include_dirs
) = \
 
 371             self
._fix
_compile
_args
(None, macros
, include_dirs
) 
 372         pp_opts 
= gen_preprocess_options(macros
, include_dirs
) 
 373         pp_args 
= ['cpp32.exe'] + pp_opts
 
 374         if output_file 
is not None: 
 375             pp_args
.append('-o' + output_file
) 
 377             pp_args
[:0] = extra_preargs
 
 379             pp_args
.extend(extra_postargs
) 
 380         pp_args
.append(source
) 
 382         # We need to preprocess: either we're being forced to, or the 
 383         # source file is newer than the target (or the target doesn't 
 385         if self
.force 
or output_file 
is None or newer(source
, output_file
): 
 387                 self
.mkpath(os
.path
.dirname(output_file
)) 
 390             except DistutilsExecError
, msg
: 
 392                 raise CompileError
, msg