OLD | NEW |
1 """SCons.Environment | 1 """SCons.Environment |
2 | 2 |
3 Base class for construction Environments. These are | 3 Base class for construction Environments. These are |
4 the primary objects used to communicate dependency and | 4 the primary objects used to communicate dependency and |
5 construction information to the build engine. | 5 construction information to the build engine. |
6 | 6 |
7 Keyword arguments supplied when the construction Environment | 7 Keyword arguments supplied when the construction Environment |
8 is created are construction variables used to initialize the | 8 is created are construction variables used to initialize the |
9 Environment | 9 Environment |
10 """ | 10 """ |
(...skipping 14 matching lines...) Expand all Loading... |
25 # | 25 # |
26 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY | 26 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
27 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE | 27 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
28 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | 28 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
29 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | 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 | 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 | 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. | 32 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
33 # | 33 # |
34 | 34 |
35 __revision__ = "src/engine/SCons/Environment.py 3603 2008/10/10 05:46:45 scons" | 35 __revision__ = "src/engine/SCons/Environment.py 3842 2008/12/20 22:59:52 scons" |
36 | 36 |
37 | 37 |
38 import copy | 38 import copy |
39 import os | 39 import os |
40 import sys | 40 import sys |
41 import re | 41 import re |
42 import shlex | 42 import shlex |
43 import string | 43 import string |
44 from UserDict import UserDict | 44 from UserDict import UserDict |
45 | 45 |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
98 return | 98 return |
99 # Filter out null tools from the list. | 99 # Filter out null tools from the list. |
100 for tool in filter(None, tools): | 100 for tool in filter(None, tools): |
101 if SCons.Util.is_List(tool) or type(tool)==type(()): | 101 if SCons.Util.is_List(tool) or type(tool)==type(()): |
102 toolname = tool[0] | 102 toolname = tool[0] |
103 toolargs = tool[1] # should be a dict of kw args | 103 toolargs = tool[1] # should be a dict of kw args |
104 tool = apply(env.Tool, [toolname], toolargs) | 104 tool = apply(env.Tool, [toolname], toolargs) |
105 else: | 105 else: |
106 env.Tool(tool) | 106 env.Tool(tool) |
107 | 107 |
108 # These names are controlled by SCons; users should never set or override | 108 # These names are (or will be) controlled by SCons; users should never |
109 # them. This warning can optionally be turned off, but scons will still | 109 # set or override them. This warning can optionally be turned off, |
110 # ignore the illegal variable names even if it's off. | 110 # but scons will still ignore the illegal variable names even if it's off. |
111 reserved_construction_var_names = \ | 111 reserved_construction_var_names = [ |
112 ['TARGET', 'TARGETS', 'SOURCE', 'SOURCES'] | 112 'SOURCE', |
| 113 'SOURCES', |
| 114 'TARGET', |
| 115 'TARGETS', |
| 116 ] |
| 117 |
| 118 future_reserved_construction_var_names = [ |
| 119 'CHANGED_SOURCES', |
| 120 'CHANGED_TARGETS', |
| 121 'UNCHANGED_SOURCES', |
| 122 'UNCHANGED_TARGETS', |
| 123 ] |
113 | 124 |
114 def copy_non_reserved_keywords(dict): | 125 def copy_non_reserved_keywords(dict): |
115 result = semi_deepcopy(dict) | 126 result = semi_deepcopy(dict) |
116 for k in result.keys(): | 127 for k in result.keys(): |
117 if k in reserved_construction_var_names: | 128 if k in reserved_construction_var_names: |
118 SCons.Warnings.warn(SCons.Warnings.ReservedVariableWarning, | 129 msg = "Ignoring attempt to set reserved variable `$%s'" |
119 "Ignoring attempt to set reserved variable `%s'"
% k) | 130 SCons.Warnings.warn(SCons.Warnings.ReservedVariableWarning, msg % k) |
120 del result[k] | 131 del result[k] |
121 return result | 132 return result |
122 | 133 |
123 def _set_reserved(env, key, value): | 134 def _set_reserved(env, key, value): |
124 msg = "Ignoring attempt to set reserved variable `%s'" % key | 135 msg = "Ignoring attempt to set reserved variable `$%s'" |
125 SCons.Warnings.warn(SCons.Warnings.ReservedVariableWarning, msg) | 136 SCons.Warnings.warn(SCons.Warnings.ReservedVariableWarning, msg % key) |
| 137 |
| 138 def _set_future_reserved(env, key, value): |
| 139 env._dict[key] = value |
| 140 msg = "`$%s' will be reserved in a future release and setting it will become
ignored" |
| 141 SCons.Warnings.warn(SCons.Warnings.FutureReservedVariableWarning, msg % key) |
126 | 142 |
127 def _set_BUILDERS(env, key, value): | 143 def _set_BUILDERS(env, key, value): |
128 try: | 144 try: |
129 bd = env._dict[key] | 145 bd = env._dict[key] |
130 for k in bd.keys(): | 146 for k in bd.keys(): |
131 del bd[k] | 147 del bd[k] |
132 except KeyError: | 148 except KeyError: |
133 bd = BuilderDict(kwbd, env) | 149 bd = BuilderDict(kwbd, env) |
134 env._dict[key] = bd | 150 env._dict[key] = bd |
135 bd.update(value) | 151 bd.update(value) |
136 | 152 |
137 def _del_SCANNERS(env, key): | 153 def _del_SCANNERS(env, key): |
138 del env._dict[key] | 154 del env._dict[key] |
139 env.scanner_map_delete() | 155 env.scanner_map_delete() |
140 | 156 |
141 def _set_SCANNERS(env, key, value): | 157 def _set_SCANNERS(env, key, value): |
142 env._dict[key] = value | 158 env._dict[key] = value |
143 env.scanner_map_delete() | 159 env.scanner_map_delete() |
144 | 160 |
| 161 def _delete_duplicates(l, keep_last): |
| 162 """Delete duplicates from a sequence, keeping the first or last.""" |
| 163 seen={} |
| 164 result=[] |
| 165 if keep_last: # reverse in & out, then keep first |
| 166 l.reverse() |
| 167 for i in l: |
| 168 try: |
| 169 if not seen.has_key(i): |
| 170 result.append(i) |
| 171 seen[i]=1 |
| 172 except TypeError: |
| 173 # probably unhashable. Just keep it. |
| 174 result.append(i) |
| 175 if keep_last: |
| 176 result.reverse() |
| 177 return result |
| 178 |
145 | 179 |
146 | 180 |
147 # The following is partly based on code in a comment added by Peter | 181 # The following is partly based on code in a comment added by Peter |
148 # Shannon at the following page (there called the "transplant" class): | 182 # Shannon at the following page (there called the "transplant" class): |
149 # | 183 # |
150 # ASPN : Python Cookbook : Dynamically added methods to a class | 184 # ASPN : Python Cookbook : Dynamically added methods to a class |
151 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81732 | 185 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81732 |
152 # | 186 # |
153 # We had independently been using the idiom as BuilderWrapper, but | 187 # We had independently been using the idiom as BuilderWrapper, but |
154 # factoring out the common parts into this base class, and making | 188 # factoring out the common parts into this base class, and making |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
212 if source is _null: | 246 if source is _null: |
213 source = target | 247 source = target |
214 target = None | 248 target = None |
215 if not target is None and not SCons.Util.is_List(target): | 249 if not target is None and not SCons.Util.is_List(target): |
216 target = [target] | 250 target = [target] |
217 if not source is None and not SCons.Util.is_List(source): | 251 if not source is None and not SCons.Util.is_List(source): |
218 source = [source] | 252 source = [source] |
219 return apply(MethodWrapper.__call__, (self, target, source) + args, kw) | 253 return apply(MethodWrapper.__call__, (self, target, source) + args, kw) |
220 | 254 |
221 def __repr__(self): | 255 def __repr__(self): |
222 fmt = '<BuilderWrapper %s instance at 0x%08X>' | 256 return '<BuilderWrapper %s>' % repr(self.name) |
223 return fmt % (repr(self.name), id(self)) | |
224 | 257 |
225 def __str__(self): | 258 def __str__(self): |
226 return self.__repr__() | 259 return self.__repr__() |
227 | 260 |
228 def __getattr__(self, name): | 261 def __getattr__(self, name): |
229 if name == 'env': | 262 if name == 'env': |
230 return self.object | 263 return self.object |
231 elif name == 'builder': | 264 elif name == 'builder': |
232 return self.method | 265 return self.method |
233 else: | 266 else: |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
340 | 373 |
341 def _init_special(self): | 374 def _init_special(self): |
342 """Initial the dispatch tables for special handling of | 375 """Initial the dispatch tables for special handling of |
343 special construction variables.""" | 376 special construction variables.""" |
344 self._special_del = {} | 377 self._special_del = {} |
345 self._special_del['SCANNERS'] = _del_SCANNERS | 378 self._special_del['SCANNERS'] = _del_SCANNERS |
346 | 379 |
347 self._special_set = {} | 380 self._special_set = {} |
348 for key in reserved_construction_var_names: | 381 for key in reserved_construction_var_names: |
349 self._special_set[key] = _set_reserved | 382 self._special_set[key] = _set_reserved |
| 383 for key in future_reserved_construction_var_names: |
| 384 self._special_set[key] = _set_future_reserved |
350 self._special_set['BUILDERS'] = _set_BUILDERS | 385 self._special_set['BUILDERS'] = _set_BUILDERS |
351 self._special_set['SCANNERS'] = _set_SCANNERS | 386 self._special_set['SCANNERS'] = _set_SCANNERS |
352 | 387 |
353 # Freeze the keys of self._special_set in a list for use by | 388 # Freeze the keys of self._special_set in a list for use by |
354 # methods that need to check. (Empirically, list scanning has | 389 # methods that need to check. (Empirically, list scanning has |
355 # gotten better than dict.has_key() in Python 2.5.) | 390 # gotten better than dict.has_key() in Python 2.5.) |
356 self._special_set_keys = self._special_set.keys() | 391 self._special_set_keys = self._special_set.keys() |
357 | 392 |
358 def __cmp__(self, other): | 393 def __cmp__(self, other): |
359 return cmp(self._dict, other._dict) | 394 return cmp(self._dict, other._dict) |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
393 raise SCons.Errors.UserError, "Illegal construction variable
`%s'" % key | 428 raise SCons.Errors.UserError, "Illegal construction variable
`%s'" % key |
394 self._dict[key] = value | 429 self._dict[key] = value |
395 | 430 |
396 def get(self, key, default=None): | 431 def get(self, key, default=None): |
397 "Emulates the get() method of dictionaries.""" | 432 "Emulates the get() method of dictionaries.""" |
398 return self._dict.get(key, default) | 433 return self._dict.get(key, default) |
399 | 434 |
400 def has_key(self, key): | 435 def has_key(self, key): |
401 return self._dict.has_key(key) | 436 return self._dict.has_key(key) |
402 | 437 |
| 438 def __contains__(self, key): |
| 439 return self._dict.__contains__(key) |
| 440 |
403 def items(self): | 441 def items(self): |
404 return self._dict.items() | 442 return self._dict.items() |
405 | 443 |
406 def arg2nodes(self, args, node_factory=_null, lookup_list=_null, **kw): | 444 def arg2nodes(self, args, node_factory=_null, lookup_list=_null, **kw): |
407 if node_factory is _null: | 445 if node_factory is _null: |
408 node_factory = self.fs.File | 446 node_factory = self.fs.File |
409 if lookup_list is _null: | 447 if lookup_list is _null: |
410 lookup_list = self.lookup_list | 448 lookup_list = self.lookup_list |
411 | 449 |
412 if not args: | 450 if not args: |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
521 else: | 559 else: |
522 p = s(p) | 560 p = s(p) |
523 r.append(p) | 561 r.append(p) |
524 return r | 562 return r |
525 | 563 |
526 subst_target_source = subst | 564 subst_target_source = subst |
527 | 565 |
528 def backtick(self, command): | 566 def backtick(self, command): |
529 import subprocess | 567 import subprocess |
530 # common arguments | 568 # common arguments |
531 kw = { 'stdout' : subprocess.PIPE, | 569 kw = { 'stdin' : 'devnull', |
| 570 'stdout' : subprocess.PIPE, |
532 'stderr' : subprocess.PIPE, | 571 'stderr' : subprocess.PIPE, |
533 'universal_newlines' : True, | 572 'universal_newlines' : True, |
534 } | 573 } |
535 # if the command is a list, assume it's been quoted | 574 # if the command is a list, assume it's been quoted |
536 # othewise force a shell | 575 # othewise force a shell |
537 if not SCons.Util.is_List(command): kw['shell'] = True | 576 if not SCons.Util.is_List(command): kw['shell'] = True |
538 # run constructed command | 577 # run constructed command |
539 #TODO(1.5) p = SCons.Action._subproc(self, command, **kw) | 578 #TODO(1.5) p = SCons.Action._subproc(self, command, **kw) |
540 p = apply(SCons.Action._subproc, (self, command), kw) | 579 p = apply(SCons.Action._subproc, (self, command), kw) |
541 out,err = p.communicate() | 580 out,err = p.communicate() |
(...skipping 641 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1183 self._dict[envname][name] = nv | 1222 self._dict[envname][name] = nv |
1184 | 1223 |
1185 def AppendUnique(self, delete_existing=0, **kw): | 1224 def AppendUnique(self, delete_existing=0, **kw): |
1186 """Append values to existing construction variables | 1225 """Append values to existing construction variables |
1187 in an Environment, if they're not already there. | 1226 in an Environment, if they're not already there. |
1188 If delete_existing is 1, removes existing values first, so | 1227 If delete_existing is 1, removes existing values first, so |
1189 values move to end. | 1228 values move to end. |
1190 """ | 1229 """ |
1191 kw = copy_non_reserved_keywords(kw) | 1230 kw = copy_non_reserved_keywords(kw) |
1192 for key, val in kw.items(): | 1231 for key, val in kw.items(): |
| 1232 if SCons.Util.is_List(val): |
| 1233 val = _delete_duplicates(val, delete_existing) |
1193 if not self._dict.has_key(key) or self._dict[key] in ('', None): | 1234 if not self._dict.has_key(key) or self._dict[key] in ('', None): |
1194 self._dict[key] = val | 1235 self._dict[key] = val |
1195 elif SCons.Util.is_Dict(self._dict[key]) and \ | 1236 elif SCons.Util.is_Dict(self._dict[key]) and \ |
1196 SCons.Util.is_Dict(val): | 1237 SCons.Util.is_Dict(val): |
1197 self._dict[key].update(val) | 1238 self._dict[key].update(val) |
1198 elif SCons.Util.is_List(val): | 1239 elif SCons.Util.is_List(val): |
1199 dk = self._dict[key] | 1240 dk = self._dict[key] |
1200 if not SCons.Util.is_List(dk): | 1241 if not SCons.Util.is_List(dk): |
1201 dk = [dk] | 1242 dk = [dk] |
1202 if delete_existing: | 1243 if delete_existing: |
(...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1536 self._dict[envname][name] = nv | 1577 self._dict[envname][name] = nv |
1537 | 1578 |
1538 def PrependUnique(self, delete_existing=0, **kw): | 1579 def PrependUnique(self, delete_existing=0, **kw): |
1539 """Prepend values to existing construction variables | 1580 """Prepend values to existing construction variables |
1540 in an Environment, if they're not already there. | 1581 in an Environment, if they're not already there. |
1541 If delete_existing is 1, removes existing values first, so | 1582 If delete_existing is 1, removes existing values first, so |
1542 values move to front. | 1583 values move to front. |
1543 """ | 1584 """ |
1544 kw = copy_non_reserved_keywords(kw) | 1585 kw = copy_non_reserved_keywords(kw) |
1545 for key, val in kw.items(): | 1586 for key, val in kw.items(): |
| 1587 if SCons.Util.is_List(val): |
| 1588 val = _delete_duplicates(val, not delete_existing) |
1546 if not self._dict.has_key(key) or self._dict[key] in ('', None): | 1589 if not self._dict.has_key(key) or self._dict[key] in ('', None): |
1547 self._dict[key] = val | 1590 self._dict[key] = val |
1548 elif SCons.Util.is_Dict(self._dict[key]) and \ | 1591 elif SCons.Util.is_Dict(self._dict[key]) and \ |
1549 SCons.Util.is_Dict(val): | 1592 SCons.Util.is_Dict(val): |
1550 self._dict[key].update(val) | 1593 self._dict[key].update(val) |
1551 elif SCons.Util.is_List(val): | 1594 elif SCons.Util.is_List(val): |
1552 dk = self._dict[key] | 1595 dk = self._dict[key] |
1553 if not SCons.Util.is_List(dk): | 1596 if not SCons.Util.is_List(dk): |
1554 dk = [dk] | 1597 dk = [dk] |
1555 if delete_existing: | 1598 if delete_existing: |
(...skipping 606 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2162 try: | 2205 try: |
2163 return self.__dict__['overrides'][key] | 2206 return self.__dict__['overrides'][key] |
2164 except KeyError: | 2207 except KeyError: |
2165 return self.__dict__['__subject'].get(key, default) | 2208 return self.__dict__['__subject'].get(key, default) |
2166 def has_key(self, key): | 2209 def has_key(self, key): |
2167 try: | 2210 try: |
2168 self.__dict__['overrides'][key] | 2211 self.__dict__['overrides'][key] |
2169 return 1 | 2212 return 1 |
2170 except KeyError: | 2213 except KeyError: |
2171 return self.__dict__['__subject'].has_key(key) | 2214 return self.__dict__['__subject'].has_key(key) |
| 2215 def __contains__(self, key): |
| 2216 if self.__dict__['overrides'].__contains__(key): |
| 2217 return 1 |
| 2218 return self.__dict__['__subject'].__contains__(key) |
2172 def Dictionary(self): | 2219 def Dictionary(self): |
2173 """Emulates the items() method of dictionaries.""" | 2220 """Emulates the items() method of dictionaries.""" |
2174 d = self.__dict__['__subject'].Dictionary().copy() | 2221 d = self.__dict__['__subject'].Dictionary().copy() |
2175 d.update(self.__dict__['overrides']) | 2222 d.update(self.__dict__['overrides']) |
2176 return d | 2223 return d |
2177 def items(self): | 2224 def items(self): |
2178 """Emulates the items() method of dictionaries.""" | 2225 """Emulates the items() method of dictionaries.""" |
2179 return self.Dictionary().items() | 2226 return self.Dictionary().items() |
2180 | 2227 |
2181 # Overridden private construction environment methods. | 2228 # Overridden private construction environment methods. |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2244 nkw['gvars'] = {} | 2291 nkw['gvars'] = {} |
2245 self.raw_to_mode(nkw) | 2292 self.raw_to_mode(nkw) |
2246 return apply(SCons.Subst.scons_subst_list, nargs, nkw) | 2293 return apply(SCons.Subst.scons_subst_list, nargs, nkw) |
2247 def subst_target_source(self, string, *args, **kwargs): | 2294 def subst_target_source(self, string, *args, **kwargs): |
2248 nargs = (string, self,) + args | 2295 nargs = (string, self,) + args |
2249 nkw = kwargs.copy() | 2296 nkw = kwargs.copy() |
2250 nkw['gvars'] = {} | 2297 nkw['gvars'] = {} |
2251 self.raw_to_mode(nkw) | 2298 self.raw_to_mode(nkw) |
2252 return apply(SCons.Subst.scons_subst, nargs, nkw) | 2299 return apply(SCons.Subst.scons_subst, nargs, nkw) |
2253 return _NoSubstitutionProxy(subject) | 2300 return _NoSubstitutionProxy(subject) |
OLD | NEW |