SCons.PathList

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

# Source Code for Module SCons.PathList

      1  #
      2  # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation
      3  #
      4  # Permission is hereby granted, free of charge, to any person obtaining
      5  # a copy of this software and associated documentation files (the
      6  # "Software"), to deal in the Software without restriction, including
      7  # without limitation the rights to use, copy, modify, merge, publish,
      8  # distribute, sublicense, and/or sell copies of the Software, and to
      9  # permit persons to whom the Software is furnished to do so, subject to
     10  # the following conditions:
     11  #
     12  # The above copyright notice and this permission notice shall be included
     13  # in all copies or substantial portions of the Software.
     14  #
     15  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
     16  # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
     17  # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     18  # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
     19  # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
     20  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     21  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     22  #
     23
     24  __revision__ = "src/engine/SCons/PathList.py 2725 2008/03/31 12:52:02 knight"
     25
     26  __doc__ = """SCons.PathList
     27
     28  A module for handling lists of directory paths (the sort of things
     29  that get set as CPPPATH, LIBPATH, etc.) with as much caching of data and
     30  efficiency as we can while still keeping the evaluation delayed so that we
     31  Do the Right Thing (almost) regardless of how the variable is specified.
     32
     33  """
     34
     35  import os
     36  import string
     37
     38  import SCons.Memoize
     39  import SCons.Node
     40  import SCons.Util
     41
     42  #
     43  # Variables to specify the different types of entries in a PathList object:
     44  #
     45
     46  TYPE_STRING_NO_SUBST = 0        # string with no '$'
     47  TYPE_STRING_SUBST = 1           # string containing '$'
     48  TYPE_OBJECT = 2                 # other object
     49
     50 -def node_conv(obj):
     51      """
     52      This is the "string conversion" routine that we have our substitutions
     53      use to return Nodes, not strings.  This relies on the fact that an
     54      EntryProxy object has a get() method that returns the underlying
     55      Node that it wraps, which is a bit of architectural dependence
     56      that we might need to break or modify in the future in response to
     57      additional requirements.
     58      """
     59      try:
     60          get = obj.get
     61      except AttributeError:
     62          if isinstance(obj, SCons.Node.Node) or SCons.Util.is_Sequence( obj ):
     63              result = obj
     64          else:
     65              result = str(obj)
     66      else:
     67          result = get()
     68      return result
     69
     70 -class _PathList:
     71      """
     72      An actual PathList object.
     73      """
     74 -    def __init__(self, pathlist):
     75          """
     76          Initializes a PathList object, canonicalizing the input and
     77          pre-processing it for quicker substitution later.
     78
     79          The stored representation of the PathList is a list of tuples
     80          containing (type, value), where the "type" is one of the TYPE_*
     81          variables defined above.  We distinguish between:
     82
     83              strings that contain no '$' and therefore need no
     84              delayed-evaluation string substitution (we expect that there
     85              will be many of these and that we therefore get a pretty
     86              big win from avoiding string substitution)
     87
     88              strings that contain '$' and therefore need substitution
     89              (the hard case is things like '${TARGET.dir}/include',
     90              which require re-evaluation for every target + source)
     91
     92              other objects (which may be something like an EntryProxy
     93              that needs a method called to return a Node)
     94
     95          Pre-identifying the type of each element in the PathList up-front
     96          and storing the type in the list of tuples is intended to reduce
     97          the amount of calculation when we actually do the substitution
     98          over and over for each target.
     99          """
    100          if SCons.Util.is_String(pathlist):
    101              pathlist = string.split(pathlist, os.pathsep)
    102          elif not SCons.Util.is_Sequence(pathlist):
    103              pathlist = [pathlist]
    104
    105          pl = []
    106          for p in pathlist:
    107              try:
    108                  index = string.find(p, '$')
    109              except (AttributeError, TypeError):
    110                  type = TYPE_OBJECT
    111              else:
    112                  if index == -1:
    113                      type = TYPE_STRING_NO_SUBST
    114                  else:
    115                      type = TYPE_STRING_SUBST
    116              pl.append((type, p))
    117
    118          self.pathlist = tuple(pl)
    119
    120 -    def __len__(self): return len(self.pathlist)
    121
    122 -    def __getitem__(self, i): return self.pathlist[i]
    123
    124 -    def subst_path(self, env, target, source):
    125          """
    126          Performs construction variable substitution on a pre-digested
    127          PathList for a specific target and source.
    128          """
    129          result = []
    130          for type, value in self.pathlist:
    131              if type == TYPE_STRING_SUBST:
    132                  value = env.subst(value, target=target, source=source,
    133                                    conv=node_conv)
    134                  if SCons.Util.is_Sequence(value):
    135                      result.extend(value)
    136                      continue
    137
    138              elif type == TYPE_OBJECT:
    139                  value = node_conv(value)
    140              if value:
    141                  result.append(value)
    142          return tuple(result)
    143
    144
    145 -class PathListCache:
    146      """
    147      A class to handle caching of PathList lookups.
    148
    149      This class gets instantiated once and then deleted from the namespace,
    150      so it's used as a Singleton (although we don't enforce that in the
    151      usual Pythonic ways).  We could have just made the cache a dictionary
    152      in the module namespace, but putting it in this class allows us to
    153      use the same Memoizer pattern that we use elsewhere to count cache
    154      hits and misses, which is very valuable.
    155
    156      Lookup keys in the cache are computed by the _PathList_key() method.
    157      Cache lookup should be quick, so we don't spend cycles canonicalizing
    158      all forms of the same lookup key.  For example, 'x:y' and ['x',
    159      'y'] logically represent the same list, but we don't bother to
    160      split string representations and treat those two equivalently.
    161      (Note, however, that we do, treat lists and tuples the same.)
    162
    163      The main type of duplication we're trying to catch will come from
    164      looking up the same path list from two different clones of the
    165      same construction environment.  That is, given
    166
    167          env2 = env1.Clone()
    168
    169      both env1 and env2 will have the same CPPPATH value, and we can
    170      cheaply avoid re-parsing both values of CPPPATH by using the
    171      common value from this cache.
    172      """
    173      if SCons.Memoize.use_memoizer:
    174          __metaclass__ = SCons.Memoize.Memoized_Metaclass
    175
    176      memoizer_counters = []
    177
    178 -    def __init__(self):
    179          self._memo = {}
    180
    181 -    def _PathList_key(self, pathlist):
    182          """
    183          Returns the key for memoization of PathLists.
    184
    185          Note that we want this to be pretty quick, so we don't completely
    186          canonicalize all forms of the same list.  For example,
    187          'dir1:$ROOT/dir2' and ['$ROOT/dir1', 'dir'] may logically
    188          represent the same list if you're executing from $ROOT, but
    189          we're not going to bother splitting strings into path elements,
    190          or massaging strings into Nodes, to identify that equivalence.
    191          We just want to eliminate obvious redundancy from the normal
    192          case of re-using exactly the same cloned value for a path.
    193          """
    194          if SCons.Util.is_Sequence(pathlist):
    195              pathlist = tuple(SCons.Util.flatten(pathlist))
    196          return pathlist
    197
    198      memoizer_counters.append(SCons.Memoize.CountDict('PathList', _PathList_key))
    199
    200 -    def PathList(self, pathlist):
    201          """
    202          Returns the cached _PathList object for the specified pathlist,
    203          creating and caching a new object as necessary.
    204          """
    205          pathlist = self._PathList_key(pathlist)
    206          try:
    207              memo_dict = self._memo['PathList']
    208          except KeyError:
    209              memo_dict = {}
    210              self._memo['PathList'] = memo_dict
    211          else:
    212              try:
    213                  return memo_dict[pathlist]
    214              except KeyError:
    215                  pass
    216
    217          result = _PathList(pathlist)
    218
    219          memo_dict[pathlist] = result
    220
    221          return result
    222
    223  PathList = PathListCache().PathList
    224
    225
    226  del PathListCache
    227