home *** CD-ROM | disk | FTP | other *** search
/ PC World 2002 May / PCWorld_2002-05_cd.bin / Software / TemaCD / activepython / ActivePython-2.1.1.msi / Python21_Lib_distutils_unixccompiler.py < prev    next >
Encoding:
Python Source  |  2001-07-26  |  10.5 KB  |  281 lines

  1. """distutils.unixccompiler
  2.  
  3. Contains the UnixCCompiler class, a subclass of CCompiler that handles
  4. the "typical" Unix-style command-line C compiler:
  5.   * macros defined with -Dname[=value]
  6.   * macros undefined with -Uname
  7.   * include search directories specified with -Idir
  8.   * libraries specified with -lllib
  9.   * library search directories specified with -Ldir
  10.   * compile handled by 'cc' (or similar) executable with -c option:
  11.     compiles .c to .o
  12.   * link static library handled by 'ar' command (possibly with 'ranlib')
  13.   * link shared library handled by 'cc -shared'
  14. """
  15.  
  16. # created 1999/07/05, Greg Ward
  17.  
  18. __revision__ = "$Id: unixccompiler.py,v 1.33.2.1 2001/07/19 09:50:49 twouters Exp $"
  19.  
  20. import string, re, os
  21. from types import *
  22. from copy import copy
  23. from distutils.dep_util import newer
  24. from distutils.ccompiler import \
  25.      CCompiler, gen_preprocess_options, gen_lib_options
  26. from distutils.errors import \
  27.      DistutilsExecError, CompileError, LibError, LinkError
  28.  
  29. # XXX Things not currently handled:
  30. #   * optimization/debug/warning flags; we just use whatever's in Python's
  31. #     Makefile and live with it.  Is this adequate?  If not, we might
  32. #     have to have a bunch of subclasses GNUCCompiler, SGICCompiler,
  33. #     SunCCompiler, and I suspect down that road lies madness.
  34. #   * even if we don't know a warning flag from an optimization flag,
  35. #     we need some way for outsiders to feed preprocessor/compiler/linker
  36. #     flags in to us -- eg. a sysadmin might want to mandate certain flags
  37. #     via a site config file, or a user might want to set something for
  38. #     compiling this module distribution only via the setup.py command
  39. #     line, whatever.  As long as these options come from something on the
  40. #     current system, they can be as system-dependent as they like, and we
  41. #     should just happily stuff them into the preprocessor/compiler/linker
  42. #     options and carry on.
  43.  
  44.  
  45. class UnixCCompiler (CCompiler):
  46.  
  47.     compiler_type = 'unix'
  48.  
  49.     # These are used by CCompiler in two places: the constructor sets
  50.     # instance attributes 'preprocessor', 'compiler', etc. from them, and
  51.     # 'set_executable()' allows any of these to be set.  The defaults here
  52.     # are pretty generic; they will probably have to be set by an outsider
  53.     # (eg. using information discovered by the sysconfig about building
  54.     # Python extensions).
  55.     executables = {'preprocessor' : None,
  56.                    'compiler'     : ["cc"],
  57.                    'compiler_so'  : ["cc"],
  58.                    'linker_so'    : ["cc", "-shared"],
  59.                    'linker_exe'   : ["cc"],
  60.                    'archiver'     : ["ar", "-cr"],
  61.                    'ranlib'       : None,
  62.                   }
  63.  
  64.     # Needed for the filename generation methods provided by the base
  65.     # class, CCompiler.  NB. whoever instantiates/uses a particular
  66.     # UnixCCompiler instance should set 'shared_lib_ext' -- we set a
  67.     # reasonable common default here, but it's not necessarily used on all
  68.     # Unices!
  69.  
  70.     src_extensions = [".c",".C",".cc",".cxx",".cpp",".m"]
  71.     obj_extension = ".o"
  72.     static_lib_extension = ".a"
  73.     shared_lib_extension = ".so"
  74.     static_lib_format = shared_lib_format = "lib%s%s"
  75.  
  76.  
  77.  
  78.     def __init__ (self,
  79.                   verbose=0,
  80.                   dry_run=0,
  81.                   force=0):
  82.         CCompiler.__init__ (self, verbose, dry_run, force)
  83.  
  84.  
  85.     def preprocess (self,
  86.                     source,
  87.                     output_file=None,
  88.                     macros=None,
  89.                     include_dirs=None,
  90.                     extra_preargs=None,
  91.                     extra_postargs=None):
  92.  
  93.         (_, macros, include_dirs) = \
  94.             self._fix_compile_args(None, macros, include_dirs)
  95.         pp_opts = gen_preprocess_options(macros, include_dirs)
  96.         pp_args = self.preprocessor + pp_opts
  97.         if output_file:
  98.             pp_args.extend(['-o', output_file])
  99.         if extra_preargs:
  100.             pp_args[:0] = extra_preargs
  101.         if extra_postargs:
  102.             pp_args.extend(extra_postargs)
  103.  
  104.         # We need to preprocess: either we're being forced to, or we're
  105.         # generating output to stdout, or there's a target output file and 
  106.         # the source file is newer than the target (or the target doesn't
  107.         # exist).
  108.         if self.force or output_file is None or newer(source, output_file):
  109.             if output_file:
  110.                 self.mkpath(os.path.dirname(output_file))
  111.             try:
  112.                 self.spawn(pp_args)
  113.             except DistutilsExecError, msg:
  114.                 raise CompileError, msg
  115.  
  116.  
  117.     def compile (self,
  118.                  sources,
  119.                  output_dir=None,
  120.                  macros=None,
  121.                  include_dirs=None,
  122.                  debug=0,
  123.                  extra_preargs=None,
  124.                  extra_postargs=None):
  125.  
  126.         (output_dir, macros, include_dirs) = \
  127.             self._fix_compile_args(output_dir, macros, include_dirs)
  128.         (objects, skip_sources) = self._prep_compile(sources, output_dir)
  129.  
  130.         # Figure out the options for the compiler command line.
  131.         pp_opts = gen_preprocess_options(macros, include_dirs)
  132.         cc_args = pp_opts + ['-c']
  133.         if debug:
  134.             cc_args[:0] = ['-g']
  135.         if extra_preargs:
  136.             cc_args[:0] = extra_preargs
  137.         if extra_postargs is None:
  138.             extra_postargs = []
  139.  
  140.         # Compile all source files that weren't eliminated by
  141.         # '_prep_compile()'.        
  142.         for i in range(len(sources)):
  143.             src = sources[i] ; obj = objects[i]
  144.             if skip_sources[src]:
  145.                 self.announce("skipping %s (%s up-to-date)" % (src, obj))
  146.             else:
  147.                 self.mkpath(os.path.dirname(obj))
  148.                 try:
  149.                     self.spawn(self.compiler_so + cc_args +
  150.                                [src, '-o', obj] +
  151.                                extra_postargs)
  152.                 except DistutilsExecError, msg:
  153.                     raise CompileError, msg
  154.  
  155.         # Return *all* object filenames, not just the ones we just built.
  156.         return objects
  157.  
  158.     # compile ()
  159.     
  160.  
  161.     def create_static_lib (self,
  162.                            objects,
  163.                            output_libname,
  164.                            output_dir=None,
  165.                            debug=0):
  166.  
  167.         (objects, output_dir) = self._fix_object_args(objects, output_dir)
  168.  
  169.         output_filename = \
  170.             self.library_filename(output_libname, output_dir=output_dir)
  171.  
  172.         if self._need_link(objects, output_filename):
  173.             self.mkpath(os.path.dirname(output_filename))
  174.             self.spawn(self.archiver +
  175.                        [output_filename] +
  176.                        objects + self.objects)
  177.  
  178.             # Not many Unices required ranlib anymore -- SunOS 4.x is, I
  179.             # think the only major Unix that does.  Maybe we need some
  180.             # platform intelligence here to skip ranlib if it's not
  181.             # needed -- or maybe Python's configure script took care of
  182.             # it for us, hence the check for leading colon.
  183.             if self.ranlib:
  184.                 try:
  185.                     self.spawn(self.ranlib + [output_filename])
  186.                 except DistutilsExecError, msg:
  187.                     raise LibError, msg
  188.         else:
  189.             self.announce("skipping %s (up-to-date)" % output_filename)
  190.  
  191.     # create_static_lib ()
  192.  
  193.  
  194.     def link (self,
  195.               target_desc,    
  196.               objects,
  197.               output_filename,
  198.               output_dir=None,
  199.               libraries=None,
  200.               library_dirs=None,
  201.               runtime_library_dirs=None,
  202.               export_symbols=None,
  203.               debug=0,
  204.               extra_preargs=None,
  205.               extra_postargs=None,
  206.               build_temp=None):
  207.  
  208.         (objects, output_dir) = self._fix_object_args(objects, output_dir)
  209.         (libraries, library_dirs, runtime_library_dirs) = \
  210.             self._fix_lib_args(libraries, library_dirs, runtime_library_dirs)
  211.  
  212.         lib_opts = gen_lib_options(self,
  213.                                    library_dirs, runtime_library_dirs,
  214.                                    libraries)
  215.         if type(output_dir) not in (StringType, NoneType):
  216.             raise TypeError, "'output_dir' must be a string or None"
  217.         if output_dir is not None:
  218.             output_filename = os.path.join(output_dir, output_filename)
  219.  
  220.         if self._need_link(objects, output_filename):
  221.             ld_args = (objects + self.objects + 
  222.                        lib_opts + ['-o', output_filename])
  223.             if debug:
  224.                 ld_args[:0] = ['-g']
  225.             if extra_preargs:
  226.                 ld_args[:0] = extra_preargs
  227.             if extra_postargs:
  228.                 ld_args.extend(extra_postargs)
  229.             self.mkpath(os.path.dirname(output_filename))
  230.             try:
  231.                 if target_desc == CCompiler.EXECUTABLE:    
  232.                     self.spawn(self.linker_exe + ld_args)
  233.                 else:
  234.                     self.spawn(self.linker_so + ld_args)
  235.             except DistutilsExecError, msg:
  236.                 raise LinkError, msg
  237.         else:
  238.             self.announce("skipping %s (up-to-date)" % output_filename)
  239.  
  240.     # link ()
  241.  
  242.  
  243.     # -- Miscellaneous methods -----------------------------------------
  244.     # These are all used by the 'gen_lib_options() function, in
  245.     # ccompiler.py.
  246.     
  247.     def library_dir_option (self, dir):
  248.         return "-L" + dir
  249.  
  250.     def runtime_library_dir_option (self, dir):
  251.         return "-R" + dir
  252.  
  253.     def library_option (self, lib):
  254.         return "-l" + lib
  255.  
  256.  
  257.     def find_library_file (self, dirs, lib, debug=0):
  258.  
  259.         for dir in dirs:
  260.             shared = os.path.join(
  261.                 dir, self.library_filename(lib, lib_type='shared'))
  262.             static = os.path.join(
  263.                 dir, self.library_filename(lib, lib_type='static'))
  264.  
  265.             # We're second-guessing the linker here, with not much hard
  266.             # data to go on: GCC seems to prefer the shared library, so I'm
  267.             # assuming that *all* Unix C compilers do.  And of course I'm
  268.             # ignoring even GCC's "-static" option.  So sue me.
  269.             if os.path.exists(shared):
  270.                 return shared
  271.             elif os.path.exists(static):
  272.                 return static
  273.  
  274.         else:
  275.             # Oops, didn't find it in *any* of 'dirs'
  276.             return None
  277.  
  278.     # find_library_file ()
  279.  
  280. # class UnixCCompiler
  281.