1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 __revision__ = "src/engine/SCons/PathList.py 5110 2010/07/25 16:14:38 bdeegan"
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
44
45
46 TYPE_STRING_NO_SUBST = 0
47 TYPE_STRING_SUBST = 1
48 TYPE_OBJECT = 2
49
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
71 """
72 An actual PathList object.
73 """
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
123
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
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
180
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
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
228
229
230
231
232
233