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__"
52 import SCons.Environment
57 # A placeholder for a default Environment (for fetching source files
58 # from source code management systems and the like). This must be
59 # initialized later, after the top-level directory is set by the calling
63 # Lazily instantiate the default environment so the overhead of creating
64 # it doesn't apply when it's not needed.
65 def _fetch_DefaultEnvironment(*args, **kw):
67 Returns the already-created default construction environment.
72 def DefaultEnvironment(*args, **kw):
74 Initial public entry point for creating the default construction
77 After creating the environment, we overwrite our name
78 (DefaultEnvironment) with the _fetch_DefaultEnvironment() function,
79 which more efficiently returns the initialized default construction
80 environment without checking for its existence.
82 (This function still exists with its _default_check because someone
83 else (*cough* Script/__init__.py *cough*) may keep a reference
84 to this function. So we can't use the fully functional idiom of
85 having the name originally be a something that *only* creates the
86 construction environment and then overwrites the name.)
91 _default_env = apply(SCons.Environment.Environment, args, kw)
93 _default_env.Decider('MD5')
95 _default_env.Decider('timestamp-match')
96 global DefaultEnvironment
97 DefaultEnvironment = _fetch_DefaultEnvironment
98 _default_env._CacheDir_path = None
101 # Emitters for setting the shared attribute on object files,
102 # and an action for checking that all of the source files
103 # going into a shared library are, in fact, shared.
104 def StaticObjectEmitter(target, source, env):
106 tgt.attributes.shared = None
107 return (target, source)
109 def SharedObjectEmitter(target, source, env):
111 tgt.attributes.shared = 1
112 return (target, source)
114 def SharedFlagChecker(source, target, env):
115 same = env.subst('$STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME')
116 if same == '0' or same == '' or same == 'False':
119 shared = src.attributes.shared
120 except AttributeError:
123 raise SCons.Errors.UserError, "Source file: %s is static and is not compatible with shared target: %s" % (src, target[0])
125 SharedCheck = SCons.Action.Action(SharedFlagChecker, None)
127 # Some people were using these variable name before we made
128 # SourceFileScanner part of the public interface. Don't break their
129 # SConscript files until we've given them some fair warning and a
131 CScan = SCons.Tool.CScanner
132 DScan = SCons.Tool.DScanner
133 LaTeXScan = SCons.Tool.LaTeXScanner
134 ObjSourceScan = SCons.Tool.SourceFileScanner
135 ProgScan = SCons.Tool.ProgramScanner
137 # These aren't really tool scanners, so they don't quite belong with
138 # the rest of those in Tool/__init__.py, but I'm not sure where else
139 # they should go. Leave them here for now.
140 import SCons.Scanner.Dir
141 DirScanner = SCons.Scanner.Dir.DirScanner()
142 DirEntryScanner = SCons.Scanner.Dir.DirEntryScanner()
144 # Actions for common languages.
145 CAction = SCons.Action.Action("$CCCOM", "$CCCOMSTR")
146 ShCAction = SCons.Action.Action("$SHCCCOM", "$SHCCCOMSTR")
147 CXXAction = SCons.Action.Action("$CXXCOM", "$CXXCOMSTR")
148 ShCXXAction = SCons.Action.Action("$SHCXXCOM", "$SHCXXCOMSTR")
150 ASAction = SCons.Action.Action("$ASCOM", "$ASCOMSTR")
151 ASPPAction = SCons.Action.Action("$ASPPCOM", "$ASPPCOMSTR")
153 LinkAction = SCons.Action.Action("$LINKCOM", "$LINKCOMSTR")
154 ShLinkAction = SCons.Action.Action("$SHLINKCOM", "$SHLINKCOMSTR")
156 LdModuleLinkAction = SCons.Action.Action("$LDMODULECOM", "$LDMODULECOMSTR")
158 # Common tasks that we allow users to perform in platform-independent
159 # ways by creating ActionFactory instances.
160 ActionFactory = SCons.Action.ActionFactory
162 def get_paths_str(dest):
163 # If dest is a list, we need to manually call str() on each element
164 if SCons.Util.is_List(dest):
167 elem_strs.append('"' + str(element) + '"')
168 return '[' + string.join(elem_strs, ', ') + ']'
170 return '"' + str(dest) + '"'
172 def chmod_func(dest, mode):
173 SCons.Node.FS.invalidate_node_memos(dest)
174 if not SCons.Util.is_List(dest):
177 os.chmod(str(element), mode)
179 def chmod_strfunc(dest, mode):
180 return 'Chmod(%s, 0%o)' % (get_paths_str(dest), mode)
182 Chmod = ActionFactory(chmod_func, chmod_strfunc)
184 def copy_func(dest, src):
185 SCons.Node.FS.invalidate_node_memos(dest)
186 if SCons.Util.is_List(src) and os.path.isdir(dest):
188 shutil.copy2(file, dest)
190 elif os.path.isfile(src):
191 return shutil.copy2(src, dest)
193 return shutil.copytree(src, dest, 1)
195 Copy = ActionFactory(copy_func,
196 lambda dest, src: 'Copy("%s", "%s")' % (dest, src),
199 def delete_func(dest, must_exist=0):
200 SCons.Node.FS.invalidate_node_memos(dest)
201 if not SCons.Util.is_List(dest):
205 if not must_exist and not os.path.exists(entry):
207 if not os.path.exists(entry) or os.path.isfile(entry):
211 shutil.rmtree(entry, 1)
214 def delete_strfunc(dest, must_exist=0):
215 return 'Delete(%s)' % get_paths_str(dest)
217 Delete = ActionFactory(delete_func, delete_strfunc)
219 def mkdir_func(dest):
220 SCons.Node.FS.invalidate_node_memos(dest)
221 if not SCons.Util.is_List(dest):
225 os.makedirs(str(entry))
228 if (e[0] == errno.EEXIST or (sys.platform=='win32' and e[0]==183)) \
229 and os.path.isdir(str(entry)):
230 pass # not an error if already exists
234 Mkdir = ActionFactory(mkdir_func,
235 lambda dir: 'Mkdir(%s)' % get_paths_str(dir))
237 def move_func(dest, src):
238 SCons.Node.FS.invalidate_node_memos(dest)
239 SCons.Node.FS.invalidate_node_memos(src)
240 shutil.move(src, dest)
242 Move = ActionFactory(move_func,
243 lambda dest, src: 'Move("%s", "%s")' % (dest, src),
246 def touch_func(dest):
247 SCons.Node.FS.invalidate_node_memos(dest)
248 if not SCons.Util.is_List(dest):
252 mtime = int(time.time())
253 if os.path.exists(file):
254 atime = os.path.getatime(file)
258 os.utime(file, (atime, mtime))
260 Touch = ActionFactory(touch_func,
261 lambda file: 'Touch(%s)' % get_paths_str(file))
263 # Internal utility functions
265 def _concat(prefix, list, suffix, env, f=lambda x: x, target=None, source=None):
267 Creates a new list from 'list' by first interpolating each element
268 in the list using the 'env' dictionary and then calling f on the
269 list, and finally calling _concat_ixes to concatenate 'prefix' and
270 'suffix' onto each element of the list.
275 l = f(SCons.PathList.PathList(list).subst_path(env, target, source))
279 return _concat_ixes(prefix, list, suffix, env)
281 def _concat_ixes(prefix, list, suffix, env):
283 Creates a new list from 'list' by concatenating the 'prefix' and
284 'suffix' arguments onto each element of the list. A trailing space
285 on 'prefix' or leading space on 'suffix' will cause them to be put
286 into separate list elements rather than being concatenated.
291 # ensure that prefix and suffix are strings
292 prefix = str(env.subst(prefix, SCons.Subst.SUBST_RAW))
293 suffix = str(env.subst(suffix, SCons.Subst.SUBST_RAW))
296 if isinstance(x, SCons.Node.FS.File):
303 if prefix[-1] == ' ':
304 result.append(prefix[:-1])
305 elif x[:len(prefix)] != prefix:
312 result.append(suffix[1:])
313 elif x[-len(suffix):] != suffix:
314 result[-1] = result[-1]+suffix
318 def _stripixes(prefix, list, suffix, stripprefixes, stripsuffixes, env, c=None):
320 This is a wrapper around _concat()/_concat_ixes() that checks for the
321 existence of prefixes or suffixes on list elements and strips them
322 where it finds them. This is used by tools (like the GNU linker)
323 that need to turn something like 'libfoo.a' into '-lfoo'.
330 env_c = env['_concat']
331 if env_c != _concat and callable(env_c):
332 # There's a custom _concat() method in the construction
333 # environment, and we've allowed people to set that in
334 # the past (see test/custom-concat.py), so preserve the
335 # backwards compatibility.
340 stripprefixes = map(env.subst, SCons.Util.flatten(stripprefixes))
341 stripsuffixes = map(env.subst, SCons.Util.flatten(stripsuffixes))
344 for l in SCons.PathList.PathList(list).subst_path(env, None, None):
345 if isinstance(l, SCons.Node.FS.File):
349 if not SCons.Util.is_String(l):
352 for stripprefix in stripprefixes:
353 lsp = len(stripprefix)
354 if l[:lsp] == stripprefix:
356 # Do not strip more than one prefix
359 for stripsuffix in stripsuffixes:
360 lss = len(stripsuffix)
361 if l[-lss:] == stripsuffix:
363 # Do not strip more than one suffix
368 return c(prefix, stripped, suffix, env)
370 def processDefines(defs):
371 """process defines, resolving strings, lists, dictionaries, into a list of
374 if SCons.Util.is_List(defs):
377 if SCons.Util.is_List(d) or type(d) is types.TupleType:
378 l.append(str(d[0]) + '=' + str(d[1]))
381 elif SCons.Util.is_Dict(defs):
382 # The items in a dictionary are stored in random order, but
383 # if the order of the command-line options changes from
384 # invocation to invocation, then the signature of the command
385 # line will change and we'll get random unnecessary rebuilds.
386 # Consequently, we have to sort the keys to ensure a
387 # consistent order...
396 l.append(str(k) + '=' + str(v))
401 def _defines(prefix, defs, suffix, env, c=_concat_ixes):
402 """A wrapper around _concat_ixes that turns a list or string
403 into a list of C preprocessor command-line definitions.
406 return c(prefix, env.subst_path(processDefines(defs)), suffix, env)
408 class NullCmdGenerator:
409 """This is a callable class that can be used in place of other
410 command generators if you don't want them to do anything.
412 The __call__ method for this class simply returns the thing
413 you instantiated it with.
416 env["DO_NOTHING"] = NullCmdGenerator
417 env["LINKCOM"] = "${DO_NOTHING('$LINK $SOURCES $TARGET')}"
420 def __init__(self, cmd):
423 def __call__(self, target, source, env, for_signature=None):
426 class Variable_Method_Caller:
427 """A class for finding a construction variable on the stack and
428 calling one of its methods.
430 We use this to support "construction variables" in our string
431 eval()s that actually stand in for methods--specifically, use
432 of "RDirs" in call to _concat that should actually execute the
433 "TARGET.RDirs" method. (We used to support this by creating a little
434 "build dictionary" that mapped RDirs to the method, but this got in
435 the way of Memoizing construction environments, because we had to
436 create new environment objects to hold the variables.)
438 def __init__(self, variable, method):
439 self.variable = variable
441 def __call__(self, *args, **kw):
443 except ZeroDivisionError:
444 # Don't start iterating with the current stack-frame to
445 # prevent creating reference cycles (f_back is safe).
446 frame = sys.exc_info()[2].tb_frame.f_back
447 variable = self.variable
449 if frame.f_locals.has_key(variable):
450 v = frame.f_locals[variable]
452 method = getattr(v, self.method)
453 return apply(method, args, kw)
457 ConstructionEnvironment = {
460 'CONFIGUREDIR' : '#/.sconf_temp',
461 'CONFIGURELOG' : '#/config.log',
462 'CPPSUFFIXES' : SCons.Tool.CSuffixes,
463 'DSUFFIXES' : SCons.Tool.DSuffixes,
465 'IDLSUFFIXES' : SCons.Tool.IDLSuffixes,
466 # 'LATEXSUFFIXES' : SCons.Tool.LaTeXSuffixes, # moved to the TeX tools generate functions
468 '_defines' : _defines,
469 '_stripixes' : _stripixes,
470 '_LIBFLAGS' : '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}',
471 '_LIBDIRFLAGS' : '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
472 '_CPPINCFLAGS' : '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
473 '_CPPDEFFLAGS' : '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}',
474 'TEMPFILE' : NullCmdGenerator,
475 'Dir' : Variable_Method_Caller('TARGET', 'Dir'),
476 'Dirs' : Variable_Method_Caller('TARGET', 'Dirs'),
477 'File' : Variable_Method_Caller('TARGET', 'File'),
478 'RDirs' : Variable_Method_Caller('TARGET', 'RDirs'),
483 # indent-tabs-mode:nil
485 # vim: set expandtab tabstop=4 shiftwidth=4: