1717
1818__rcsid__ = "$Id$"
1919
20- import string , re
20+ import string , re , os
2121from types import *
22+ from copy import copy
2223from sysconfig import \
2324 CC , CCSHARED , CFLAGS , OPT , LDSHARED , LDFLAGS , RANLIB , AR , SO
2425from ccompiler import CCompiler , gen_preprocess_options , gen_lib_options
25-
26+ from util import move_file , newer_pairwise , newer_group
2627
2728# XXX Things not currently handled:
2829# * optimization/debug/warning flags; we just use whatever's in Python's
@@ -86,9 +87,12 @@ def __init__ (self,
8687
8788 def compile (self ,
8889 sources ,
90+ output_dir = None ,
8991 macros = None ,
9092 includes = None ):
9193
94+ if output_dir is None :
95+ output_dir = self .output_dir
9296 if macros is None :
9397 macros = []
9498 if includes is None :
@@ -104,15 +108,48 @@ def compile (self,
104108 pp_opts = gen_preprocess_options (self .macros + macros ,
105109 self .include_dirs + includes )
106110
107- # use of ccflags_shared means we're blithely assuming that we're
108- # compiling for inclusion in a shared object! (will have to fix
109- # this when I add the ability to build a new Python)
110- cc_args = ['-c' ] + pp_opts + \
111- self .ccflags + self .ccflags_shared + \
112- sources
111+ # So we can mangle 'sources' without hurting the caller's data
112+ orig_sources = sources
113+ sources = copy (sources )
114+
115+ # Get the list of expected output (object) files and drop files we
116+ # don't have to recompile. (Simplistic check -- we just compare the
117+ # source and object file, no deep dependency checking involving
118+ # header files. Hmmm.)
119+ objects = self .object_filenames (sources , output_dir )
120+ skipped = newer_pairwise (sources , objects )
121+ for skipped_pair in skipped :
122+ self .announce ("skipping %s (%s up-to-date)" % skipped_pair )
123+
124+ # If anything left to compile, compile it
125+ if sources :
126+ # XXX use of ccflags_shared means we're blithely assuming
127+ # that we're compiling for inclusion in a shared object!
128+ # (will have to fix this when I add the ability to build a
129+ # new Python)
130+ cc_args = ['-c' ] + pp_opts + \
131+ self .ccflags + self .ccflags_shared + \
132+ sources
133+ self .spawn ([self .cc ] + cc_args )
134+
113135
114- self .spawn ([self .cc ] + cc_args )
115- return self .object_filenames (sources )
136+ # Note that compiling multiple source files in the same go like
137+ # we've just done drops the .o file in the current directory, which
138+ # may not be what the caller wants (depending on the 'output_dir'
139+ # parameter). So, if necessary, fix that now by moving the .o
140+ # files into the desired output directory. (The alternative, of
141+ # course, is to compile one-at-a-time with a -o option. 6 of one,
142+ # 12/2 of the other...)
143+
144+ if output_dir :
145+ for i in range (len (objects )):
146+ src = os .path .basename (objects [i ])
147+ objects [i ] = self .move_file (src , output_dir )
148+
149+ # Have to re-fetch list of object filenames, because we want to
150+ # return *all* of them, including those that weren't recompiled on
151+ # this call!
152+ return self .object_filenames (orig_sources , output_dir )
116153
117154
118155 # XXX punting on 'link_static_lib()' for now -- it might be better for
@@ -124,23 +161,31 @@ def compile (self,
124161 def link_shared_lib (self ,
125162 objects ,
126163 output_libname ,
164+ output_dir = None ,
127165 libraries = None ,
128166 library_dirs = None ,
129167 build_info = None ):
130168 # XXX should we sanity check the library name? (eg. no
131169 # slashes)
132- self .link_shared_object (objects , "lib%s%s" % \
133- (output_libname , self ._shared_lib_ext ),
134- build_info = build_info )
135-
170+ self .link_shared_object (
171+ objects ,
172+ "lib%s%s" % (output_libname , self ._shared_lib_ext ),
173+ output_dir ,
174+ libraries ,
175+ library_dirs ,
176+ build_info )
177+
136178
137179 def link_shared_object (self ,
138180 objects ,
139181 output_filename ,
182+ output_dir = None ,
140183 libraries = None ,
141184 library_dirs = None ,
142185 build_info = None ):
143186
187+ if output_dir is None :
188+ output_dir = self .output_dir
144189 if libraries is None :
145190 libraries = []
146191 if library_dirs is None :
@@ -151,21 +196,37 @@ def link_shared_object (self,
151196 lib_opts = gen_lib_options (self .libraries + libraries ,
152197 self .library_dirs + library_dirs ,
153198 "-l%s" , "-L%s" )
154- ld_args = self .ldflags_shared + lib_opts + \
155- objects + ['-o' , output_filename ]
199+ if output_dir is not None :
200+ output_filename = os .path .join (output_dir , output_filename )
201+
202+ # If any of the input object files are newer than the output shared
203+ # object, relink. Again, this is a simplistic dependency check:
204+ # doesn't look at any of the libraries we might be linking with.
205+ if newer_group (objects , output_filename ):
206+ ld_args = self .ldflags_shared + lib_opts + \
207+ objects + ['-o' , output_filename ]
156208
157- self .spawn ([self .ld_shared ] + ld_args )
209+ self .spawn ([self .ld_shared ] + ld_args )
210+ else :
211+ self .announce ("skipping %s (up-to-date)" % output_filename )
158212
159213
160- def object_filenames (self , source_filenames ):
214+ def object_filenames (self , source_filenames , output_dir = None ):
161215 outnames = []
162216 for inname in source_filenames :
163- outnames .append ( re .sub (r'\.(c|C|cc|cxx|cpp)$' ,
164- self ._obj_ext , inname ))
217+ outname = re .sub (r'\.(c|C|cc|cxx|cpp)$' , self ._obj_ext , inname )
218+ outname = os .path .basename (outname )
219+ if output_dir is not None :
220+ outname = os .path .join (output_dir , outname )
221+ outnames .append (outname )
165222 return outnames
166223
167- def shared_object_filename (self , source_filename ):
168- return re .sub (r'\.(c|C|cc|cxx|cpp)$' , self ._shared_lib_ext )
224+ def shared_object_filename (self , source_filename , output_dir = None ):
225+ outname = re .sub (r'\.(c|C|cc|cxx|cpp)$' , self ._shared_lib_ext )
226+ outname = os .path .basename (outname )
227+ if output_dir is not None :
228+ outname = os .path .join (output_dir , outname )
229+ return outname
169230
170231 def library_filename (self , libname ):
171232 return "lib%s%s" % (libname , self ._static_lib_ext )
0 commit comments