home *** CD-ROM | disk | FTP | other *** search
/ Freelog Special Freeware 31 / FreelogHS31.iso / Texte / scribus / scribus-1.3.3.9-win32-install.exe / lib / distutils / bcppcompiler.py < prev    next >
Text File  |  2004-11-18  |  15KB  |  399 lines

  1. """distutils.bcppcompiler
  2.  
  3. Contains BorlandCCompiler, an implementation of the abstract CCompiler class
  4. for the Borland C++ compiler.
  5. """
  6.  
  7. # This implementation by Lyle Johnson, based on the original msvccompiler.py
  8. # module and using the directions originally published by Gordon Williams.
  9.  
  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
  13.  
  14. # This module should be kept compatible with Python 2.1.
  15.  
  16. __revision__ = "$Id: bcppcompiler.py,v 1.18 2004/11/10 22:23:13 loewis Exp $"
  17.  
  18.  
  19. import sys, os
  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
  28.  
  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.
  32.     """
  33.  
  34.     compiler_type = 'bcpp'
  35.  
  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.
  41.     executables = {}
  42.  
  43.     # Private class data (need to distinguish C from C++ source for compiler)
  44.     _c_extensions = ['.c']
  45.     _cpp_extensions = ['.cc', '.cpp', '.cxx']
  46.  
  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'
  55.  
  56.  
  57.     def __init__ (self,
  58.                   verbose=0,
  59.                   dry_run=0,
  60.                   force=0):
  61.  
  62.         CCompiler.__init__ (self, verbose, dry_run, force)
  63.  
  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.
  67.  
  68.         self.cc = "bcc32.exe"
  69.         self.linker = "ilink32.exe"
  70.         self.lib = "tlib.exe"
  71.  
  72.         self.preprocess_options = None
  73.         self.compile_options = ['/tWM', '/O2', '/q', '/g0']
  74.         self.compile_options_debug = ['/tWM', '/Od', '/q', '/g0']
  75.  
  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']
  81.  
  82.  
  83.     # -- Worker methods ------------------------------------------------
  84.  
  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):
  88.  
  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')
  94.         if debug:
  95.             compile_opts.extend (self.compile_options_debug)
  96.         else:
  97.             compile_opts.extend (self.compile_options)
  98.  
  99.         for obj in objects:
  100.             try:
  101.                 src, ext = build[obj]
  102.             except KeyError:
  103.                 continue
  104.             # XXX why do the normpath here?
  105.             src = os.path.normpath(src)
  106.             obj = os.path.normpath(obj)
  107.             # XXX _setup_compile() did a mkpath() too but before the normpath.
  108.             # Is it possible to skip the normpath?
  109.             self.mkpath(os.path.dirname(obj))
  110.  
  111.             if ext == '.res':
  112.                 # This is already a binary file -- skip it.
  113.                 continue # the 'for' loop
  114.             if ext == '.rc':
  115.                 # This needs to be compiled to a .res file -- do it now.
  116.                 try:
  117.                     self.spawn (["brcc32", "-fo", obj, src])
  118.                 except DistutilsExecError, msg:
  119.                     raise CompileError, msg
  120.                 continue # the 'for' loop
  121.  
  122.             # The next two are both for the real compiler.
  123.             if ext in self._c_extensions:
  124.                 input_opt = ""
  125.             elif ext in self._cpp_extensions:
  126.                 input_opt = "-P"
  127.             else:
  128.                 # Unknown file type -- no extra options.  The compiler
  129.                 # will probably fail, but let it just in case this is a
  130.                 # file the compiler recognizes even if we don't.
  131.                 input_opt = ""
  132.  
  133.             output_opt = "-o" + obj
  134.  
  135.             # Compiler command line syntax is: "bcc32 [options] file(s)".
  136.             # Note that the source file names must appear at the end of
  137.             # the command line.
  138.             try:
  139.                 self.spawn ([self.cc] + compile_opts + pp_opts +
  140.                             [input_opt, output_opt] +
  141.                             extra_postargs + [src])
  142.             except DistutilsExecError, msg:
  143.                 raise CompileError, msg
  144.  
  145.         return objects
  146.  
  147.     # compile ()
  148.  
  149.  
  150.     def create_static_lib (self,
  151.                            objects,
  152.                            output_libname,
  153.                            output_dir=None,
  154.                            debug=0,
  155.                            target_lang=None):
  156.  
  157.         (objects, output_dir) = self._fix_object_args (objects, output_dir)
  158.         output_filename = \
  159.             self.library_filename (output_libname, output_dir=output_dir)
  160.  
  161.         if self._need_link (objects, output_filename):
  162.             lib_args = [output_filename, '/u'] + objects
  163.             if debug:
  164.                 pass                    # XXX what goes here?
  165.             try:
  166.                 self.spawn ([self.lib] + lib_args)
  167.             except DistutilsExecError, msg:
  168.                 raise LibError, msg
  169.         else:
  170.             log.debug("skipping %s (up-to-date)", output_filename)
  171.  
  172.     # create_static_lib ()
  173.  
  174.  
  175.     def link (self,
  176.               target_desc,
  177.               objects,
  178.               output_filename,
  179.               output_dir=None,
  180.               libraries=None,
  181.               library_dirs=None,
  182.               runtime_library_dirs=None,
  183.               export_symbols=None,
  184.               debug=0,
  185.               extra_preargs=None,
  186.               extra_postargs=None,
  187.               build_temp=None,
  188.               target_lang=None):
  189.  
  190.         # XXX this ignores 'build_temp'!  should follow the lead of
  191.         # msvccompiler.py
  192.  
  193.         (objects, output_dir) = self._fix_object_args (objects, output_dir)
  194.         (libraries, library_dirs, runtime_library_dirs) = \
  195.             self._fix_lib_args (libraries, library_dirs, runtime_library_dirs)
  196.  
  197.         if runtime_library_dirs:
  198.             log.warn("I don't know what to do with 'runtime_library_dirs': %s",
  199.                      str(runtime_library_dirs))
  200.  
  201.         if output_dir is not None:
  202.             output_filename = os.path.join (output_dir, output_filename)
  203.  
  204.         if self._need_link (objects, output_filename):
  205.  
  206.             # Figure out linker args based on type of target.
  207.             if target_desc == CCompiler.EXECUTABLE:
  208.                 startup_obj = 'c0w32'
  209.                 if debug:
  210.                     ld_args = self.ldflags_exe_debug[:]
  211.                 else:
  212.                     ld_args = self.ldflags_exe[:]
  213.             else:
  214.                 startup_obj = 'c0d32'
  215.                 if debug:
  216.                     ld_args = self.ldflags_shared_debug[:]
  217.                 else:
  218.                     ld_args = self.ldflags_shared[:]
  219.  
  220.  
  221.             # Create a temporary exports file for use by the linker
  222.             if export_symbols is None:
  223.                 def_file = ''
  224.             else:
  225.                 head, tail = os.path.split (output_filename)
  226.                 modname, ext = os.path.splitext (tail)
  227.                 temp_dir = os.path.dirname(objects[0]) # preserve tree structure
  228.                 def_file = os.path.join (temp_dir, '%s.def' % modname)
  229.                 contents = ['EXPORTS']
  230.                 for sym in (export_symbols or []):
  231.                     contents.append('  %s=_%s' % (sym, sym))
  232.                 self.execute(write_file, (def_file, contents),
  233.                              "writing %s" % def_file)
  234.  
  235.             # Borland C++ has problems with '/' in paths
  236.             objects2 = map(os.path.normpath, objects)
  237.             # split objects in .obj and .res files
  238.             # Borland C++ needs them at different positions in the command line
  239.             objects = [startup_obj]
  240.             resources = []
  241.             for file in objects2:
  242.                 (base, ext) = os.path.splitext(os.path.normcase(file))
  243.                 if ext == '.res':
  244.                     resources.append(file)
  245.                 else:
  246.                     objects.append(file)
  247.  
  248.  
  249.             for l in library_dirs:
  250.                 ld_args.append("/L%s" % os.path.normpath(l))
  251.             ld_args.append("/L.") # we sometimes use relative paths
  252.  
  253.             # list of object files
  254.             ld_args.extend(objects)
  255.  
  256.             # XXX the command-line syntax for Borland C++ is a bit wonky;
  257.             # certain filenames are jammed together in one big string, but
  258.             # comma-delimited.  This doesn't mesh too well with the
  259.             # Unix-centric attitude (with a DOS/Windows quoting hack) of
  260.             # 'spawn()', so constructing the argument list is a bit
  261.             # awkward.  Note that doing the obvious thing and jamming all
  262.             # the filenames and commas into one argument would be wrong,
  263.             # because 'spawn()' would quote any filenames with spaces in
  264.             # them.  Arghghh!.  Apparently it works fine as coded...
  265.  
  266.             # name of dll/exe file
  267.             ld_args.extend([',',output_filename])
  268.             # no map file and start libraries
  269.             ld_args.append(',,')
  270.  
  271.             for lib in libraries:
  272.                 # see if we find it and if there is a bcpp specific lib
  273.                 # (xxx_bcpp.lib)
  274.                 libfile = self.find_library_file(library_dirs, lib, debug)
  275.                 if libfile is None:
  276.                     ld_args.append(lib)
  277.                     # probably a BCPP internal library -- don't warn
  278.                 else:
  279.                     # full name which prefers bcpp_xxx.lib over xxx.lib
  280.                     ld_args.append(libfile)
  281.  
  282.             # some default libraries
  283.             ld_args.append ('import32')
  284.             ld_args.append ('cw32mt')
  285.  
  286.             # def file for export symbols
  287.             ld_args.extend([',',def_file])
  288.             # add resource files
  289.             ld_args.append(',')
  290.             ld_args.extend(resources)
  291.  
  292.  
  293.             if extra_preargs:
  294.                 ld_args[:0] = extra_preargs
  295.             if extra_postargs:
  296.                 ld_args.extend(extra_postargs)
  297.  
  298.             self.mkpath (os.path.dirname (output_filename))
  299.             try:
  300.                 self.spawn ([self.linker] + ld_args)
  301.             except DistutilsExecError, msg:
  302.                 raise LinkError, msg
  303.  
  304.         else:
  305.             log.debug("skipping %s (up-to-date)", output_filename)
  306.  
  307.     # link ()
  308.  
  309.     # -- Miscellaneous methods -----------------------------------------
  310.  
  311.  
  312.     def find_library_file (self, dirs, lib, debug=0):
  313.         # List of effective library names to try, in order of preference:
  314.         # xxx_bcpp.lib is better than xxx.lib
  315.         # and xxx_d.lib is better than xxx.lib if debug is set
  316.         #
  317.         # The "_bcpp" suffix is to handle a Python installation for people
  318.         # with multiple compilers (primarily Distutils hackers, I suspect
  319.         # ;-).  The idea is they'd have one static library for each
  320.         # compiler they care about, since (almost?) every Windows compiler
  321.         # seems to have a different format for static libraries.
  322.         if debug:
  323.             dlib = (lib + "_d")
  324.             try_names = (dlib + "_bcpp", lib + "_bcpp", dlib, lib)
  325.         else:
  326.             try_names = (lib + "_bcpp", lib)
  327.  
  328.         for dir in dirs:
  329.             for name in try_names:
  330.                 libfile = os.path.join(dir, self.library_filename(name))
  331.                 if os.path.exists(libfile):
  332.                     return libfile
  333.         else:
  334.             # Oops, didn't find it in *any* of 'dirs'
  335.             return None
  336.  
  337.     # overwrite the one from CCompiler to support rc and res-files
  338.     def object_filenames (self,
  339.                           source_filenames,
  340.                           strip_dir=0,
  341.                           output_dir=''):
  342.         if output_dir is None: output_dir = ''
  343.         obj_names = []
  344.         for src_name in source_filenames:
  345.             # use normcase to make sure '.rc' is really '.rc' and not '.RC'
  346.             (base, ext) = os.path.splitext (os.path.normcase(src_name))
  347.             if ext not in (self.src_extensions + ['.rc','.res']):
  348.                 raise UnknownFileError, \
  349.                       "unknown file type '%s' (from '%s')" % \
  350.                       (ext, src_name)
  351.             if strip_dir:
  352.                 base = os.path.basename (base)
  353.             if ext == '.res':
  354.                 # these can go unchanged
  355.                 obj_names.append (os.path.join (output_dir, base + ext))
  356.             elif ext == '.rc':
  357.                 # these need to be compiled to .res-files
  358.                 obj_names.append (os.path.join (output_dir, base + '.res'))
  359.             else:
  360.                 obj_names.append (os.path.join (output_dir,
  361.                                             base + self.obj_extension))
  362.         return obj_names
  363.  
  364.     # object_filenames ()
  365.  
  366.     def preprocess (self,
  367.                     source,
  368.                     output_file=None,
  369.                     macros=None,
  370.                     include_dirs=None,
  371.                     extra_preargs=None,
  372.                     extra_postargs=None):
  373.  
  374.         (_, macros, include_dirs) = \
  375.             self._fix_compile_args(None, macros, include_dirs)
  376.         pp_opts = gen_preprocess_options(macros, include_dirs)
  377.         pp_args = ['cpp32.exe'] + pp_opts
  378.         if output_file is not None:
  379.             pp_args.append('-o' + output_file)
  380.         if extra_preargs:
  381.             pp_args[:0] = extra_preargs
  382.         if extra_postargs:
  383.             pp_args.extend(extra_postargs)
  384.         pp_args.append(source)
  385.  
  386.         # We need to preprocess: either we're being forced to, or the
  387.         # source file is newer than the target (or the target doesn't
  388.         # exist).
  389.         if self.force or output_file is None or newer(source, output_file):
  390.             if output_file:
  391.                 self.mkpath(os.path.dirname(output_file))
  392.             try:
  393.                 self.spawn(pp_args)
  394.             except DistutilsExecError, msg:
  395.                 print msg
  396.                 raise CompileError, msg
  397.  
  398.     # preprocess()
  399.