Skip to content

Commit 8037cb1

Browse files
committed
Added 'output_dir' parameter to 'compile()' and 'link_shared_object().
Changed those two methods to only compile/link if necessary (according to simplistic timestamp checks). Added 'output_dir' to 'object_filenames()' and 'shared_object_filename()'.
1 parent 3b120ab commit 8037cb1

1 file changed

Lines changed: 83 additions & 22 deletions

File tree

Lib/distutils/unixccompiler.py

Lines changed: 83 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,13 @@
1717

1818
__rcsid__ = "$Id$"
1919

20-
import string, re
20+
import string, re, os
2121
from types import *
22+
from copy import copy
2223
from sysconfig import \
2324
CC, CCSHARED, CFLAGS, OPT, LDSHARED, LDFLAGS, RANLIB, AR, SO
2425
from 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

Comments
 (0)