| Index: scons-2.0.1/engine/SCons/Defaults.py
|
| ===================================================================
|
| --- scons-2.0.1/engine/SCons/Defaults.py (revision 0)
|
| +++ scons-2.0.1/engine/SCons/Defaults.py (revision 0)
|
| @@ -0,0 +1,480 @@
|
| +"""SCons.Defaults
|
| +
|
| +Builders and other things for the local site. Here's where we'll
|
| +duplicate the functionality of autoconf until we move it into the
|
| +installation procedure or use something like qmconf.
|
| +
|
| +The code that reads the registry to find MSVC components was borrowed
|
| +from distutils.msvccompiler.
|
| +
|
| +"""
|
| +
|
| +#
|
| +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation
|
| +#
|
| +# Permission is hereby granted, free of charge, to any person obtaining
|
| +# a copy of this software and associated documentation files (the
|
| +# "Software"), to deal in the Software without restriction, including
|
| +# without limitation the rights to use, copy, modify, merge, publish,
|
| +# distribute, sublicense, and/or sell copies of the Software, and to
|
| +# permit persons to whom the Software is furnished to do so, subject to
|
| +# the following conditions:
|
| +#
|
| +# The above copyright notice and this permission notice shall be included
|
| +# in all copies or substantial portions of the Software.
|
| +#
|
| +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
| +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
| +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
| +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
| +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
| +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
| +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
| +#
|
| +from __future__ import division
|
| +
|
| +__revision__ = "src/engine/SCons/Defaults.py 5134 2010/08/16 23:02:40 bdeegan"
|
| +
|
| +
|
| +import os
|
| +import errno
|
| +import shutil
|
| +import stat
|
| +import time
|
| +import sys
|
| +
|
| +import SCons.Action
|
| +import SCons.Builder
|
| +import SCons.CacheDir
|
| +import SCons.Environment
|
| +import SCons.PathList
|
| +import SCons.Subst
|
| +import SCons.Tool
|
| +
|
| +# A placeholder for a default Environment (for fetching source files
|
| +# from source code management systems and the like). This must be
|
| +# initialized later, after the top-level directory is set by the calling
|
| +# interface.
|
| +_default_env = None
|
| +
|
| +# Lazily instantiate the default environment so the overhead of creating
|
| +# it doesn't apply when it's not needed.
|
| +def _fetch_DefaultEnvironment(*args, **kw):
|
| + """
|
| + Returns the already-created default construction environment.
|
| + """
|
| + global _default_env
|
| + return _default_env
|
| +
|
| +def DefaultEnvironment(*args, **kw):
|
| + """
|
| + Initial public entry point for creating the default construction
|
| + Environment.
|
| +
|
| + After creating the environment, we overwrite our name
|
| + (DefaultEnvironment) with the _fetch_DefaultEnvironment() function,
|
| + which more efficiently returns the initialized default construction
|
| + environment without checking for its existence.
|
| +
|
| + (This function still exists with its _default_check because someone
|
| + else (*cough* Script/__init__.py *cough*) may keep a reference
|
| + to this function. So we can't use the fully functional idiom of
|
| + having the name originally be a something that *only* creates the
|
| + construction environment and then overwrites the name.)
|
| + """
|
| + global _default_env
|
| + if not _default_env:
|
| + import SCons.Util
|
| + _default_env = SCons.Environment.Environment(*args, **kw)
|
| + if SCons.Util.md5:
|
| + _default_env.Decider('MD5')
|
| + else:
|
| + _default_env.Decider('timestamp-match')
|
| + global DefaultEnvironment
|
| + DefaultEnvironment = _fetch_DefaultEnvironment
|
| + _default_env._CacheDir_path = None
|
| + return _default_env
|
| +
|
| +# Emitters for setting the shared attribute on object files,
|
| +# and an action for checking that all of the source files
|
| +# going into a shared library are, in fact, shared.
|
| +def StaticObjectEmitter(target, source, env):
|
| + for tgt in target:
|
| + tgt.attributes.shared = None
|
| + return (target, source)
|
| +
|
| +def SharedObjectEmitter(target, source, env):
|
| + for tgt in target:
|
| + tgt.attributes.shared = 1
|
| + return (target, source)
|
| +
|
| +def SharedFlagChecker(source, target, env):
|
| + same = env.subst('$STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME')
|
| + if same == '0' or same == '' or same == 'False':
|
| + for src in source:
|
| + try:
|
| + shared = src.attributes.shared
|
| + except AttributeError:
|
| + shared = None
|
| + if not shared:
|
| + raise SCons.Errors.UserError("Source file: %s is static and is not compatible with shared target: %s" % (src, target[0]))
|
| +
|
| +SharedCheck = SCons.Action.Action(SharedFlagChecker, None)
|
| +
|
| +# Some people were using these variable name before we made
|
| +# SourceFileScanner part of the public interface. Don't break their
|
| +# SConscript files until we've given them some fair warning and a
|
| +# transition period.
|
| +CScan = SCons.Tool.CScanner
|
| +DScan = SCons.Tool.DScanner
|
| +LaTeXScan = SCons.Tool.LaTeXScanner
|
| +ObjSourceScan = SCons.Tool.SourceFileScanner
|
| +ProgScan = SCons.Tool.ProgramScanner
|
| +
|
| +# These aren't really tool scanners, so they don't quite belong with
|
| +# the rest of those in Tool/__init__.py, but I'm not sure where else
|
| +# they should go. Leave them here for now.
|
| +import SCons.Scanner.Dir
|
| +DirScanner = SCons.Scanner.Dir.DirScanner()
|
| +DirEntryScanner = SCons.Scanner.Dir.DirEntryScanner()
|
| +
|
| +# Actions for common languages.
|
| +CAction = SCons.Action.Action("$CCCOM", "$CCCOMSTR")
|
| +ShCAction = SCons.Action.Action("$SHCCCOM", "$SHCCCOMSTR")
|
| +CXXAction = SCons.Action.Action("$CXXCOM", "$CXXCOMSTR")
|
| +ShCXXAction = SCons.Action.Action("$SHCXXCOM", "$SHCXXCOMSTR")
|
| +
|
| +ASAction = SCons.Action.Action("$ASCOM", "$ASCOMSTR")
|
| +ASPPAction = SCons.Action.Action("$ASPPCOM", "$ASPPCOMSTR")
|
| +
|
| +LinkAction = SCons.Action.Action("$LINKCOM", "$LINKCOMSTR")
|
| +ShLinkAction = SCons.Action.Action("$SHLINKCOM", "$SHLINKCOMSTR")
|
| +
|
| +LdModuleLinkAction = SCons.Action.Action("$LDMODULECOM", "$LDMODULECOMSTR")
|
| +
|
| +# Common tasks that we allow users to perform in platform-independent
|
| +# ways by creating ActionFactory instances.
|
| +ActionFactory = SCons.Action.ActionFactory
|
| +
|
| +def get_paths_str(dest):
|
| + # If dest is a list, we need to manually call str() on each element
|
| + if SCons.Util.is_List(dest):
|
| + elem_strs = []
|
| + for element in dest:
|
| + elem_strs.append('"' + str(element) + '"')
|
| + return '[' + ', '.join(elem_strs) + ']'
|
| + else:
|
| + return '"' + str(dest) + '"'
|
| +
|
| +def chmod_func(dest, mode):
|
| + SCons.Node.FS.invalidate_node_memos(dest)
|
| + if not SCons.Util.is_List(dest):
|
| + dest = [dest]
|
| + for element in dest:
|
| + os.chmod(str(element), mode)
|
| +
|
| +def chmod_strfunc(dest, mode):
|
| + return 'Chmod(%s, 0%o)' % (get_paths_str(dest), mode)
|
| +
|
| +Chmod = ActionFactory(chmod_func, chmod_strfunc)
|
| +
|
| +def copy_func(dest, src):
|
| + SCons.Node.FS.invalidate_node_memos(dest)
|
| + if SCons.Util.is_List(src) and os.path.isdir(dest):
|
| + for file in src:
|
| + shutil.copy2(file, dest)
|
| + return 0
|
| + elif os.path.isfile(src):
|
| + return shutil.copy2(src, dest)
|
| + else:
|
| + return shutil.copytree(src, dest, 1)
|
| +
|
| +Copy = ActionFactory(copy_func,
|
| + lambda dest, src: 'Copy("%s", "%s")' % (dest, src),
|
| + convert=str)
|
| +
|
| +def delete_func(dest, must_exist=0):
|
| + SCons.Node.FS.invalidate_node_memos(dest)
|
| + if not SCons.Util.is_List(dest):
|
| + dest = [dest]
|
| + for entry in dest:
|
| + entry = str(entry)
|
| + if not must_exist and not os.path.exists(entry):
|
| + continue
|
| + if not os.path.exists(entry) or os.path.isfile(entry):
|
| + os.unlink(entry)
|
| + continue
|
| + else:
|
| + shutil.rmtree(entry, 1)
|
| + continue
|
| +
|
| +def delete_strfunc(dest, must_exist=0):
|
| + return 'Delete(%s)' % get_paths_str(dest)
|
| +
|
| +Delete = ActionFactory(delete_func, delete_strfunc)
|
| +
|
| +def mkdir_func(dest):
|
| + SCons.Node.FS.invalidate_node_memos(dest)
|
| + if not SCons.Util.is_List(dest):
|
| + dest = [dest]
|
| + for entry in dest:
|
| + try:
|
| + os.makedirs(str(entry))
|
| + except os.error, e:
|
| + p = str(entry)
|
| + if (e.args[0] == errno.EEXIST or
|
| + (sys.platform=='win32' and e.args[0]==183)) \
|
| + and os.path.isdir(str(entry)):
|
| + pass # not an error if already exists
|
| + else:
|
| + raise
|
| +
|
| +Mkdir = ActionFactory(mkdir_func,
|
| + lambda dir: 'Mkdir(%s)' % get_paths_str(dir))
|
| +
|
| +def move_func(dest, src):
|
| + SCons.Node.FS.invalidate_node_memos(dest)
|
| + SCons.Node.FS.invalidate_node_memos(src)
|
| + shutil.move(src, dest)
|
| +
|
| +Move = ActionFactory(move_func,
|
| + lambda dest, src: 'Move("%s", "%s")' % (dest, src),
|
| + convert=str)
|
| +
|
| +def touch_func(dest):
|
| + SCons.Node.FS.invalidate_node_memos(dest)
|
| + if not SCons.Util.is_List(dest):
|
| + dest = [dest]
|
| + for file in dest:
|
| + file = str(file)
|
| + mtime = int(time.time())
|
| + if os.path.exists(file):
|
| + atime = os.path.getatime(file)
|
| + else:
|
| + open(file, 'w')
|
| + atime = mtime
|
| + os.utime(file, (atime, mtime))
|
| +
|
| +Touch = ActionFactory(touch_func,
|
| + lambda file: 'Touch(%s)' % get_paths_str(file))
|
| +
|
| +# Internal utility functions
|
| +
|
| +def _concat(prefix, list, suffix, env, f=lambda x: x, target=None, source=None):
|
| + """
|
| + Creates a new list from 'list' by first interpolating each element
|
| + in the list using the 'env' dictionary and then calling f on the
|
| + list, and finally calling _concat_ixes to concatenate 'prefix' and
|
| + 'suffix' onto each element of the list.
|
| + """
|
| + if not list:
|
| + return list
|
| +
|
| + l = f(SCons.PathList.PathList(list).subst_path(env, target, source))
|
| + if l is not None:
|
| + list = l
|
| +
|
| + return _concat_ixes(prefix, list, suffix, env)
|
| +
|
| +def _concat_ixes(prefix, list, suffix, env):
|
| + """
|
| + Creates a new list from 'list' by concatenating the 'prefix' and
|
| + 'suffix' arguments onto each element of the list. A trailing space
|
| + on 'prefix' or leading space on 'suffix' will cause them to be put
|
| + into separate list elements rather than being concatenated.
|
| + """
|
| +
|
| + result = []
|
| +
|
| + # ensure that prefix and suffix are strings
|
| + prefix = str(env.subst(prefix, SCons.Subst.SUBST_RAW))
|
| + suffix = str(env.subst(suffix, SCons.Subst.SUBST_RAW))
|
| +
|
| + for x in list:
|
| + if isinstance(x, SCons.Node.FS.File):
|
| + result.append(x)
|
| + continue
|
| + x = str(x)
|
| + if x:
|
| +
|
| + if prefix:
|
| + if prefix[-1] == ' ':
|
| + result.append(prefix[:-1])
|
| + elif x[:len(prefix)] != prefix:
|
| + x = prefix + x
|
| +
|
| + result.append(x)
|
| +
|
| + if suffix:
|
| + if suffix[0] == ' ':
|
| + result.append(suffix[1:])
|
| + elif x[-len(suffix):] != suffix:
|
| + result[-1] = result[-1]+suffix
|
| +
|
| + return result
|
| +
|
| +def _stripixes(prefix, itms, suffix, stripprefixes, stripsuffixes, env, c=None):
|
| + """
|
| + This is a wrapper around _concat()/_concat_ixes() that checks for
|
| + the existence of prefixes or suffixes on list items and strips them
|
| + where it finds them. This is used by tools (like the GNU linker)
|
| + that need to turn something like 'libfoo.a' into '-lfoo'.
|
| + """
|
| +
|
| + if not itms:
|
| + return itms
|
| +
|
| + if not callable(c):
|
| + env_c = env['_concat']
|
| + if env_c != _concat and callable(env_c):
|
| + # There's a custom _concat() method in the construction
|
| + # environment, and we've allowed people to set that in
|
| + # the past (see test/custom-concat.py), so preserve the
|
| + # backwards compatibility.
|
| + c = env_c
|
| + else:
|
| + c = _concat_ixes
|
| +
|
| + stripprefixes = list(map(env.subst, SCons.Util.flatten(stripprefixes)))
|
| + stripsuffixes = list(map(env.subst, SCons.Util.flatten(stripsuffixes)))
|
| +
|
| + stripped = []
|
| + for l in SCons.PathList.PathList(itms).subst_path(env, None, None):
|
| + if isinstance(l, SCons.Node.FS.File):
|
| + stripped.append(l)
|
| + continue
|
| +
|
| + if not SCons.Util.is_String(l):
|
| + l = str(l)
|
| +
|
| + for stripprefix in stripprefixes:
|
| + lsp = len(stripprefix)
|
| + if l[:lsp] == stripprefix:
|
| + l = l[lsp:]
|
| + # Do not strip more than one prefix
|
| + break
|
| +
|
| + for stripsuffix in stripsuffixes:
|
| + lss = len(stripsuffix)
|
| + if l[-lss:] == stripsuffix:
|
| + l = l[:-lss]
|
| + # Do not strip more than one suffix
|
| + break
|
| +
|
| + stripped.append(l)
|
| +
|
| + return c(prefix, stripped, suffix, env)
|
| +
|
| +def processDefines(defs):
|
| + """process defines, resolving strings, lists, dictionaries, into a list of
|
| + strings
|
| + """
|
| + if SCons.Util.is_List(defs):
|
| + l = []
|
| + for d in defs:
|
| + if SCons.Util.is_List(d) or isinstance(d, tuple):
|
| + l.append(str(d[0]) + '=' + str(d[1]))
|
| + else:
|
| + l.append(str(d))
|
| + elif SCons.Util.is_Dict(defs):
|
| + # The items in a dictionary are stored in random order, but
|
| + # if the order of the command-line options changes from
|
| + # invocation to invocation, then the signature of the command
|
| + # line will change and we'll get random unnecessary rebuilds.
|
| + # Consequently, we have to sort the keys to ensure a
|
| + # consistent order...
|
| + l = []
|
| + for k,v in sorted(defs.items()):
|
| + if v is None:
|
| + l.append(str(k))
|
| + else:
|
| + l.append(str(k) + '=' + str(v))
|
| + else:
|
| + l = [str(defs)]
|
| + return l
|
| +
|
| +def _defines(prefix, defs, suffix, env, c=_concat_ixes):
|
| + """A wrapper around _concat_ixes that turns a list or string
|
| + into a list of C preprocessor command-line definitions.
|
| + """
|
| +
|
| + return c(prefix, env.subst_path(processDefines(defs)), suffix, env)
|
| +
|
| +class NullCmdGenerator(object):
|
| + """This is a callable class that can be used in place of other
|
| + command generators if you don't want them to do anything.
|
| +
|
| + The __call__ method for this class simply returns the thing
|
| + you instantiated it with.
|
| +
|
| + Example usage:
|
| + env["DO_NOTHING"] = NullCmdGenerator
|
| + env["LINKCOM"] = "${DO_NOTHING('$LINK $SOURCES $TARGET')}"
|
| + """
|
| +
|
| + def __init__(self, cmd):
|
| + self.cmd = cmd
|
| +
|
| + def __call__(self, target, source, env, for_signature=None):
|
| + return self.cmd
|
| +
|
| +class Variable_Method_Caller(object):
|
| + """A class for finding a construction variable on the stack and
|
| + calling one of its methods.
|
| +
|
| + We use this to support "construction variables" in our string
|
| + eval()s that actually stand in for methods--specifically, use
|
| + of "RDirs" in call to _concat that should actually execute the
|
| + "TARGET.RDirs" method. (We used to support this by creating a little
|
| + "build dictionary" that mapped RDirs to the method, but this got in
|
| + the way of Memoizing construction environments, because we had to
|
| + create new environment objects to hold the variables.)
|
| + """
|
| + def __init__(self, variable, method):
|
| + self.variable = variable
|
| + self.method = method
|
| + def __call__(self, *args, **kw):
|
| + try: 1//0
|
| + except ZeroDivisionError:
|
| + # Don't start iterating with the current stack-frame to
|
| + # prevent creating reference cycles (f_back is safe).
|
| + frame = sys.exc_info()[2].tb_frame.f_back
|
| + variable = self.variable
|
| + while frame:
|
| + if variable in frame.f_locals:
|
| + v = frame.f_locals[variable]
|
| + if v:
|
| + method = getattr(v, self.method)
|
| + return method(*args, **kw)
|
| + frame = frame.f_back
|
| + return None
|
| +
|
| +ConstructionEnvironment = {
|
| + 'BUILDERS' : {},
|
| + 'SCANNERS' : [],
|
| + 'CONFIGUREDIR' : '#/.sconf_temp',
|
| + 'CONFIGURELOG' : '#/config.log',
|
| + 'CPPSUFFIXES' : SCons.Tool.CSuffixes,
|
| + 'DSUFFIXES' : SCons.Tool.DSuffixes,
|
| + 'ENV' : {},
|
| + 'IDLSUFFIXES' : SCons.Tool.IDLSuffixes,
|
| +# 'LATEXSUFFIXES' : SCons.Tool.LaTeXSuffixes, # moved to the TeX tools generate functions
|
| + '_concat' : _concat,
|
| + '_defines' : _defines,
|
| + '_stripixes' : _stripixes,
|
| + '_LIBFLAGS' : '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}',
|
| + '_LIBDIRFLAGS' : '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
|
| + '_CPPINCFLAGS' : '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
|
| + '_CPPDEFFLAGS' : '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}',
|
| + 'TEMPFILE' : NullCmdGenerator,
|
| + 'Dir' : Variable_Method_Caller('TARGET', 'Dir'),
|
| + 'Dirs' : Variable_Method_Caller('TARGET', 'Dirs'),
|
| + 'File' : Variable_Method_Caller('TARGET', 'File'),
|
| + 'RDirs' : Variable_Method_Caller('TARGET', 'RDirs'),
|
| +}
|
| +
|
| +# Local Variables:
|
| +# tab-width:4
|
| +# indent-tabs-mode:nil
|
| +# End:
|
| +# vim: set expandtab tabstop=4 shiftwidth=4:
|
|
|
| Property changes on: scons-2.0.1/engine/SCons/Defaults.py
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|