Index: scons-2.0.1/engine/SCons/PathList.py |
=================================================================== |
--- scons-2.0.1/engine/SCons/PathList.py (revision 0) |
+++ scons-2.0.1/engine/SCons/PathList.py (revision 0) |
@@ -0,0 +1,231 @@ |
+# |
+# 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. |
+# |
+ |
+__revision__ = "src/engine/SCons/PathList.py 5134 2010/08/16 23:02:40 bdeegan" |
+ |
+__doc__ = """SCons.PathList |
+ |
+A module for handling lists of directory paths (the sort of things |
+that get set as CPPPATH, LIBPATH, etc.) with as much caching of data and |
+efficiency as we can while still keeping the evaluation delayed so that we |
+Do the Right Thing (almost) regardless of how the variable is specified. |
+ |
+""" |
+ |
+import os |
+ |
+import SCons.Memoize |
+import SCons.Node |
+import SCons.Util |
+ |
+# |
+# Variables to specify the different types of entries in a PathList object: |
+# |
+ |
+TYPE_STRING_NO_SUBST = 0 # string with no '$' |
+TYPE_STRING_SUBST = 1 # string containing '$' |
+TYPE_OBJECT = 2 # other object |
+ |
+def node_conv(obj): |
+ """ |
+ This is the "string conversion" routine that we have our substitutions |
+ use to return Nodes, not strings. This relies on the fact that an |
+ EntryProxy object has a get() method that returns the underlying |
+ Node that it wraps, which is a bit of architectural dependence |
+ that we might need to break or modify in the future in response to |
+ additional requirements. |
+ """ |
+ try: |
+ get = obj.get |
+ except AttributeError: |
+ if isinstance(obj, SCons.Node.Node) or SCons.Util.is_Sequence( obj ): |
+ result = obj |
+ else: |
+ result = str(obj) |
+ else: |
+ result = get() |
+ return result |
+ |
+class _PathList(object): |
+ """ |
+ An actual PathList object. |
+ """ |
+ def __init__(self, pathlist): |
+ """ |
+ Initializes a PathList object, canonicalizing the input and |
+ pre-processing it for quicker substitution later. |
+ |
+ The stored representation of the PathList is a list of tuples |
+ containing (type, value), where the "type" is one of the TYPE_* |
+ variables defined above. We distinguish between: |
+ |
+ strings that contain no '$' and therefore need no |
+ delayed-evaluation string substitution (we expect that there |
+ will be many of these and that we therefore get a pretty |
+ big win from avoiding string substitution) |
+ |
+ strings that contain '$' and therefore need substitution |
+ (the hard case is things like '${TARGET.dir}/include', |
+ which require re-evaluation for every target + source) |
+ |
+ other objects (which may be something like an EntryProxy |
+ that needs a method called to return a Node) |
+ |
+ Pre-identifying the type of each element in the PathList up-front |
+ and storing the type in the list of tuples is intended to reduce |
+ the amount of calculation when we actually do the substitution |
+ over and over for each target. |
+ """ |
+ if SCons.Util.is_String(pathlist): |
+ pathlist = pathlist.split(os.pathsep) |
+ elif not SCons.Util.is_Sequence(pathlist): |
+ pathlist = [pathlist] |
+ |
+ pl = [] |
+ for p in pathlist: |
+ try: |
+ index = p.find('$') |
+ except (AttributeError, TypeError): |
+ type = TYPE_OBJECT |
+ else: |
+ if index == -1: |
+ type = TYPE_STRING_NO_SUBST |
+ else: |
+ type = TYPE_STRING_SUBST |
+ pl.append((type, p)) |
+ |
+ self.pathlist = tuple(pl) |
+ |
+ def __len__(self): return len(self.pathlist) |
+ |
+ def __getitem__(self, i): return self.pathlist[i] |
+ |
+ def subst_path(self, env, target, source): |
+ """ |
+ Performs construction variable substitution on a pre-digested |
+ PathList for a specific target and source. |
+ """ |
+ result = [] |
+ for type, value in self.pathlist: |
+ if type == TYPE_STRING_SUBST: |
+ value = env.subst(value, target=target, source=source, |
+ conv=node_conv) |
+ if SCons.Util.is_Sequence(value): |
+ result.extend(value) |
+ continue |
+ |
+ elif type == TYPE_OBJECT: |
+ value = node_conv(value) |
+ if value: |
+ result.append(value) |
+ return tuple(result) |
+ |
+ |
+class PathListCache(object): |
+ """ |
+ A class to handle caching of PathList lookups. |
+ |
+ This class gets instantiated once and then deleted from the namespace, |
+ so it's used as a Singleton (although we don't enforce that in the |
+ usual Pythonic ways). We could have just made the cache a dictionary |
+ in the module namespace, but putting it in this class allows us to |
+ use the same Memoizer pattern that we use elsewhere to count cache |
+ hits and misses, which is very valuable. |
+ |
+ Lookup keys in the cache are computed by the _PathList_key() method. |
+ Cache lookup should be quick, so we don't spend cycles canonicalizing |
+ all forms of the same lookup key. For example, 'x:y' and ['x', |
+ 'y'] logically represent the same list, but we don't bother to |
+ split string representations and treat those two equivalently. |
+ (Note, however, that we do, treat lists and tuples the same.) |
+ |
+ The main type of duplication we're trying to catch will come from |
+ looking up the same path list from two different clones of the |
+ same construction environment. That is, given |
+ |
+ env2 = env1.Clone() |
+ |
+ both env1 and env2 will have the same CPPPATH value, and we can |
+ cheaply avoid re-parsing both values of CPPPATH by using the |
+ common value from this cache. |
+ """ |
+ if SCons.Memoize.use_memoizer: |
+ __metaclass__ = SCons.Memoize.Memoized_Metaclass |
+ |
+ memoizer_counters = [] |
+ |
+ def __init__(self): |
+ self._memo = {} |
+ |
+ def _PathList_key(self, pathlist): |
+ """ |
+ Returns the key for memoization of PathLists. |
+ |
+ Note that we want this to be pretty quick, so we don't completely |
+ canonicalize all forms of the same list. For example, |
+ 'dir1:$ROOT/dir2' and ['$ROOT/dir1', 'dir'] may logically |
+ represent the same list if you're executing from $ROOT, but |
+ we're not going to bother splitting strings into path elements, |
+ or massaging strings into Nodes, to identify that equivalence. |
+ We just want to eliminate obvious redundancy from the normal |
+ case of re-using exactly the same cloned value for a path. |
+ """ |
+ if SCons.Util.is_Sequence(pathlist): |
+ pathlist = tuple(SCons.Util.flatten(pathlist)) |
+ return pathlist |
+ |
+ memoizer_counters.append(SCons.Memoize.CountDict('PathList', _PathList_key)) |
+ |
+ def PathList(self, pathlist): |
+ """ |
+ Returns the cached _PathList object for the specified pathlist, |
+ creating and caching a new object as necessary. |
+ """ |
+ pathlist = self._PathList_key(pathlist) |
+ try: |
+ memo_dict = self._memo['PathList'] |
+ except KeyError: |
+ memo_dict = {} |
+ self._memo['PathList'] = memo_dict |
+ else: |
+ try: |
+ return memo_dict[pathlist] |
+ except KeyError: |
+ pass |
+ |
+ result = _PathList(pathlist) |
+ |
+ memo_dict[pathlist] = result |
+ |
+ return result |
+ |
+PathList = PathListCache().PathList |
+ |
+ |
+del PathListCache |
+ |
+# 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/PathList.py |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |