diff options
author | Greg Ward <gward@python.net> | 2000-03-06 03:40:29 (GMT) |
---|---|---|
committer | Greg Ward <gward@python.net> | 2000-03-06 03:40:29 (GMT) |
commit | 32c4a8a0ee74ab932c693de3c8658f4fe57c1ca9 (patch) | |
tree | 5180654fe8178af8320c4cc3efb51f0f6999a107 | |
parent | eb3f75e636316c7ee1edeb42b4ae2c0de9665f8c (diff) | |
download | cpython-32c4a8a0ee74ab932c693de3c8658f4fe57c1ca9.zip cpython-32c4a8a0ee74ab932c693de3c8658f4fe57c1ca9.tar.gz cpython-32c4a8a0ee74ab932c693de3c8658f4fe57c1ca9.tar.bz2 |
Serious overhaul of the C compiler interface and the two classes that
implement it (so far):
* moved filename generation methods into CCompiler base class,
driven by data supplied by implementation classes
* moved a bunch of common code from UnixCCompiler to convenience
methods in CCompiler
* overhauled MSVCCompiler's compile/link methods to look and act
as much as possible like UnixCCompiler's, in order to regularize
both interface and behaviour (especially by using those new
convenience methods)
-rw-r--r-- | Lib/distutils/ccompiler.py | 290 | ||||
-rw-r--r-- | Lib/distutils/msvccompiler.py | 235 | ||||
-rw-r--r-- | Lib/distutils/unixccompiler.py | 237 |
3 files changed, 400 insertions, 362 deletions
diff --git a/Lib/distutils/ccompiler.py b/Lib/distutils/ccompiler.py index 4819b23..2336e96 100644 --- a/Lib/distutils/ccompiler.py +++ b/Lib/distutils/ccompiler.py @@ -12,7 +12,7 @@ from types import * from copy import copy from distutils.errors import * from distutils.spawn import spawn -from distutils.util import move_file, mkpath +from distutils.util import move_file, mkpath, newer_pairwise, newer_group class CCompiler: @@ -65,6 +65,18 @@ class CCompiler: # library search path anyways. + # Subclasses that rely on the standard filename generation methods + # implemented below should override these; see the comment near + # those methods ('object_filenames()' et. al.) for details: + src_extensions = None # list of strings + obj_extension = None # string + static_lib_extension = None + shared_lib_extension = None # string + static_lib_format = None # format string + shared_lib_format = None # prob. same as static_lib_format + exe_extension = None # string + + def __init__ (self, verbose=0, dry_run=0, @@ -255,6 +267,138 @@ class CCompiler: self.objects = copy (objects) + # -- Priviate utility methods -------------------------------------- + # (here for the convenience of subclasses) + + def _fix_compile_args (self, output_dir, macros, include_dirs): + """Typecheck and fix-up some of the arguments to the 'compile()' method, + and return fixed-up values. Specifically: if 'output_dir' is + None, replaces it with 'self.output_dir'; ensures that 'macros' + is a list, and augments it with 'self.macros'; ensures that + 'include_dirs' is a list, and augments it with + 'self.include_dirs'. Guarantees that the returned values are of + the correct type, i.e. for 'output_dir' either string or None, + and for 'macros' and 'include_dirs' either list or None.""" + + if output_dir is None: + output_dir = self.output_dir + elif type (output_dir) is not StringType: + raise TypeError, "'output_dir' must be a string or None" + + if macros is None: + macros = self.macros + elif type (macros) is ListType: + macros = macros + (self.macros or []) + else: + raise TypeError, \ + "'macros' (if supplied) must be a list of tuples" + + if include_dirs is None: + include_dirs = self.include_dirs + elif type (include_dirs) in (ListType, TupleType): + include_dirs = list (include_dirs) + (self.include_dirs or []) + else: + raise TypeError, \ + "'include_dirs' (if supplied) must be a list of strings" + + return (output_dir, macros, include_dirs) + + # _fix_compile_args () + + + def _prep_compile (self, sources, output_dir): + """Determine the list of object files corresponding to 'sources', and + figure out which ones really need to be recompiled. Return a list + of all object files and a dictionary telling which source files can + be skipped.""" + + # Get the list of expected output (object) files + objects = self.object_filenames (sources, + output_dir=output_dir) + + if self.force: + skip_source = {} # rebuild everything + for source in sources: + skip_source[source] = 0 + else: + # Figure out which source files we have to recompile according + # to a simplistic check -- we just compare the source and + # object file, no deep dependency checking involving header + # files. + skip_source = {} # rebuild everything + for source in sources: # no wait, rebuild nothing + skip_source[source] = 1 + + (n_sources, n_objects) = newer_pairwise (sources, objects) + for source in n_sources: # no really, only rebuild what's out-of-date + skip_source[source] = 0 + + return (objects, skip_source) + + # _prep_compile () + + + def _fix_link_args (self, objects, output_dir, + takes_libs=0, libraries=None, library_dirs=None): + """Typecheck and fix up some of the arguments supplied to the + 'link_*' methods and return the fixed values. Specifically: + ensure that 'objects' is a list; if output_dir is None, use + self.output_dir; ensure that 'libraries' and 'library_dirs' are + both lists, and augment them with 'self.libraries' and + 'self.library_dirs'. If 'takes_libs' is true, return a tuple + (objects, output_dir, libraries, library_dirs; else return + (objects, output_dir).""" + + if type (objects) not in (ListType, TupleType): + raise TypeError, \ + "'objects' must be a list or tuple of strings" + objects = list (objects) + + if output_dir is None: + output_dir = self.output_dir + elif type (output_dir) is not StringType: + raise TypeError, "'output_dir' must be a string or None" + + if takes_libs: + if libraries is None: + libraries = self.libraries + elif type (libraries) in (ListType, TupleType): + libraries = list (libraries) + (self.libraries or []) + else: + raise TypeError, \ + "'libraries' (if supplied) must be a list of strings" + + if library_dirs is None: + library_dirs = self.library_dirs + elif type (library_dirs) in (ListType, TupleType): + library_dirs = list (library_dirs) + (self.library_dirs or []) + else: + raise TypeError, \ + "'library_dirs' (if supplied) must be a list of strings" + + return (objects, output_dir, libraries, library_dirs) + else: + return (objects, output_dir) + + # _fix_link_args () + + + def _need_link (self, objects, output_file): + """Return true if we need to relink the files listed in 'objects' to + recreate 'output_file'.""" + + if self.force: + return 1 + else: + if self.dry_run: + newer = newer_group (objects, output_file, missing='newer') + else: + newer = newer_group (objects, output_file) + return newer + + # _need_link () + + # -- Worker methods ------------------------------------------------ # (must be implemented by subclasses) @@ -268,8 +412,16 @@ class CCompiler: extra_postargs=None): """Compile one or more C/C++ source files. 'sources' must be a list of strings, each one the name of a C/C++ source - file. Return a list of the object filenames generated - (one for each source filename in 'sources'). + file. Return a list of object filenames, one per source + filename in 'sources'. Depending on the implementation, + not all source files will necessarily be compiled, but + all corresponding object filenames will be returned. + + If 'output_dir' is given, object files will be put under it, + while retaining their original path component. That is, + "foo/bar.c" normally compiles to "foo/bar.o" (for a Unix + implementation); if 'output_dir' is "build", then it would + compile to "build/foo/bar.o". 'macros', if given, must be a list of macro definitions. A macro definition is either a (name, value) 2-tuple or a (name,) @@ -285,11 +437,12 @@ class CCompiler: 'debug' is a boolean; if true, the compiler will be instructed to output debug symbols in (or alongside) the object file(s). - 'extra_preargs' and 'extra_postargs' are optional lists of extra - command-line arguments that will be, respectively, prepended or - appended to the generated command line immediately before - execution. These will most likely be peculiar to the particular - platform and compiler being worked with, but are a necessary + 'extra_preargs' and 'extra_postargs' are implementation- + dependent. On platforms that have the notion of a command-line + (e.g. Unix, DOS/Windows), they are most likely lists of strings: + extra command-line arguments to prepand/append to the compiler + command line. On other platforms, consult the implementation + class documentation. In any event, they are intended as an escape hatch for those occasions when the abstract compiler framework doesn't cut the mustard.""" @@ -398,45 +551,88 @@ class CCompiler: - # -- Filename mangling methods ------------------------------------- - - # General principle for the filename-mangling methods: by default, - # don't include a directory component, no matter what the caller - # supplies. Eg. for UnixCCompiler, a source file of "foo/bar/baz.c" - # becomes "baz.o" or "baz.so", etc. (That way, it's easiest for the - # caller to decide where it wants to put/find the output file.) The - # 'output_dir' parameter overrides this, of course -- the directory - # component of the input filenames is replaced by 'output_dir'. - - def object_filenames (self, source_filenames, output_dir=None): - """Return the list of object filenames corresponding to each - specified source filename.""" - pass - - def shared_object_filename (self, source_filename): - """Return the shared object filename corresponding to a - specified source filename (assuming the same directory).""" - pass - - def library_filename (self, libname): - """Return the static library filename corresponding to the - specified library name.""" - - pass - - def shared_library_filename (self, libname): - """Return the shared library filename corresponding to the - specified library name.""" - pass - - # XXX ugh -- these should go! - def object_name (self, inname): - """Given a name with no extension, return the name + object extension""" - return inname + self._obj_ext + # -- Filename generation methods ----------------------------------- + + # The default implementation of the filename generating methods are + # prejudiced towards the Unix/DOS/Windows view of the world: + # * object files are named by replacing the source file extension + # (eg. .c/.cpp -> .o/.obj) + # * library files (shared or static) are named by plugging the + # library name and extension into a format string, eg. + # "lib%s.%s" % (lib_name, ".a") for Unix static libraries + # * executables are named by appending an extension (possibly + # empty) to the program name: eg. progname + ".exe" for + # Windows + # + # To reduce redundant code, these methods expect to find + # several attributes in the current object (presumably defined + # as class attributes): + # * src_extensions - + # list of C/C++ source file extensions, eg. ['.c', '.cpp'] + # * obj_extension - + # object file extension, eg. '.o' or '.obj' + # * static_lib_extension - + # extension for static library files, eg. '.a' or '.lib' + # * shared_lib_extension - + # extension for shared library/object files, eg. '.so', '.dll' + # * static_lib_format - + # format string for generating static library filenames, + # eg. 'lib%s.%s' or '%s.%s' + # * shared_lib_format + # format string for generating shared library filenames + # (probably same as static_lib_format, since the extension + # is one of the intended parameters to the format string) + # * exe_extension - + # extension for executable files, eg. '' or '.exe' + + def object_filenames (self, + source_filenames, + strip_dir=0, + output_dir=''): + if output_dir is None: output_dir = '' + obj_names = [] + for src_name in source_filenames: + (base, ext) = os.path.splitext (src_name) + if ext not in self.src_extensions: + continue + if strip_dir: + base = os.path.basename (base) + obj_names.append (os.path.join (output_dir, + base + self.obj_extension)) + return obj_names + + # object_filenames () + + + def shared_object_filename (self, + basename, + strip_dir=0, + output_dir=''): + if output_dir is None: output_dir = '' + if strip_dir: + basename = os.path.basename (basename) + return os.path.join (output_dir, basename + self.shared_lib_extension) + + + def library_filename (self, + libname, + lib_type='static', # or 'shared' + strip_dir=0, + output_dir=''): + + if output_dir is None: output_dir = '' + if lib_type not in ("static","shared"): + raise ValueError, "'lib_type' must be \"static\" or \"shared\"" + fmt = getattr (self, lib_type + "_lib_format") + ext = getattr (self, lib_type + "_lib_extension") + + (dir, base) = os.path.split (libname) + filename = fmt % (base, ext) + if strip_dir: + dir = '' + + return os.path.join (output_dir, dir, filename) - def shared_library_name (self, inname): - """Given a name with no extension, return the name + shared object extension""" - return inname + self._shared_lib_ext # -- Utility methods ----------------------------------------------- @@ -606,4 +802,4 @@ def gen_lib_options (compiler, library_dirs, libraries): return lib_opts -# _gen_lib_options () +# gen_lib_options () diff --git a/Lib/distutils/msvccompiler.py b/Lib/distutils/msvccompiler.py index 2dd8dc1..847c611 100644 --- a/Lib/distutils/msvccompiler.py +++ b/Lib/distutils/msvccompiler.py @@ -5,12 +5,13 @@ for the Microsoft Visual Studio.""" # created 1999/08/19, Perry Stoll -# +# hacked by Robin Becker and Thomas Heller to do a better job of +# finding DevStudio (through the registry) + __revision__ = "$Id$" -import os -import sys -import string +import sys, os, string +from types import * from distutils.errors import * from distutils.ccompiler import \ CCompiler, gen_preprocess_options, gen_lib_options @@ -137,6 +138,20 @@ class MSVCCompiler (CCompiler) : compiler_type = 'msvc' + # Private class data (need to distinguish C from C++ source for compiler) + _c_extensions = ['.c'] + _cpp_extensions = ['.cc','.cpp'] + + # Needed for the filename generation methods provided by the + # base class, CCompiler. + src_extensions = _c_extensions + _cpp_extensions + obj_extension = '.obj' + static_lib_extension = '.lib' + shared_lib_extension = '.dll' + static_lib_format = shared_lib_format = '%s%s' + exe_extension = '.exe' + + def __init__ (self, verbose=0, dry_run=0, @@ -169,9 +184,7 @@ class MSVCCompiler (CCompiler) : self.preprocess_options = None self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3' ] - self.compile_options_debug = [ - '/nologo', '/Od', '/MDd', '/W3', '/Z7', '/D_DEBUG' - ] + self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/Z7', '/D_DEBUG'] self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO'] self.ldflags_shared_debug = [ @@ -181,21 +194,7 @@ class MSVCCompiler (CCompiler) : # -- Worker methods ------------------------------------------------ - # (must be implemented by subclasses) - _c_extensions = [ '.c' ] - _cpp_extensions = [ '.cc', '.cpp' ] - - _obj_ext = '.obj' - _exe_ext = '.exe' - _shared_lib_ext = '.dll' - _static_lib_ext = '.lib' - - # XXX the 'output_dir' parameter is ignored by the methods in this - # class! I just put it in to be consistent with CCompiler and - # UnixCCompiler, but someone who actually knows Visual C++ will - # have to make it work... - def compile (self, sources, output_dir=None, @@ -205,48 +204,43 @@ class MSVCCompiler (CCompiler) : extra_preargs=None, extra_postargs=None): - if macros is None: - macros = [] - if include_dirs is None: - include_dirs = [] - - objectFiles = [] + (output_dir, macros, include_dirs) = \ + self._fix_compile_args (output_dir, macros, include_dirs) + (objects, skip_sources) = self._prep_compile (sources, output_dir) - base_pp_opts = \ - gen_preprocess_options (self.macros + macros, - self.include_dirs + include_dirs) - - base_pp_opts.append('/c') + if extra_postargs is None: + extra_postargs = [] + pp_opts = gen_preprocess_options (macros, include_dirs) + compile_opts = extra_preargs or [] + compile_opts.append ('/c') if debug: - compile_options = self.compile_options_debug + compile_opts.extend (self.compile_options_debug) else: - compile_options = self.compile_options + compile_opts.extend (self.compile_options) - for srcFile in sources: - base,ext = os.path.splitext(srcFile) - objFile = base + ".obj" + for i in range (len (sources)): + src = sources[i] ; obj = objects[i] + ext = (os.path.splitext (src))[1] - if ext in self._c_extensions: - fileOpt = "/Tc" - elif ext in self._cpp_extensions: - fileOpt = "/Tp" + if skip_sources[src]: + self.announce ("skipping %s (%s up-to-date)" % (src, obj)) + else: + if ext in self._c_extensions: + input_opt = "/Tc" + src + elif ext in self._cpp_extensions: + input_opt = "/Tp" + src - inputOpt = fileOpt + srcFile - outputOpt = "/Fo" + objFile + output_opt = "/Fo" + obj - cc_args = compile_options + \ - base_pp_opts + \ - [outputOpt, inputOpt] + self.mkpath (os.path.dirname (obj)) + self.spawn ([self.cc] + compile_opts + pp_opts + + [input_opt, output_opt] + + extra_postargs) - if extra_preargs: - cc_args[:0] = extra_preargs - if extra_postargs: - cc_args.extend (extra_postargs) + return objects - self.spawn ([self.cc] + cc_args) - objectFiles.append( objFile ) - return objectFiles + # compile () # XXX the signature of this method is different from CCompiler and @@ -263,25 +257,30 @@ class MSVCCompiler (CCompiler) : extra_preargs=None, extra_postargs=None): - if libraries is None: - libraries = [] - if library_dirs is None: - library_dirs = [] + (objects, output_dir, libraries, library_dirs) = \ + self._fix_link_args (objects, output_dir, takes_libs=1, + libraries=libraries, + library_dirs=library_dirs) - lib_opts = gen_lib_options (self.libraries + libraries, - self.library_dirs + library_dirs, - "%s.lib", "/LIBPATH:%s") - - ld_args = self.ldflags_static + lib_opts + \ - objects + ['/OUT:' + output_filename] - if debug: - pass # XXX what goes here? - if extra_preargs: - ld_args[:0] = extra_preargs - if extra_postargs: - ld_args.extend (extra_postargs) + output_filename = \ + self.library_filename (output_libname, output_dir=output_dir) + + if self._need_link (objects, output_filename): + lib_opts = gen_lib_options (libraries, library_dirs, + "%s.lib", "/LIBPATH:%s") + ld_args = self.ldflags_static + lib_opts + \ + objects + ['/OUT:' + output_filename] + if debug: + pass # XXX what goes here? + if extra_preargs: + ld_args[:0] = extra_preargs + if extra_postargs: + ld_args.extend (extra_postargs) + self.spawn ([self.link] + ld_args) + else: + self.announce ("skipping %s (up-to-date)" % output_filename) - self.spawn ( [ self.link ] + ld_args ) + # link_static_lib () def link_shared_lib (self, @@ -294,8 +293,6 @@ class MSVCCompiler (CCompiler) : extra_preargs=None, extra_postargs=None): - # XXX should we sanity check the library name? (eg. no - # slashes) self.link_shared_object (objects, self.shared_library_name(output_libname), output_dir=output_dir, @@ -315,70 +312,48 @@ class MSVCCompiler (CCompiler) : debug=0, extra_preargs=None, extra_postargs=None): - """Link a bunch of stuff together to create a shared object - file. Much like 'link_shared_lib()', except the output - filename is explicitly supplied as 'output_filename'.""" - if libraries is None: - libraries = [] - if library_dirs is None: - library_dirs = [] - - lib_opts = gen_lib_options (self, - self.library_dirs + library_dirs, - self.libraries + libraries) - - if debug: - ldflags = self.ldflags_shared_debug - basename, ext = os.path.splitext (output_filename) - #XXX not sure this belongs here - # extensions in debug_mode are named 'module_d.pyd' - output_filename = basename + '_d' + ext - else: - ldflags = self.ldflags_shared - - ld_args = ldflags + lib_opts + \ - objects + ['/OUT:' + output_filename] - - if extra_preargs: - ld_args[:0] = extra_preargs - if extra_postargs: - ld_args.extend (extra_postargs) - - self.spawn ( [ self.link ] + ld_args ) - - # -- Filename mangling methods ------------------------------------- - - def _change_extensions( self, filenames, newExtension ): - object_filenames = [] - - for srcFile in filenames: - base,ext = os.path.splitext( srcFile ) - # XXX should we strip off any existing path? - object_filenames.append( base + newExtension ) - - return object_filenames + (objects, output_dir, libraries, library_dirs) = \ + self._fix_link_args (objects, output_dir, takes_libs=1, + libraries=libraries, library_dirs=library_dirs) + + lib_opts = gen_lib_options (self, library_dirs, libraries) + if type (output_dir) not in (StringType, NoneType): + raise TypeError, "'output_dir' must be a string or None" + if output_dir is not None: + output_filename = os.path.join (output_dir, output_filename) + + if self._need_link (objects, output_filename): + + if debug: + ldflags = self.ldflags_shared_debug + # XXX not sure this belongs here + # extensions in debug_mode are named 'module_d.pyd' + basename, ext = os.path.splitext (output_filename) + output_filename = basename + '_d' + ext + else: + ldflags = self.ldflags_shared + + ld_args = ldflags + lib_opts + \ + objects + ['/OUT:' + output_filename] - def object_filenames (self, source_filenames): - """Return the list of object filenames corresponding to each - specified source filename.""" - return self._change_extensions( source_filenames, self._obj_ext ) + if extra_preargs: + ld_args[:0] = extra_preargs + if extra_postargs: + ld_args.extend (extra_postargs) - def shared_object_filename (self, source_filename): - """Return the shared object filename corresponding to a - specified source filename.""" - return self._change_extensions( source_filenames, self._shared_lib_ext ) + self.mkpath (os.path.dirname (output_filename)) + self.spawn ([self.link] + ld_args) - def library_filename (self, libname): - """Return the static library filename corresponding to the - specified library name.""" - return "%s%s" %( libname, self._static_lib_ext ) + else: + self.announce ("skipping %s (up-to-date)" % output_filename) - def shared_library_filename (self, libname): - """Return the shared library filename corresponding to the - specified library name.""" - return "%s%s" %( libname, self._shared_lib_ext ) + # link_shared_object () + + # -- Miscellaneous methods ----------------------------------------- + # These are all used by the 'gen_lib_options() function, in + # ccompiler.py. def library_dir_option (self, dir): return "/LIBPATH:" + dir diff --git a/Lib/distutils/unixccompiler.py b/Lib/distutils/unixccompiler.py index 7765faf..35390de 100644 --- a/Lib/distutils/unixccompiler.py +++ b/Lib/distutils/unixccompiler.py @@ -20,10 +20,9 @@ __revision__ = "$Id$" import string, re, os from types import * from copy import copy -from sysconfig import \ +from distutils.sysconfig import \ CC, CCSHARED, CFLAGS, OPT, LDSHARED, LDFLAGS, RANLIB, AR, SO -from ccompiler import CCompiler, gen_preprocess_options, gen_lib_options -from util import move_file, newer_pairwise, newer_group +from distutils.ccompiler import CCompiler, gen_preprocess_options, gen_lib_options # XXX Things not currently handled: # * optimization/debug/warning flags; we just use whatever's in Python's @@ -55,10 +54,13 @@ class UnixCCompiler (CCompiler): compiler_type = 'unix' - _obj_ext = '.o' - _exe_ext = '' - _shared_lib_ext = SO - _static_lib_ext = '.a' + # Needed for the filename generation methods provided by the + # base class, CCompiler. + src_extensions = [".c",".C",".cc",".cxx",".cpp"] + obj_extension = ".o" + static_lib_extension = ".a" + shared_lib_extension = ".so" + static_lib_format = shared_lib_format = "lib%s%s" # Command to create a static library: seems to be pretty consistent # across the major Unices. Might have to move down into the @@ -96,66 +98,24 @@ class UnixCCompiler (CCompiler): self.ld_exec = self.cc + # __init__ () + def compile (self, sources, output_dir=None, - keep_dir=0, macros=None, include_dirs=None, debug=0, extra_preargs=None, extra_postargs=None): - if type (output_dir) not in (StringType, NoneType): - raise TypeError, "'output_dir' must be a string or None" - if output_dir is None: - output_dir = self.output_dir - if macros is None: - macros = [] - if include_dirs is None: - include_dirs = [] - - if type (macros) is not ListType: - raise TypeError, \ - "'macros' (if supplied) must be a list of tuples" - if type (include_dirs) not in (ListType, TupleType): - raise TypeError, \ - "'include_dirs' (if supplied) must be a list of strings" - include_dirs = list (include_dirs) - - pp_opts = gen_preprocess_options (self.macros + macros, - self.include_dirs + include_dirs) - - # So we can mangle 'sources' without hurting the caller's data - orig_sources = sources - sources = copy (sources) - - # Get the list of expected output (object) files and drop files we - # don't have to recompile. (Simplistic check -- we just compare the - # source and object file, no deep dependency checking involving - # header files. Hmmm.) - objects = self.object_filenames (sources, - output_dir=output_dir, - keep_dir=keep_dir) - all_objects = copy (objects) # preserve full list to return - - if not self.force: - skipped = newer_pairwise (sources, objects) - for skipped_pair in skipped: - self.announce ("skipping %s (%s up-to-date)" % skipped_pair) - - # Build list of (source,object) tuples for convenience - srcobj = [] - for i in range (len (sources)): - srcobj.append ((sources[i], objects[i])) + (output_dir, macros, include_dirs) = \ + self._fix_compile_args (output_dir, macros, include_dirs) + (objects, skip_sources) = self._prep_compile (sources, output_dir) - # Compile all source files that weren't eliminated by - # 'newer_pairwise()'. - # XXX use of ccflags_shared means we're blithely assuming - # that we're compiling for inclusion in a shared object! - # (will have to fix this when I add the ability to build a - # new Python) + # Figure out the options for the compiler command line. + pp_opts = gen_preprocess_options (macros, include_dirs) cc_args = ['-c'] + pp_opts + self.ccflags + self.ccflags_shared if debug: cc_args[:0] = ['-g'] @@ -164,44 +124,21 @@ class UnixCCompiler (CCompiler): if extra_postargs is None: extra_postargs = [] - if output_dir is not None: - self.mkpath (output_dir) - for (source,object) in srcobj: - self.spawn ([self.cc] + cc_args + - [source, '-o', object] + - extra_postargs) - - # Have to re-fetch list of object filenames, because we want to - # return *all* of them, including those that weren't recompiled on - # this call! - return all_objects - - - def _fix_link_args (self, output_dir, libraries, library_dirs): - """Fixes up the arguments supplied to the 'link_*' methods: - if output_dir is None, use self.output_dir; ensure that - libraries and library_dirs are both lists (could be None or - tuples on input -- both are converted to lists). Return - a tuple of the three input arguments.""" - - if output_dir is None: - output_dir = self.output_dir - if libraries is None: - libraries = [] - if library_dirs is None: - library_dirs = [] - - if type (libraries) not in (ListType, TupleType): - raise TypeError, \ - "'libraries' (if supplied) must be a list of strings" - if type (library_dirs) not in (ListType, TupleType): - raise TypeError, \ - "'library_dirs' (if supplied) must be a list of strings" - libraries = list (libraries) - library_dirs = list (library_dirs) + # Compile all source files that weren't eliminated by + # '_prep_compile()'. + for i in range (len (sources)): + src = sources[i] ; obj = objects[i] + if skip_sources[src]: + self.announce ("skipping %s (%s up-to-date)" % (src, obj)) + else: + self.mkpath (os.path.dirname (obj)) + self.spawn ([self.cc] + cc_args + [src, '-o', obj] + extra_postargs) - return (output_dir, libraries, library_dirs) + # Return *all* object filenames, not just the ones we just built. + return objects + # compile () + def link_static_lib (self, objects, @@ -209,35 +146,17 @@ class UnixCCompiler (CCompiler): output_dir=None, debug=0): - if type (objects) not in (ListType, TupleType): - raise TypeError, \ - "'objects' must be a list or tuple of strings" - objects = list (objects) - - if type (output_dir) not in (StringType, NoneType): - raise TypeError, "'output_dir' must be a string or None" - if output_dir is None: - output_dir = self.output_dir + (objects, output_dir) = self._fix_link_args (objects, output_dir, takes_libs=0) - output_filename = self.library_filename (output_libname) - if output_dir is not None: - output_filename = os.path.join (output_dir, output_filename) + output_filename = \ + self.library_filename (output_libname, output_dir=output_dir) - # Check timestamps: if any of the object files are newer than - # the library file, *or* if "force" is true, then we'll - # recreate the library. - if not self.force: - if self.dry_run: - newer = newer_group (objects, output_filename, missing='newer') - else: - newer = newer_group (objects, output_filename) - - if self.force or newer: + if self._need_link (objects, output_filename): self.mkpath (os.path.dirname (output_filename)) self.spawn ([self.archiver, self.archiver_options, output_filename] + - objects) + objects + self.objects) else: self.announce ("skipping %s (up-to-date)" % output_filename) @@ -253,11 +172,9 @@ class UnixCCompiler (CCompiler): debug=0, extra_preargs=None, extra_postargs=None): - # XXX should we sanity check the library name? (eg. no - # slashes) self.link_shared_object ( objects, - "lib%s%s" % (output_libname, self._shared_lib_ext), + self.shared_library_filename (output_libname), output_dir, libraries, library_dirs, @@ -276,30 +193,19 @@ class UnixCCompiler (CCompiler): extra_preargs=None, extra_postargs=None): - (output_dir, libraries, library_dirs) = \ - self._fix_link_args (output_dir, libraries, library_dirs) + (objects, output_dir, libraries, library_dirs) = \ + self._fix_link_args (objects, output_dir, takes_libs=1, + libraries=libraries, library_dirs=library_dirs) - lib_opts = gen_lib_options (self, - self.library_dirs + library_dirs, - self.libraries + libraries) + lib_opts = gen_lib_options (self, library_dirs, libraries) if type (output_dir) not in (StringType, NoneType): raise TypeError, "'output_dir' must be a string or None" if output_dir is not None: output_filename = os.path.join (output_dir, output_filename) - # If any of the input object files are newer than the output shared - # object, relink. Again, this is a simplistic dependency check: - # doesn't look at any of the libraries we might be linking with. - - if not self.force: - if self.dry_run: - newer = newer_group (objects, output_filename, missing='newer') - else: - newer = newer_group (objects, output_filename) - - if self.force or newer: - ld_args = self.ldflags_shared + objects + \ - lib_opts + ['-o', output_filename] + if self._need_link (objects, output_filename): + ld_args = (self.ldflags_shared + objects + self.objects + + lib_opts + ['-o', output_filename]) if debug: ld_args[:0] = ['-g'] if extra_preargs: @@ -324,25 +230,17 @@ class UnixCCompiler (CCompiler): extra_preargs=None, extra_postargs=None): - (output_dir, libraries, library_dirs) = \ - self._fix_link_args (output_dir, libraries, library_dirs) + (objects, output_dir, libraries, library_dirs) = \ + self._fix_link_args (objects, output_dir, takes_libs=1, + libraries=libraries, library_dirs=library_dirs) - lib_opts = gen_lib_options (self, - self.library_dirs + library_dirs, - self.libraries + libraries) + lib_opts = gen_lib_options (self, library_dirs, libraries) output_filename = output_progname # Unix-ism! if output_dir is not None: output_filename = os.path.join (output_dir, output_filename) - # Same ol' simplistic-but-still-useful dependency check. - if not self.force: - if self.dry_run: - newer = newer_group (objects, output_filename, missing='newer') - else: - newer = newer_group (objects, output_filename) - - if self.force or newer: - ld_args = objects + lib_opts + ['-o', output_filename] + if self._need_link (objects, output_filename): + ld_args = objects + self.objects + lib_opts + ['-o', output_filename] if debug: ld_args[:0] = ['-g'] if extra_preargs: @@ -357,41 +255,10 @@ class UnixCCompiler (CCompiler): # link_executable () - # -- Filename-mangling (etc.) methods ------------------------------ - - def object_filenames (self, source_filenames, - keep_dir=0, output_dir=None): - outnames = [] - for inname in source_filenames: - outname = re.sub (r'\.(c|C|cc|cxx|cpp)$', self._obj_ext, inname) - if not keep_dir: - outname = os.path.basename (outname) - if output_dir is not None: - outname = os.path.join (output_dir, outname) - outnames.append (outname) - return outnames - - def shared_object_filename (self, source_filename, - keep_dir=0, output_dir=None): - outname = re.sub (r'\.(c|C|cc|cxx|cpp)$', self._shared_lib_ext) - if not keep_dir: - outname = os.path.basename (outname) - if output_dir is not None: - outname = os.path.join (output_dir, outname) - return outname - - - def library_filename (self, libname): - (dirname, basename) = os.path.split (libname) - return os.path.join (dirname, - "lib%s%s" % (basename, self._static_lib_ext)) - - def shared_library_filename (self, libname): - (dirname, basename) = os.path.split (libname) - return os.path.join (dirname, - "lib%s%s" % (basename, self._shared_lib_ext)) - - + # -- Miscellaneous methods ----------------------------------------- + # These are all used by the 'gen_lib_options() function, in + # ccompiler.py. + def library_dir_option (self, dir): return "-L" + dir |