1 """distutils.unixccompiler
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:
12 * link static library handled by 'ar' command (possibly with 'ranlib')
13 * link shared library handled by 'cc -shared'
16 # created 1999/07/05, Greg Ward
23 from sysconfig
import \
24 CC
, CCSHARED
, CFLAGS
, OPT
, LDSHARED
, LDFLAGS
, RANLIB
, AR
, SO
25 from ccompiler
import CCompiler
, gen_preprocess_options
, gen_lib_options
26 from util
import move_file
, newer_pairwise
, newer_group
28 # XXX Things not currently handled:
29 # * optimization/debug/warning flags; we just use whatever's in Python's
30 # Makefile and live with it. Is this adequate? If not, we might
31 # have to have a bunch of subclasses GNUCCompiler, SGICCompiler,
32 # SunCCompiler, and I suspect down that road lies madness.
33 # * even if we don't know a warning flag from an optimization flag,
34 # we need some way for outsiders to feed preprocessor/compiler/linker
35 # flags in to us -- eg. a sysadmin might want to mandate certain flags
36 # via a site config file, or a user might want to set something for
37 # compiling this module distribution only via the setup.py command
38 # line, whatever. As long as these options come from something on the
39 # current system, they can be as system-dependent as they like, and we
40 # should just happily stuff them into the preprocessor/compiler/linker
41 # options and carry on.
44 class UnixCCompiler (CCompiler
):
46 # XXX perhaps there should really be *three* kinds of include
47 # directories: those built in to the preprocessor, those from Python's
48 # Makefiles, and those supplied to {add,set}_include_dirs(). Currently
49 # we make no distinction between the latter two at this point; it's all
50 # up to the client class to select the include directories to use above
51 # and beyond the compiler's defaults. That is, both the Python include
52 # directories and any module- or package-specific include directories
53 # are specified via {add,set}_include_dirs(), and there's no way to
54 # distinguish them. This might be a bug.
56 compiler_type
= 'unix'
61 _static_lib_ext
= '.a'
67 CCompiler
.__init
__ (self
, verbose
, dry_run
)
69 self
.preprocess_options
= None
70 self
.compile_options
= None
72 # Munge CC and OPT together in case there are flags stuck in CC.
73 # Note that using these variables from sysconfig immediately makes
74 # this module specific to building Python extensions and
75 # inappropriate as a general-purpose C compiler front-end. So sue
76 # me. Note also that we use OPT rather than CFLAGS, because CFLAGS
77 # is the flags used to compile Python itself -- not only are there
78 # -I options in there, they are the *wrong* -I options. We'll
79 # leave selection of include directories up to the class using
82 (self
.cc
, self
.ccflags
) = \
83 _split_command (CC
+ ' ' + OPT
)
84 self
.ccflags_shared
= string
.split (CCSHARED
)
86 (self
.ld_shared
, self
.ldflags_shared
) = \
87 _split_command (LDSHARED
)
98 if output_dir
is None:
99 output_dir
= self
.output_dir
105 if type (macros
) is not ListType
:
107 "'macros' (if supplied) must be a list of tuples"
108 if type (includes
) is not ListType
:
110 "'includes' (if supplied) must be a list of strings"
112 pp_opts
= gen_preprocess_options (self
.macros
+ macros
,
113 self
.include_dirs
+ includes
)
115 # So we can mangle 'sources' without hurting the caller's data
116 orig_sources
= sources
117 sources
= copy (sources
)
119 # Get the list of expected output (object) files and drop files we
120 # don't have to recompile. (Simplistic check -- we just compare the
121 # source and object file, no deep dependency checking involving
122 # header files. Hmmm.)
123 objects
= self
.object_filenames (sources
, output_dir
)
124 skipped
= newer_pairwise (sources
, objects
)
125 for skipped_pair
in skipped
:
126 self
.announce ("skipping %s (%s up-to-date)" % skipped_pair
)
128 # If anything left to compile, compile it
130 # XXX use of ccflags_shared means we're blithely assuming
131 # that we're compiling for inclusion in a shared object!
132 # (will have to fix this when I add the ability to build a
134 cc_args
= ['-c'] + pp_opts
+ \
135 self
.ccflags
+ self
.ccflags_shared
+ \
138 cc_args
[:0] = extra_preargs
140 cc_args
.extend (extra_postargs
)
141 self
.spawn ([self
.cc
] + cc_args
)
144 # Note that compiling multiple source files in the same go like
145 # we've just done drops the .o file in the current directory, which
146 # may not be what the caller wants (depending on the 'output_dir'
147 # parameter). So, if necessary, fix that now by moving the .o
148 # files into the desired output directory. (The alternative, of
149 # course, is to compile one-at-a-time with a -o option. 6 of one,
150 # 12/2 of the other...)
153 for i
in range (len (objects
)):
154 src
= os
.path
.basename (objects
[i
])
155 objects
[i
] = self
.move_file (src
, output_dir
)
157 # Have to re-fetch list of object filenames, because we want to
158 # return *all* of them, including those that weren't recompiled on
160 return self
.object_filenames (orig_sources
, output_dir
)
163 # XXX punting on 'link_static_lib()' for now -- it might be better for
164 # CCompiler to mandate just 'link_binary()' or some such to build a new
165 # Python binary; it would then take care of linking in everything
166 # needed for the new Python without messing with an intermediate static
169 def link_shared_lib (self
,
176 extra_postargs
=None):
177 # XXX should we sanity check the library name? (eg. no
179 self
.link_shared_object (
181 "lib%s%s" % (output_libname
, self
._shared
_lib
_ext
),
189 def link_shared_object (self
,
196 extra_postargs
=None):
198 if output_dir
is None:
199 output_dir
= self
.output_dir
200 if libraries
is None:
202 if library_dirs
is None:
205 lib_opts
= gen_lib_options (self
.library_dirs
+ library_dirs
,
206 self
.libraries
+ libraries
,
208 if output_dir
is not None:
209 output_filename
= os
.path
.join (output_dir
, output_filename
)
211 # If any of the input object files are newer than the output shared
212 # object, relink. Again, this is a simplistic dependency check:
213 # doesn't look at any of the libraries we might be linking with.
214 # Note that we have to dance around errors comparing timestamps if
215 # we're in dry-run mode (yuck).
217 newer
= newer_group (objects
, output_filename
)
225 ld_args
= self
.ldflags_shared
+ lib_opts
+ \
226 objects
+ ['-o', output_filename
]
228 ld_args
[:0] = extra_preargs
230 ld_args
.extend (extra_postargs
)
231 self
.spawn ([self
.ld_shared
] + ld_args
)
233 self
.announce ("skipping %s (up-to-date)" % output_filename
)
236 def object_filenames (self
, source_filenames
, output_dir
=None):
238 for inname
in source_filenames
:
239 outname
= re
.sub (r
'\.(c|C|cc|cxx|cpp)$', self
._obj
_ext
, inname
)
240 outname
= os
.path
.basename (outname
)
241 if output_dir
is not None:
242 outname
= os
.path
.join (output_dir
, outname
)
243 outnames
.append (outname
)
246 def shared_object_filename (self
, source_filename
, output_dir
=None):
247 outname
= re
.sub (r
'\.(c|C|cc|cxx|cpp)$', self
._shared
_lib
_ext
)
248 outname
= os
.path
.basename (outname
)
249 if output_dir
is not None:
250 outname
= os
.path
.join (output_dir
, outname
)
253 def library_filename (self
, libname
):
254 return "lib%s%s" % (libname
, self
._static
_lib
_ext
)
256 def shared_library_filename (self
, libname
):
257 return "lib%s%s" % (libname
, self
._shared
_lib
_ext
)
259 # class UnixCCompiler
262 def _split_command (cmd
):
263 """Split a command string up into the progam to run (a string) and
264 the list of arguments; return them as (cmd, arglist)."""
265 args
= string
.split (cmd
)
266 return (args
[0], args
[1:])