PathList.py
上传用户:market2
上传日期:2018-11-18
资源大小:18786k
文件大小:8k
源码类别:

外挂编程

开发平台:

Windows_Unix

  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. __revision__ = "src/engine/SCons/PathList.py 3057 2008/06/09 22:21:00 knight"
  24. __doc__ = """SCons.PathList
  25. A module for handling lists of directory paths (the sort of things
  26. that get set as CPPPATH, LIBPATH, etc.) with as much caching of data and
  27. efficiency as we can while still keeping the evaluation delayed so that we
  28. Do the Right Thing (almost) regardless of how the variable is specified.
  29. """
  30. import os
  31. import string
  32. import SCons.Memoize
  33. import SCons.Node
  34. import SCons.Util
  35. #
  36. # Variables to specify the different types of entries in a PathList object:
  37. #
  38. TYPE_STRING_NO_SUBST = 0        # string with no '$'
  39. TYPE_STRING_SUBST = 1           # string containing '$'
  40. TYPE_OBJECT = 2                 # other object
  41. def node_conv(obj):
  42.     """
  43.     This is the "string conversion" routine that we have our substitutions
  44.     use to return Nodes, not strings.  This relies on the fact that an
  45.     EntryProxy object has a get() method that returns the underlying
  46.     Node that it wraps, which is a bit of architectural dependence
  47.     that we might need to break or modify in the future in response to
  48.     additional requirements.
  49.     """
  50.     try:
  51.         get = obj.get
  52.     except AttributeError:
  53.         if isinstance(obj, SCons.Node.Node) or SCons.Util.is_Sequence( obj ):
  54.             result = obj
  55.         else:
  56.             result = str(obj)
  57.     else:
  58.         result = get()
  59.     return result
  60. class _PathList:
  61.     """
  62.     An actual PathList object.
  63.     """
  64.     def __init__(self, pathlist):
  65.         """
  66.         Initializes a PathList object, canonicalizing the input and
  67.         pre-processing it for quicker substitution later.
  68.         The stored representation of the PathList is a list of tuples
  69.         containing (type, value), where the "type" is one of the TYPE_*
  70.         variables defined above.  We distinguish between:
  71.             strings that contain no '$' and therefore need no
  72.             delayed-evaluation string substitution (we expect that there
  73.             will be many of these and that we therefore get a pretty
  74.             big win from avoiding string substitution)
  75.             strings that contain '$' and therefore need substitution
  76.             (the hard case is things like '${TARGET.dir}/include',
  77.             which require re-evaluation for every target + source)
  78.             other objects (which may be something like an EntryProxy
  79.             that needs a method called to return a Node)
  80.         Pre-identifying the type of each element in the PathList up-front
  81.         and storing the type in the list of tuples is intended to reduce
  82.         the amount of calculation when we actually do the substitution
  83.         over and over for each target.
  84.         """
  85.         if SCons.Util.is_String(pathlist):
  86.             pathlist = string.split(pathlist, os.pathsep)
  87.         elif not SCons.Util.is_Sequence(pathlist):
  88.             pathlist = [pathlist]
  89.         pl = []
  90.         for p in pathlist:
  91.             try:
  92.                 index = string.find(p, '$')
  93.             except (AttributeError, TypeError):
  94.                 type = TYPE_OBJECT
  95.             else:
  96.                 if index == -1:
  97.                     type = TYPE_STRING_NO_SUBST
  98.                 else:
  99.                     type = TYPE_STRING_SUBST
  100.             pl.append((type, p))
  101.         self.pathlist = tuple(pl)
  102.     def __len__(self): return len(self.pathlist)
  103.     def __getitem__(self, i): return self.pathlist[i]
  104.     def subst_path(self, env, target, source):
  105.         """
  106.         Performs construction variable substitution on a pre-digested
  107.         PathList for a specific target and source.
  108.         """
  109.         result = []
  110.         for type, value in self.pathlist:
  111.             if type == TYPE_STRING_SUBST:
  112.                 value = env.subst(value, target=target, source=source,
  113.                                   conv=node_conv)
  114.                 if SCons.Util.is_Sequence(value):
  115.                     result.extend(value)
  116.                     continue
  117.                     
  118.             elif type == TYPE_OBJECT:
  119.                 value = node_conv(value)
  120.             if value:
  121.                 result.append(value)
  122.         return tuple(result)
  123. class PathListCache:
  124.     """
  125.     A class to handle caching of PathList lookups.
  126.     This class gets instantiated once and then deleted from the namespace,
  127.     so it's used as a Singleton (although we don't enforce that in the
  128.     usual Pythonic ways).  We could have just made the cache a dictionary
  129.     in the module namespace, but putting it in this class allows us to
  130.     use the same Memoizer pattern that we use elsewhere to count cache
  131.     hits and misses, which is very valuable.
  132.     Lookup keys in the cache are computed by the _PathList_key() method.
  133.     Cache lookup should be quick, so we don't spend cycles canonicalizing
  134.     all forms of the same lookup key.  For example, 'x:y' and ['x',
  135.     'y'] logically represent the same list, but we don't bother to
  136.     split string representations and treat those two equivalently.
  137.     (Note, however, that we do, treat lists and tuples the same.)
  138.     The main type of duplication we're trying to catch will come from
  139.     looking up the same path list from two different clones of the
  140.     same construction environment.  That is, given
  141.     
  142.         env2 = env1.Clone()
  143.     both env1 and env2 will have the same CPPPATH value, and we can
  144.     cheaply avoid re-parsing both values of CPPPATH by using the
  145.     common value from this cache.
  146.     """
  147.     if SCons.Memoize.use_memoizer:
  148.         __metaclass__ = SCons.Memoize.Memoized_Metaclass
  149.     memoizer_counters = []
  150.     def __init__(self):
  151.         self._memo = {}
  152.     def _PathList_key(self, pathlist):
  153.         """
  154.         Returns the key for memoization of PathLists.
  155.         Note that we want this to be pretty quick, so we don't completely
  156.         canonicalize all forms of the same list.  For example,
  157.         'dir1:$ROOT/dir2' and ['$ROOT/dir1', 'dir'] may logically
  158.         represent the same list if you're executing from $ROOT, but
  159.         we're not going to bother splitting strings into path elements,
  160.         or massaging strings into Nodes, to identify that equivalence.
  161.         We just want to eliminate obvious redundancy from the normal
  162.         case of re-using exactly the same cloned value for a path.
  163.         """
  164.         if SCons.Util.is_Sequence(pathlist):
  165.             pathlist = tuple(SCons.Util.flatten(pathlist))
  166.         return pathlist
  167.     memoizer_counters.append(SCons.Memoize.CountDict('PathList', _PathList_key))
  168.     def PathList(self, pathlist):
  169.         """
  170.         Returns the cached _PathList object for the specified pathlist,
  171.         creating and caching a new object as necessary.
  172.         """
  173.         pathlist = self._PathList_key(pathlist)
  174.         try:
  175.             memo_dict = self._memo['PathList']
  176.         except KeyError:
  177.             memo_dict = {}
  178.             self._memo['PathList'] = memo_dict
  179.         else:
  180.             try:
  181.                 return memo_dict[pathlist]
  182.             except KeyError:
  183.                 pass
  184.         result = _PathList(pathlist)
  185.         memo_dict[pathlist] = result
  186.         return result
  187. PathList = PathListCache().PathList
  188. del PathListCache