3 Builders and other things for the local site. Here's where we'll
4 duplicate the functionality of autoconf until we move it into the
5 installation procedure or use something like qmconf.
7 The code that reads the registry to find MSVC components was borrowed
8 from distutils.msvccompiler.
15 # Permission is hereby granted, free of charge, to any person obtaining
16 # a copy of this software and associated documentation files (the
17 # "Software"), to deal in the Software without restriction, including
18 # without limitation the rights to use, copy, modify, merge, publish,
19 # distribute, sublicense, and/or sell copies of the Software, and to
20 # permit persons to whom the Software is furnished to do so, subject to
21 # the following conditions:
23 # The above copyright notice and this permission notice shall be included
24 # in all copies or substantial portions of the Software.
26 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
27 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
28 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
49 import SCons.Environment
55 # A placeholder for a default Environment (for fetching source files
56 # from source code management systems and the like). This must be
57 # initialized later, after the top-level directory is set by the calling
61 # Lazily instantiate the default environment so the overhead of creating
62 # it doesn't apply when it's not needed.
63 def DefaultEnvironment(*args, **kw):
66 _default_env = apply(SCons.Environment.Environment, args, kw)
67 _default_env._build_signature = 1
68 _default_env._calc_module = SCons.Sig.default_module
71 # Emitters for setting the shared attribute on object files,
72 # and an action for checking that all of the source files
73 # going into a shared library are, in fact, shared.
74 def StaticObjectEmitter(target, source, env):
76 tgt.attributes.shared = None
77 return (target, source)
79 def SharedObjectEmitter(target, source, env):
81 tgt.attributes.shared = 1
82 return (target, source)
84 def SharedFlagChecker(source, target, env):
85 same = env.subst('$STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME')
86 if same == '0' or same == '' or same == 'False':
89 shared = src.attributes.shared
90 except AttributeError:
93 raise SCons.Errors.UserError, "Source file: %s is static and is not compatible with shared target: %s" % (src, target[0])
95 SharedCheck = SCons.Action.Action(SharedFlagChecker, None)
97 # Some people were using these variable name before we made
98 # SourceFileScanner part of the public interface. Don't break their
99 # SConscript files until we've given them some fair warning and a
101 CScan = SCons.Tool.CScanner
102 DScan = SCons.Tool.DScanner
103 LaTeXScan = SCons.Tool.LaTeXScanner
104 ObjSourceScan = SCons.Tool.SourceFileScanner
105 ProgScan = SCons.Tool.ProgramScanner
107 # This isn't really a tool scanner, so it doesn't quite belong with
108 # the rest of those in Tool/__init__.py, but I'm not sure where else it
109 # should go. Leave it here for now.
110 import SCons.Scanner.Dir
111 DirScanner = SCons.Scanner.Dir.DirScanner()
112 DirEntryScanner = SCons.Scanner.Dir.DirEntryScanner()
114 # Actions for common languages.
115 CAction = SCons.Action.Action("$CCCOM", "$CCCOMSTR")
116 ShCAction = SCons.Action.Action("$SHCCCOM", "$SHCCCOMSTR")
117 CXXAction = SCons.Action.Action("$CXXCOM", "$CXXCOMSTR")
118 ShCXXAction = SCons.Action.Action("$SHCXXCOM", "$SHCXXCOMSTR")
120 ASAction = SCons.Action.Action("$ASCOM", "$ASCOMSTR")
121 ASPPAction = SCons.Action.Action("$ASPPCOM", "$ASPPCOMSTR")
123 LinkAction = SCons.Action.Action("$LINKCOM", "$LINKCOMSTR")
124 ShLinkAction = SCons.Action.Action("$SHLINKCOM", "$SHLINKCOMSTR")
126 LdModuleLinkAction = SCons.Action.Action("$LDMODULECOM", "$LDMODULECOMSTR")
128 # Common tasks that we allow users to perform in platform-independent
129 # ways by creating ActionFactory instances.
130 ActionFactory = SCons.Action.ActionFactory
132 Chmod = ActionFactory(os.chmod,
133 lambda dest, mode: 'Chmod("%s", 0%o)' % (dest, mode))
135 def copy_func(dest, src):
136 if os.path.isfile(src):
137 return shutil.copy(src, dest)
139 return shutil.copytree(src, dest, 1)
141 Copy = ActionFactory(copy_func,
142 lambda dest, src: 'Copy("%s", "%s")' % (dest, src))
144 def delete_func(entry, must_exist=0):
145 if not must_exist and not os.path.exists(entry):
147 if not os.path.exists(entry) or os.path.isfile(entry):
148 return os.unlink(entry)
150 return shutil.rmtree(entry, 1)
152 def delete_strfunc(entry, must_exist=0):
153 return 'Delete("%s")' % entry
155 Delete = ActionFactory(delete_func, delete_strfunc)
157 Mkdir = ActionFactory(os.makedirs,
158 lambda dir: 'Mkdir("%s")' % dir)
160 Move = ActionFactory(lambda dest, src: os.rename(src, dest),
161 lambda dest, src: 'Move("%s", "%s")' % (dest, src))
163 def touch_func(file):
164 mtime = int(time.time())
165 if os.path.exists(file):
166 atime = os.path.getatime(file)
170 return os.utime(file, (atime, mtime))
172 Touch = ActionFactory(touch_func,
173 lambda file: 'Touch("%s")' % file)
175 # Internal utility functions
176 def installFunc(dest, source, env):
177 """Install a source file or directory into a destination by copying,
178 (including copying permission/mode bits)."""
180 if os.path.isdir(source):
181 if os.path.exists(dest):
182 if not os.path.isdir(dest):
183 raise SCons.Errors.UserError, "cannot overwrite non-directory `%s' with a directory `%s'" % (str(dest), str(source))
185 parent = os.path.split(dest)[0]
186 if not os.path.exists(parent):
188 shutil.copytree(source, dest)
190 shutil.copy2(source, dest)
192 os.chmod(dest, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
196 def installStr(dest, source, env):
198 if os.path.isdir(source):
202 return 'Install %s: "%s" as "%s"' % (type, source, dest)
204 def _concat(prefix, list, suffix, env, f=lambda x: x, target=None, source=None):
206 Creates a new list from 'list' by first interpolating each element
207 in the list using the 'env' dictionary and then calling f on the
208 list, and finally calling _concat_ixes to concatenate 'prefix' and
209 'suffix' onto each element of the list.
214 if SCons.Util.is_List(list):
215 list = SCons.Util.flatten(list)
217 l = f(SCons.PathList.PathList(list).subst_path(env, target, source))
221 return _concat_ixes(prefix, list, suffix, env)
223 def _concat_ixes(prefix, list, suffix, env):
225 Creates a new list from 'list' by concatenating the 'prefix' and
226 'suffix' arguments onto each element of the list. A trailing space
227 on 'prefix' or leading space on 'suffix' will cause them to be put
228 into separate list elements rather than being concatenated.
233 # ensure that prefix and suffix are strings
234 prefix = str(env.subst(prefix, SCons.Subst.SUBST_RAW))
235 suffix = str(env.subst(suffix, SCons.Subst.SUBST_RAW))
238 if isinstance(x, SCons.Node.FS.File):
245 if prefix[-1] == ' ':
246 result.append(prefix[:-1])
247 elif x[:len(prefix)] != prefix:
254 result.append(suffix[1:])
255 elif x[-len(suffix):] != suffix:
256 result[-1] = result[-1]+suffix
260 def _stripixes(prefix, list, suffix, stripprefix, stripsuffix, env, c=None):
261 """This is a wrapper around _concat() that checks for the existence
262 of prefixes or suffixes on list elements and strips them where it
263 finds them. This is used by tools (like the GNU linker) that need
264 to turn something like 'libfoo.a' into '-lfoo'."""
267 if callable(env["_concat"]):
271 def f(list, sp=stripprefix, ss=stripsuffix):
274 if isinstance(l, SCons.Node.FS.File):
277 if not SCons.Util.is_String(l):
279 if l[:len(sp)] == sp:
281 if l[-len(ss):] == ss:
285 return c(prefix, list, suffix, env, f)
287 # This is an alternate _stripixes() function that passes all of our tests
288 # (as of 21 February 2007), like the current version above. It's more
289 # straightforward because it does its manipulation directly, not using
290 # the funky f call-back function to _concat(). (In this respect it's
291 # like the updated _defines() function below.)
293 # The most convoluted thing is that it still uses a custom _concat()
294 # function if one was placed in the construction environment; there's
295 # a specific test for that functionality, but it might be worth getting
298 # Since this work was done while trying to get 0.97 out the door
299 # (just prior to 0.96.96), I decided to be cautious and leave the old
300 # function as is, to minimize the chance of other corner-case regressions.
301 # The updated version is captured here so we can uncomment it and start
302 # using it at a less sensitive time in the development cycle (or when
303 # it's clearly required to fix something).
305 #def _stripixes(prefix, list, suffix, stripprefix, stripsuffix, env, c=None):
307 # This is a wrapper around _concat()/_concat_ixes() that checks for the
308 # existence of prefixes or suffixes on list elements and strips them
309 # where it finds them. This is used by tools (like the GNU linker)
310 # that need to turn something like 'libfoo.a' into '-lfoo'.
316 # if not callable(c):
317 # env_c = env['_concat']
318 # if env_c != _concat and callable(env_c):
319 # # There's a custom _concat() method in the construction
320 # # environment, and we've allowed people to set that in
321 # # the past (see test/custom-concat.py), so preserve the
322 # # backwards compatibility.
327 # if SCons.Util.is_List(list):
328 # list = SCons.Util.flatten(list)
330 # lsp = len(stripprefix)
331 # lss = len(stripsuffix)
333 # for l in SCons.PathList.PathList(list).subst_path(env, None, None):
334 # if isinstance(l, SCons.Node.FS.File):
337 # if not SCons.Util.is_String(l):
339 # if l[:lsp] == stripprefix:
341 # if l[-lss:] == stripsuffix:
345 # return c(prefix, stripped, suffix, env)
347 def _defines(prefix, defs, suffix, env, c=_concat_ixes):
348 """A wrapper around _concat_ixes that turns a list or string
349 into a list of C preprocessor command-line definitions.
351 if SCons.Util.is_List(defs):
354 if SCons.Util.is_List(d) or type(d) is types.TupleType:
355 l.append(str(d[0]) + '=' + str(d[1]))
358 elif SCons.Util.is_Dict(defs):
359 # The items in a dictionary are stored in random order, but
360 # if the order of the command-line options changes from
361 # invocation to invocation, then the signature of the command
362 # line will change and we'll get random unnecessary rebuilds.
363 # Consequently, we have to sort the keys to ensure a
364 # consistent order...
373 l.append(str(k) + '=' + str(v))
376 return c(prefix, env.subst_path(l), suffix, env)
378 class NullCmdGenerator:
379 """This is a callable class that can be used in place of other
380 command generators if you don't want them to do anything.
382 The __call__ method for this class simply returns the thing
383 you instantiated it with.
386 env["DO_NOTHING"] = NullCmdGenerator
387 env["LINKCOM"] = "${DO_NOTHING('$LINK $SOURCES $TARGET')}"
390 def __init__(self, cmd):
393 def __call__(self, target, source, env, for_signature=None):
396 class Variable_Method_Caller:
397 """A class for finding a construction variable on the stack and
398 calling one of its methods.
400 We use this to support "construction variables" in our string
401 eval()s that actually stand in for methods--specifically, use
402 of "RDirs" in call to _concat that should actually execute the
403 "TARGET.RDirs" method. (We used to support this by creating a little
404 "build dictionary" that mapped RDirs to the method, but this got in
405 the way of Memoizing construction environments, because we had to
406 create new environment objects to hold the variables.)
408 def __init__(self, variable, method):
409 self.variable = variable
411 def __call__(self, *args, **kw):
413 except ZeroDivisionError: frame = sys.exc_info()[2].tb_frame
414 variable = self.variable
416 if frame.f_locals.has_key(variable):
417 v = frame.f_locals[variable]
419 method = getattr(v, self.method)
420 return apply(method, args, kw)
424 ConstructionEnvironment = {
427 'CONFIGUREDIR' : '#/.sconf_temp',
428 'CONFIGURELOG' : '#/config.log',
429 'CPPSUFFIXES' : SCons.Tool.CSuffixes,
430 'DSUFFIXES' : SCons.Tool.DSuffixes,
432 'IDLSUFFIXES' : SCons.Tool.IDLSuffixes,
433 'INSTALL' : installFunc,
434 'INSTALLSTR' : installStr,
435 '_installStr' : installStr,
436 'LATEXSUFFIXES' : SCons.Tool.LaTeXSuffixes,
438 '_defines' : _defines,
439 '_stripixes' : _stripixes,
440 '_LIBFLAGS' : '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}',
441 '_LIBDIRFLAGS' : '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
442 '_CPPINCFLAGS' : '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
443 '_CPPDEFFLAGS' : '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}',
444 'TEMPFILE' : NullCmdGenerator,
445 'Dir' : Variable_Method_Caller('TARGET', 'Dir'),
446 'Dirs' : Variable_Method_Caller('TARGET', 'Dirs'),
447 'File' : Variable_Method_Caller('TARGET', 'File'),
448 'RDirs' : Variable_Method_Caller('TARGET', 'RDirs'),