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__"
50 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 _fetch_DefaultEnvironment(*args, **kw):
65 Returns the already-created default construction environment.
70 def DefaultEnvironment(*args, **kw):
72 Initial public entry point for creating the default construction
75 After creating the environment, we overwrite our name
76 (DefaultEnvironment) with the _fetch_DefaultEnvironment() function,
77 which more efficiently returns the initialized default construction
78 environment without checking for its existence.
80 (This function still exists with its _default_check because someone
81 else (*cough* Script/__init__.py *cough*) may keep a reference
82 to this function. So we can't use the fully functional idiom of
83 having the name originally be a something that *only* creates the
84 construction environment and then overwrites the name.)
89 _default_env = apply(SCons.Environment.Environment, args, kw)
90 _default_env.TargetSignatures('source')
92 _default_env.SourceSignatures('MD5')
94 _default_env.SourceSignatures('timestamp')
95 global DefaultEnvironment
96 DefaultEnvironment = _fetch_DefaultEnvironment
97 _default_env._CacheDir = SCons.CacheDir.Null()
100 # Emitters for setting the shared attribute on object files,
101 # and an action for checking that all of the source files
102 # going into a shared library are, in fact, shared.
103 def StaticObjectEmitter(target, source, env):
105 tgt.attributes.shared = None
106 return (target, source)
108 def SharedObjectEmitter(target, source, env):
110 tgt.attributes.shared = 1
111 return (target, source)
113 def SharedFlagChecker(source, target, env):
114 same = env.subst('$STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME')
115 if same == '0' or same == '' or same == 'False':
118 shared = src.attributes.shared
119 except AttributeError:
122 raise SCons.Errors.UserError, "Source file: %s is static and is not compatible with shared target: %s" % (src, target[0])
124 SharedCheck = SCons.Action.Action(SharedFlagChecker, None)
126 # Some people were using these variable name before we made
127 # SourceFileScanner part of the public interface. Don't break their
128 # SConscript files until we've given them some fair warning and a
130 CScan = SCons.Tool.CScanner
131 DScan = SCons.Tool.DScanner
132 LaTeXScan = SCons.Tool.LaTeXScanner
133 ObjSourceScan = SCons.Tool.SourceFileScanner
134 ProgScan = SCons.Tool.ProgramScanner
136 # These aren't really tool scanners, so they don't quite belong with
137 # the rest of those in Tool/__init__.py, but I'm not sure where else
138 # they should go. Leave them here for now.
139 import SCons.Scanner.Dir
140 DirScanner = SCons.Scanner.Dir.DirScanner()
141 DirEntryScanner = SCons.Scanner.Dir.DirEntryScanner()
143 # Actions for common languages.
144 CAction = SCons.Action.Action("$CCCOM", "$CCCOMSTR")
145 ShCAction = SCons.Action.Action("$SHCCCOM", "$SHCCCOMSTR")
146 CXXAction = SCons.Action.Action("$CXXCOM", "$CXXCOMSTR")
147 ShCXXAction = SCons.Action.Action("$SHCXXCOM", "$SHCXXCOMSTR")
149 ASAction = SCons.Action.Action("$ASCOM", "$ASCOMSTR")
150 ASPPAction = SCons.Action.Action("$ASPPCOM", "$ASPPCOMSTR")
152 LinkAction = SCons.Action.Action("$LINKCOM", "$LINKCOMSTR")
153 ShLinkAction = SCons.Action.Action("$SHLINKCOM", "$SHLINKCOMSTR")
155 LdModuleLinkAction = SCons.Action.Action("$LDMODULECOM", "$LDMODULECOMSTR")
157 # Common tasks that we allow users to perform in platform-independent
158 # ways by creating ActionFactory instances.
159 ActionFactory = SCons.Action.ActionFactory
161 Chmod = ActionFactory(os.chmod,
162 lambda dest, mode: 'Chmod("%s", 0%o)' % (dest, mode))
164 def copy_func(dest, src):
165 if SCons.Util.is_List(src) and os.path.isdir(dest):
167 shutil.copy(file, dest)
169 elif os.path.isfile(src):
170 return shutil.copy(src, dest)
172 return shutil.copytree(src, dest, 1)
174 Copy = ActionFactory(copy_func,
175 lambda dest, src: 'Copy("%s", "%s")' % (dest, src))
177 def delete_func(entry, must_exist=0):
178 if not must_exist and not os.path.exists(entry):
180 if not os.path.exists(entry) or os.path.isfile(entry):
181 return os.unlink(entry)
183 return shutil.rmtree(entry, 1)
185 def delete_strfunc(entry, must_exist=0):
186 return 'Delete("%s")' % entry
188 Delete = ActionFactory(delete_func, delete_strfunc)
190 Mkdir = ActionFactory(os.makedirs,
191 lambda dir: 'Mkdir("%s")' % dir)
193 Move = ActionFactory(lambda dest, src: os.rename(src, dest),
194 lambda dest, src: 'Move("%s", "%s")' % (dest, src))
196 def touch_func(file):
197 mtime = int(time.time())
198 if os.path.exists(file):
199 atime = os.path.getatime(file)
203 return os.utime(file, (atime, mtime))
205 Touch = ActionFactory(touch_func,
206 lambda file: 'Touch("%s")' % file)
208 # Internal utility functions
210 def _concat(prefix, list, suffix, env, f=lambda x: x, target=None, source=None):
212 Creates a new list from 'list' by first interpolating each element
213 in the list using the 'env' dictionary and then calling f on the
214 list, and finally calling _concat_ixes to concatenate 'prefix' and
215 'suffix' onto each element of the list.
220 if SCons.Util.is_List(list):
221 list = SCons.Util.flatten(list)
223 l = f(SCons.PathList.PathList(list).subst_path(env, target, source))
227 return _concat_ixes(prefix, list, suffix, env)
229 def _concat_ixes(prefix, list, suffix, env):
231 Creates a new list from 'list' by concatenating the 'prefix' and
232 'suffix' arguments onto each element of the list. A trailing space
233 on 'prefix' or leading space on 'suffix' will cause them to be put
234 into separate list elements rather than being concatenated.
239 # ensure that prefix and suffix are strings
240 prefix = str(env.subst(prefix, SCons.Subst.SUBST_RAW))
241 suffix = str(env.subst(suffix, SCons.Subst.SUBST_RAW))
244 if isinstance(x, SCons.Node.FS.File):
251 if prefix[-1] == ' ':
252 result.append(prefix[:-1])
253 elif x[:len(prefix)] != prefix:
260 result.append(suffix[1:])
261 elif x[-len(suffix):] != suffix:
262 result[-1] = result[-1]+suffix
266 def _stripixes(prefix, list, suffix, stripprefix, stripsuffix, env, c=None):
268 This is a wrapper around _concat()/_concat_ixes() that checks for the
269 existence of prefixes or suffixes on list elements and strips them
270 where it finds them. This is used by tools (like the GNU linker)
271 that need to turn something like 'libfoo.a' into '-lfoo'.
278 env_c = env['_concat']
279 if env_c != _concat and callable(env_c):
280 # There's a custom _concat() method in the construction
281 # environment, and we've allowed people to set that in
282 # the past (see test/custom-concat.py), so preserve the
283 # backwards compatibility.
288 if SCons.Util.is_List(list):
289 list = SCons.Util.flatten(list)
291 lsp = len(stripprefix)
292 lss = len(stripsuffix)
294 for l in SCons.PathList.PathList(list).subst_path(env, None, None):
295 if isinstance(l, SCons.Node.FS.File):
298 if not SCons.Util.is_String(l):
300 if l[:lsp] == stripprefix:
302 if l[-lss:] == stripsuffix:
306 return c(prefix, stripped, suffix, env)
308 def _defines(prefix, defs, suffix, env, c=_concat_ixes):
309 """A wrapper around _concat_ixes that turns a list or string
310 into a list of C preprocessor command-line definitions.
312 if SCons.Util.is_List(defs):
315 if SCons.Util.is_List(d) or type(d) is types.TupleType:
316 l.append(str(d[0]) + '=' + str(d[1]))
319 elif SCons.Util.is_Dict(defs):
320 # The items in a dictionary are stored in random order, but
321 # if the order of the command-line options changes from
322 # invocation to invocation, then the signature of the command
323 # line will change and we'll get random unnecessary rebuilds.
324 # Consequently, we have to sort the keys to ensure a
325 # consistent order...
334 l.append(str(k) + '=' + str(v))
337 return c(prefix, env.subst_path(l), suffix, env)
339 class NullCmdGenerator:
340 """This is a callable class that can be used in place of other
341 command generators if you don't want them to do anything.
343 The __call__ method for this class simply returns the thing
344 you instantiated it with.
347 env["DO_NOTHING"] = NullCmdGenerator
348 env["LINKCOM"] = "${DO_NOTHING('$LINK $SOURCES $TARGET')}"
351 def __init__(self, cmd):
354 def __call__(self, target, source, env, for_signature=None):
357 class Variable_Method_Caller:
358 """A class for finding a construction variable on the stack and
359 calling one of its methods.
361 We use this to support "construction variables" in our string
362 eval()s that actually stand in for methods--specifically, use
363 of "RDirs" in call to _concat that should actually execute the
364 "TARGET.RDirs" method. (We used to support this by creating a little
365 "build dictionary" that mapped RDirs to the method, but this got in
366 the way of Memoizing construction environments, because we had to
367 create new environment objects to hold the variables.)
369 def __init__(self, variable, method):
370 self.variable = variable
372 def __call__(self, *args, **kw):
374 except ZeroDivisionError: frame = sys.exc_info()[2].tb_frame
375 variable = self.variable
377 if frame.f_locals.has_key(variable):
378 v = frame.f_locals[variable]
380 method = getattr(v, self.method)
381 return apply(method, args, kw)
385 ConstructionEnvironment = {
388 'CONFIGUREDIR' : '#/.sconf_temp',
389 'CONFIGURELOG' : '#/config.log',
390 'CPPSUFFIXES' : SCons.Tool.CSuffixes,
391 'DSUFFIXES' : SCons.Tool.DSuffixes,
393 'IDLSUFFIXES' : SCons.Tool.IDLSuffixes,
394 'LATEXSUFFIXES' : SCons.Tool.LaTeXSuffixes,
396 '_defines' : _defines,
397 '_stripixes' : _stripixes,
398 '_LIBFLAGS' : '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}',
399 '_LIBDIRFLAGS' : '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
400 '_CPPINCFLAGS' : '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
401 '_CPPDEFFLAGS' : '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}',
402 'TEMPFILE' : NullCmdGenerator,
403 'Dir' : Variable_Method_Caller('TARGET', 'Dir'),
404 'Dirs' : Variable_Method_Caller('TARGET', 'Dirs'),
405 'File' : Variable_Method_Caller('TARGET', 'File'),
406 'RDirs' : Variable_Method_Caller('TARGET', 'RDirs'),