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)
This commit is contained in:
Greg Ward 2000-03-06 03:40:29 +00:00
parent eb3f75e636
commit 32c4a8a0ee
3 changed files with 394 additions and 356 deletions

View File

@ -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 -------------------------------------
# -- Filename generation 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'.
# 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, output_dir=None):
"""Return the list of object filenames corresponding to each
specified source filename."""
pass
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
def shared_object_filename (self, source_filename):
"""Return the shared object filename corresponding to a
specified source filename (assuming the same directory)."""
pass
# object_filenames ()
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
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)
# 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
def shared_library_name (self, inname):
"""Given a name with no extension, return the name + shared object extension"""
return inname + self._shared_lib_ext
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)
# -- Utility methods -----------------------------------------------
@ -606,4 +802,4 @@ def gen_lib_options (compiler, library_dirs, libraries):
return lib_opts
# _gen_lib_options ()
# gen_lib_options ()

View File

@ -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 = []
(output_dir, macros, include_dirs) = \
self._fix_compile_args (output_dir, macros, include_dirs)
(objects, skip_sources) = self._prep_compile (sources, output_dir)
objectFiles = []
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")
output_filename = \
self.library_filename (output_libname, output_dir=output_dir)
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)
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 = []
(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 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]
if extra_preargs:
ld_args[:0] = extra_preargs
if extra_postargs:
ld_args.extend (extra_postargs)
self.mkpath (os.path.dirname (output_filename))
self.spawn ([self.link] + ld_args)
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
self.announce ("skipping %s (up-to-date)" % output_filename)
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
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 )
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 )
def library_filename (self, libname):
"""Return the static library filename corresponding to the
specified library name."""
return "%s%s" %( libname, self._static_lib_ext )
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

View File

@ -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 = []
(output_dir, macros, include_dirs) = \
self._fix_compile_args (output_dir, macros, include_dirs)
(objects, skip_sources) = self._prep_compile (sources, output_dir)
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]))
# 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)
# 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)
# 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)
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