SCons.Defaults

Package SCons :: Module Defaults |
[hide private]
[frames] | no frames]

# Source Code for Module SCons.Defaults

      1  """SCons.Defaults
      2
      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.
      6
      7  The code that reads the registry to find MSVC components was borrowed
      8  from distutils.msvccompiler.
      9
     10  """
     11
     12  #
     13  # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation
     14  #
     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:
     22  #
     23  # The above copyright notice and this permission notice shall be included
     24  # in all copies or substantial portions of the Software.
     25  #
     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.
     33  #
     34
     35  __revision__ = "src/engine/SCons/Defaults.py 2725 2008/03/31 12:52:02 knight"
     36
     37
     38
     39  import os
     40  import os.path
     41  import shutil
     42  import stat
     43  import string
     44  import time
     45  import types
     46  import sys
     47
     48  import SCons.Action
     49  import SCons.Builder
     50  import SCons.CacheDir
     51  import SCons.Environment
     52  import SCons.PathList
     53  import SCons.Subst
     54  import SCons.Tool
     55
     56  # A placeholder for a default Environment (for fetching source files
     57  # from source code management systems and the like).  This must be
     58  # initialized later, after the top-level directory is set by the calling
     59  # interface.
     60  _default_env = None
     61
     62  # Lazily instantiate the default environment so the overhead of creating
     63  # it doesn't apply when it's not needed.
     64 -def _fetch_DefaultEnvironment(*args, **kw):
     65      """
     66      Returns the already-created default construction environment.
     67      """
     68      global _default_env
     69      return _default_env
     70
     71 -def DefaultEnvironment(*args, **kw):
     72      """
     73      Initial public entry point for creating the default construction
     74      Environment.
     75
     76      After creating the environment, we overwrite our name
     77      (DefaultEnvironment) with the _fetch_DefaultEnvironment() function,
     78      which more efficiently returns the initialized default construction
     79      environment without checking for its existence.
     80
     81      (This function still exists with its _default_check because someone
     82      else (*cough* Script/__init__.py *cough*) may keep a reference
     83      to this function.  So we can't use the fully functional idiom of
     84      having the name originally be a something that *only* creates the
     85      construction environment and then overwrites the name.)
     86      """
     87      global _default_env
     88      if not _default_env:
     89          import SCons.Util
     90          _default_env = apply(SCons.Environment.Environment, args, kw)
     91          if SCons.Util.md5:
     92              _default_env.Decider('MD5')
     93          else:
     94              _default_env.Decider('timestamp-match')
     95          global DefaultEnvironment
     96          DefaultEnvironment = _fetch_DefaultEnvironment
     97          _default_env._CacheDir_path = None
     98      return _default_env
     99
    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):
    104      for tgt in target:
    105          tgt.attributes.shared = None
    106      return (target, source)
    107
    108 -def SharedObjectEmitter(target, source, env):
    109      for tgt in target:
    110          tgt.attributes.shared = 1
    111      return (target, source)
    112
    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':
    116          for src in source:
    117              try:
    118                  shared = src.attributes.shared
    119              except AttributeError:
    120                  shared = None
    121              if not shared:
    122                  raise SCons.Errors.UserError, "Source file: %s is static and is not compatible with shared target: %s" % (src, target[0])
    123
    124  SharedCheck = SCons.Action.Action(SharedFlagChecker, None)
    125
    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
    129  # transition period.
    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
    135
    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()
    142
    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")
    148
    149  ASAction = SCons.Action.Action("$ASCOM", "$ASCOMSTR")
    150  ASPPAction = SCons.Action.Action("$ASPPCOM", "$ASPPCOMSTR")
    151
    152  LinkAction = SCons.Action.Action("$LINKCOM", "$LINKCOMSTR")
    153  ShLinkAction = SCons.Action.Action("$SHLINKCOM", "$SHLINKCOMSTR")
    154
    155  LdModuleLinkAction = SCons.Action.Action("$LDMODULECOM", "$LDMODULECOMSTR")
    156
    157  # Common tasks that we allow users to perform in platform-independent
    158  # ways by creating ActionFactory instances.
    159  ActionFactory = SCons.Action.ActionFactory
    160
    161 -def get_paths_str(dest):
    162      # If dest is a list, we need to manually call str() on each element
    163      if SCons.Util.is_List(dest):
    164          elem_strs = []
    165          for element in dest:
    166              elem_strs.append('"' + str(element) + '"')
    167          return '[' + string.join(elem_strs, ', ') + ']'
    168      else:
    169          return '"' + str(dest) + '"'
    170
    171 -def chmod_func(dest, mode):
    172      if not SCons.Util.is_List(dest):
    173          dest = [dest]
    174      for element in dest:
    175          os.chmod(str(element), mode)
    176
    177 -def chmod_strfunc(dest, mode):
    178      return 'Chmod(%s, 0%o)' % (get_paths_str(dest), mode)
    179
    180  Chmod = ActionFactory(chmod_func, chmod_strfunc)
    181
    182 -def copy_func(dest, src):
    183      if SCons.Util.is_List(src) and os.path.isdir(dest):
    184          for file in src:
    185              shutil.copy2(file, dest)
    186          return 0
    187      elif os.path.isfile(src):
    188          return shutil.copy2(src, dest)
    189      else:
    190          return shutil.copytree(src, dest, 1)
    191
    192  Copy = ActionFactory(copy_func,
    193                       lambda dest, src: 'Copy("%s", "%s")' % (dest, src),
    194                       convert=str)
    195
    196 -def delete_func(dest, must_exist=0):
    197      if not SCons.Util.is_List(dest):
    198          dest = [dest]
    199      for entry in dest:
    200          entry = str(entry)
    201          if not must_exist and not os.path.exists(entry):
    202              continue
    203          if not os.path.exists(entry) or os.path.isfile(entry):
    204              os.unlink(entry)
    205              continue
    206          else:
    207              shutil.rmtree(entry, 1)
    208              continue
    209
    210 -def delete_strfunc(dest, must_exist=0):
    211      return 'Delete(%s)' % get_paths_str(dest)
    212
    213  Delete = ActionFactory(delete_func, delete_strfunc)
    214
    215 -def mkdir_func(dest):
    216      if not SCons.Util.is_List(dest):
    217          dest = [dest]
    218      for entry in dest:
    219          os.makedirs(str(entry))
    220
    221  Mkdir = ActionFactory(mkdir_func,
    222                        lambda dir: 'Mkdir(%s)' % get_paths_str(dir))
    223
    224  Move = ActionFactory(lambda dest, src: os.rename(src, dest),
    225                       lambda dest, src: 'Move("%s", "%s")' % (dest, src),
    226                       convert=str)
    227
    228 -def touch_func(dest):
    229      if not SCons.Util.is_List(dest):
    230          dest = [dest]
    231      for file in dest:
    232          file = str(file)
    233          mtime = int(time.time())
    234          if os.path.exists(file):
    235              atime = os.path.getatime(file)
    236          else:
    237              open(file, 'w')
    238              atime = mtime
    239          os.utime(file, (atime, mtime))
    240
    241  Touch = ActionFactory(touch_func,
    242                        lambda file: 'Touch(%s)' % get_paths_str(file))
    243
    244  # Internal utility functions
    245
    246 -def _concat(prefix, list, suffix, env, f=lambda x: x, target=None, source=None):
    247      """
    248      Creates a new list from 'list' by first interpolating each element
    249      in the list using the 'env' dictionary and then calling f on the
    250      list, and finally calling _concat_ixes to concatenate 'prefix' and
    251      'suffix' onto each element of the list.
    252      """
    253      if not list:
    254          return list
    255
    256      l = f(SCons.PathList.PathList(list).subst_path(env, target, source))
    257      if not l is None:
    258          list = l
    259
    260      return _concat_ixes(prefix, list, suffix, env)
    261
    262 -def _concat_ixes(prefix, list, suffix, env):
    263      """
    264      Creates a new list from 'list' by concatenating the 'prefix' and
    265      'suffix' arguments onto each element of the list.  A trailing space
    266      on 'prefix' or leading space on 'suffix' will cause them to be put
    267      into separate list elements rather than being concatenated.
    268      """
    269
    270      result = []
    271
    272      # ensure that prefix and suffix are strings
    273      prefix = str(env.subst(prefix, SCons.Subst.SUBST_RAW))
    274      suffix = str(env.subst(suffix, SCons.Subst.SUBST_RAW))
    275
    276      for x in list:
    277          if isinstance(x, SCons.Node.FS.File):
    278              result.append(x)
    279              continue
    280          x = str(x)
    281          if x:
    282
    283              if prefix:
    284                  if prefix[-1] == ' ':
    285                      result.append(prefix[:-1])
    286                  elif x[:len(prefix)] != prefix:
    287                      x = prefix + x
    288
    289              result.append(x)
    290
    291              if suffix:
    292                  if suffix[0] == ' ':
    293                      result.append(suffix[1:])
    294                  elif x[-len(suffix):] != suffix:
    295                      result[-1] = result[-1]+suffix
    296
    297      return result
    298
    299 -def _stripixes(prefix, list, suffix, stripprefixes, stripsuffixes, env, c=None):
    300      """
    301      This is a wrapper around _concat()/_concat_ixes() that checks for the
    302      existence of prefixes or suffixes on list elements and strips them
    303      where it finds them.  This is used by tools (like the GNU linker)
    304      that need to turn something like 'libfoo.a' into '-lfoo'.
    305      """
    306
    307      if not list:
    308          return list
    309
    310      if not callable(c):
    311          env_c = env['_concat']
    312          if env_c != _concat and callable(env_c):
    313              # There's a custom _concat() method in the construction
    314              # environment, and we've allowed people to set that in
    315              # the past (see test/custom-concat.py), so preserve the
    316              # backwards compatibility.
    317              c = env_c
    318          else:
    319              c = _concat_ixes
    320
    321      stripprefixes = map(env.subst, SCons.Util.flatten(stripprefixes))
    322      stripsuffixes = map(env.subst, SCons.Util.flatten(stripsuffixes))
    323
    324      stripped = []
    325      for l in SCons.PathList.PathList(list).subst_path(env, None, None):
    326          if isinstance(l, SCons.Node.FS.File):
    327              stripped.append(l)
    328              continue
    329
    330          if not SCons.Util.is_String(l):
    331              l = str(l)
    332
    333          for stripprefix in stripprefixes:
    334              lsp = len(stripprefix)
    335              if l[:lsp] == stripprefix:
    336                  l = l[lsp:]
    337                  # Do not strip more than one prefix
    338                  break
    339
    340          for stripsuffix in stripsuffixes:
    341              lss = len(stripsuffix)
    342              if l[-lss:] == stripsuffix:
    343                  l = l[:-lss]
    344                  # Do not strip more than one suffix
    345                  break
    346
    347          stripped.append(l)
    348
    349      return c(prefix, stripped, suffix, env)
    350
    351 -def _defines(prefix, defs, suffix, env, c=_concat_ixes):
    352      """A wrapper around _concat_ixes that turns a list or string
    353      into a list of C preprocessor command-line definitions.
    354      """
    355      if SCons.Util.is_List(defs):
    356          l = []
    357          for d in defs:
    358              if SCons.Util.is_List(d) or type(d) is types.TupleType:
    359                  l.append(str(d[0]) + '=' + str(d[1]))
    360              else:
    361                  l.append(str(d))
    362      elif SCons.Util.is_Dict(defs):
    363          # The items in a dictionary are stored in random order, but
    364          # if the order of the command-line options changes from
    365          # invocation to invocation, then the signature of the command
    366          # line will change and we'll get random unnecessary rebuilds.
    367          # Consequently, we have to sort the keys to ensure a
    368          # consistent order...
    369          l = []
    370          keys = defs.keys()
    371          keys.sort()
    372          for k in keys:
    373              v = defs[k]
    374              if v is None:
    375                  l.append(str(k))
    376              else:
    377                  l.append(str(k) + '=' + str(v))
    378      else:
    379          l = [str(defs)]
    380      return c(prefix, env.subst_path(l), suffix, env)
    381
    382 -class NullCmdGenerator:
    383      """This is a callable class that can be used in place of other
    384      command generators if you don't want them to do anything.
    385
    386      The __call__ method for this class simply returns the thing
    387      you instantiated it with.
    388
    389      Example usage:
    390      env["DO_NOTHING"] = NullCmdGenerator
    391      env["LINKCOM"] = "${DO_NOTHING('$LINK $SOURCES $TARGET')}"
    392      """
    393
    394 -    def __init__(self, cmd):
    395          self.cmd = cmd
    396
    397 -    def __call__(self, target, source, env, for_signature=None):
    398          return self.cmd
    399
    400 -class Variable_Method_Caller:
    401      """A class for finding a construction variable on the stack and
    402      calling one of its methods.
    403
    404      We use this to support "construction variables" in our string
    405      eval()s that actually stand in for methods--specifically, use
    406      of "RDirs" in call to _concat that should actually execute the
    407      "TARGET.RDirs" method.  (We used to support this by creating a little
    408      "build dictionary" that mapped RDirs to the method, but this got in
    409      the way of Memoizing construction environments, because we had to
    410      create new environment objects to hold the variables.)
    411      """
    412 -    def __init__(self, variable, method):
    413          self.variable = variable
    414          self.method = method
    415 -    def __call__(self, *args, **kw):
    416          try: 1/0
    417          except ZeroDivisionError: frame = sys.exc_info()[2].tb_frame
    418          variable = self.variable
    419          while frame:
    420              if frame.f_locals.has_key(variable):
    421                  v = frame.f_locals[variable]
    422                  if v:
    423                      method = getattr(v, self.method)
    424                      return apply(method, args, kw)
    425              frame = frame.f_back
    426          return None
    427
    428  ConstructionEnvironment = {
    429      'BUILDERS'      : {},
    430      'SCANNERS'      : [],
    431      'CONFIGUREDIR'  : '#/.sconf_temp',
    432      'CONFIGURELOG'  : '#/config.log',
    433      'CPPSUFFIXES'   : SCons.Tool.CSuffixes,
    434      'DSUFFIXES'     : SCons.Tool.DSuffixes,
    435      'ENV'           : {},
    436      'IDLSUFFIXES'   : SCons.Tool.IDLSuffixes,
    437      'LATEXSUFFIXES' : SCons.Tool.LaTeXSuffixes,
    438      '_concat'       : _concat,
    439      '_defines'      : _defines,
    440      '_stripixes'    : _stripixes,
    441      '_LIBFLAGS'     : '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}',
    442      '_LIBDIRFLAGS'  : '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
    443      '_CPPINCFLAGS'  : '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
    444      '_CPPDEFFLAGS'  : '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}',
    445      'TEMPFILE'      : NullCmdGenerator,
    446      'Dir'           : Variable_Method_Caller('TARGET', 'Dir'),
    447      'Dirs'          : Variable_Method_Caller('TARGET', 'Dirs'),
    448      'File'          : Variable_Method_Caller('TARGET', 'File'),
    449      'RDirs'         : Variable_Method_Caller('TARGET', 'RDirs'),
    450  }
    451