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

Source Code for Module SCons.Environment

   1  """SCons.Environment 
   2   
   3  Base class for construction Environments.  These are 
   4  the primary objects used to communicate dependency and 
   5  construction information to the build engine. 
   6   
   7  Keyword arguments supplied when the construction Environment 
   8  is created are construction variables used to initialize the 
   9  Environment 
  10  """ 
  11   
  12  # 
  13  # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation 
  14  # 
  15  # Permission is hereby granted, free of charge, to any person obtaining 
  16  # a copy of this software and associated documentation files (the 
  17  # "Software"), to deal in the Software without restriction, including 
  18  # without limitation the rights to use, copy, modify, merge, publish, 
  19  # distribute, sublicense, and/or sell copies of the Software, and to 
  20  # permit persons to whom the Software is furnished to do so, subject to 
  21  # the following conditions: 
  22  # 
  23  # The above copyright notice and this permission notice shall be included 
  24  # in all copies or substantial portions of the Software. 
  25  # 
  26  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 
  27  # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 
  28  # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
  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 
  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. 
  33  # 
  34   
  35  __revision__ = "src/engine/SCons/Environment.py 2928 2008/04/29 22:44:09 knight" 
  36   
  37   
  38  import copy 
  39  import os 
  40  import os.path 
  41  import re 
  42  import shlex 
  43  import string 
  44  from UserDict import UserDict 
  45   
  46  import SCons.Action 
  47  import SCons.Builder 
  48  from SCons.Debug import logInstanceCreation 
  49  import SCons.Defaults 
  50  import SCons.Errors 
  51  import SCons.Memoize 
  52  import SCons.Node 
  53  import SCons.Node.Alias 
  54  import SCons.Node.FS 
  55  import SCons.Node.Python 
  56  import SCons.Platform 
  57  import SCons.SConsign 
  58  import SCons.Subst 
  59  import SCons.Tool 
  60  import SCons.Util 
  61  import SCons.Warnings 
  62   
63 -class _Null:
64 pass
65 66 _null = _Null 67 68 _warn_copy_deprecated = True 69 _warn_source_signatures_deprecated = True 70 _warn_target_signatures_deprecated = True 71 72 CleanTargets = {} 73 CalculatorArgs = {} 74 75 semi_deepcopy = SCons.Util.semi_deepcopy 76 77 # Pull UserError into the global name space for the benefit of 78 # Environment().SourceSignatures(), which has some import statements 79 # which seem to mess up its ability to reference SCons directly. 80 UserError = SCons.Errors.UserError 81
82 -def alias_builder(env, target, source):
83 pass
84 85 AliasBuilder = SCons.Builder.Builder(action = alias_builder, 86 target_factory = SCons.Node.Alias.default_ans.Alias, 87 source_factory = SCons.Node.FS.Entry, 88 multi = 1, 89 is_explicit = None, 90 name='AliasBuilder') 91
92 -def apply_tools(env, tools, toolpath):
93 # Store the toolpath in the Environment. 94 if toolpath is not None: 95 env['toolpath'] = toolpath 96 97 if not tools: 98 return 99 # Filter out null tools from the list. 100 for tool in filter(None, tools): 101 if SCons.Util.is_List(tool) or type(tool)==type(()): 102 toolname = tool[0] 103 toolargs = tool[1] # should be a dict of kw args 104 tool = apply(env.Tool, [toolname], toolargs) 105 else: 106 env.Tool(tool)
107 108 # These names are controlled by SCons; users should never set or override 109 # them. This warning can optionally be turned off, but scons will still 110 # ignore the illegal variable names even if it's off. 111 reserved_construction_var_names = \ 112 ['TARGET', 'TARGETS', 'SOURCE', 'SOURCES'] 113
114 -def copy_non_reserved_keywords(dict):
115 result = semi_deepcopy(dict) 116 for k in result.keys(): 117 if k in reserved_construction_var_names: 118 SCons.Warnings.warn(SCons.Warnings.ReservedVariableWarning, 119 "Ignoring attempt to set reserved variable `%s'" % k) 120 del result[k] 121 return result
122
123 -def _set_reserved(env, key, value):
124 msg = "Ignoring attempt to set reserved variable `%s'" % key 125 SCons.Warnings.warn(SCons.Warnings.ReservedVariableWarning, msg)
126
127 -def _set_BUILDERS(env, key, value):
128 try: 129 bd = env._dict[key] 130 for k in bd.keys(): 131 del bd[k] 132 except KeyError: 133 bd = BuilderDict(kwbd, env) 134 env._dict[key] = bd 135 bd.update(value)
136
137 -def _del_SCANNERS(env, key):
138 del env._dict[key] 139 env.scanner_map_delete()
140
141 -def _set_SCANNERS(env, key, value):
142 env._dict[key] = value 143 env.scanner_map_delete()
144 145 146 147 # The following is partly based on code in a comment added by Peter 148 # Shannon at the following page (there called the "transplant" class): 149 # 150 # ASPN : Python Cookbook : Dynamically added methods to a class 151 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81732 152 # 153 # We had independently been using the idiom as BuilderWrapper, but 154 # factoring out the common parts into this base class, and making 155 # BuilderWrapper a subclass that overrides __call__() to enforce specific 156 # Builder calling conventions, simplified some of our higher-layer code. 157
158 -class MethodWrapper:
159 """ 160 A generic Wrapper class that associates a method (which can 161 actually be any callable) with an object. As part of creating this 162 MethodWrapper object an attribute with the specified (by default, 163 the name of the supplied method) is added to the underlying object. 164 When that new "method" is called, our __call__() method adds the 165 object as the first argument, simulating the Python behavior of 166 supplying "self" on method calls. 167 168 We hang on to the name by which the method was added to the underlying 169 base class so that we can provide a method to "clone" ourselves onto 170 a new underlying object being copied (without which we wouldn't need 171 to save that info). 172 """
173 - def __init__(self, object, method, name=None):
174 if name is None: 175 name = method.__name__ 176 self.object = object 177 self.method = method 178 self.name = name 179 setattr(self.object, name, self)
180
181 - def __call__(self, *args, **kwargs):
182 nargs = (self.object,) + args 183 return apply(self.method, nargs, kwargs)
184
185 - def clone(self, new_object):
186 """ 187 Returns an object that re-binds the underlying "method" to 188 the specified new object. 189 """ 190 return self.__class__(new_object, self.method, self.name)
191
192 -class BuilderWrapper(MethodWrapper):
193 """ 194 A MethodWrapper subclass that that associates an environment with 195 a Builder. 196 197 This mainly exists to wrap the __call__() function so that all calls 198 to Builders can have their argument lists massaged in the same way 199 (treat a lone argument as the source, treat two arguments as target 200 then source, make sure both target and source are lists) without 201 having to have cut-and-paste code to do it. 202 203 As a bit of obsessive backwards compatibility, we also intercept 204 attempts to get or set the "env" or "builder" attributes, which were 205 the names we used before we put the common functionality into the 206 MethodWrapper base class. We'll keep this around for a while in case 207 people shipped Tool modules that reached into the wrapper (like the 208 Tool/qt.py module does, or did). There shouldn't be a lot attribute 209 fetching or setting on these, so a little extra work shouldn't hurt. 210 """
211 - def __call__(self, target=None, source=_null, *args, **kw):
212 if source is _null: 213 source = target 214 target = None 215 if not target is None and not SCons.Util.is_List(target): 216 target = [target] 217 if not source is None and not SCons.Util.is_List(source): 218 source = [source] 219 return apply(MethodWrapper.__call__, (self, target, source) + args, kw)
220
221 - def __repr__(self):
222 return '<BuilderWrapper %s>' % repr(self.name)
223
224 - def __str__(self):
225 return self.__repr__()
226
227 - def __getattr__(self, name):
228 if name == 'env': 229 return self.object 230 elif name == 'builder': 231 return self.method 232 else: 233 return self.__dict__[name]
234
235 - def __setattr__(self, name, value):
236 if name == 'env': 237 self.object = value 238 elif name == 'builder': 239 self.method = value 240 else: 241 self.__dict__[name] = value
242 243 # This allows a Builder to be executed directly 244 # through the Environment to which it's attached. 245 # In practice, we shouldn't need this, because 246 # builders actually get executed through a Node. 247 # But we do have a unit test for this, and can't 248 # yet rule out that it would be useful in the 249 # future, so leave it for now. 250 #def execute(self, **kw): 251 # kw['env'] = self.env 252 # apply(self.builder.execute, (), kw) 253
254 -class BuilderDict(UserDict):
255 """This is a dictionary-like class used by an Environment to hold 256 the Builders. We need to do this because every time someone changes 257 the Builders in the Environment's BUILDERS dictionary, we must 258 update the Environment's attributes."""
259 - def __init__(self, dict, env):
260 # Set self.env before calling the superclass initialization, 261 # because it will end up calling our other methods, which will 262 # need to point the values in this dictionary to self.env. 263 self.env = env 264 UserDict.__init__(self, dict)
265
266 - def __semi_deepcopy__(self):
267 return self.__class__(self.data, self.env)
268
269 - def __setitem__(self, item, val):
270 try: 271 method = getattr(self.env, item).method 272 except AttributeError: 273 pass 274 else: 275 self.env.RemoveMethod(method) 276 UserDict.__setitem__(self, item, val) 277 BuilderWrapper(self.env, val, item)
278
279 - def __delitem__(self, item):
280 UserDict.__delitem__(self, item) 281 delattr(self.env, item)
282
283 - def update(self, dict):
284 for i, v in dict.items(): 285 self.__setitem__(i, v)
286 287 288 289 _is_valid_var = re.compile(r'[_a-zA-Z]\w*$') 290
291 -def is_valid_construction_var(varstr):
292 """Return if the specified string is a legitimate construction 293 variable. 294 """ 295 return _is_valid_var.match(varstr)
296 297 298
299 -class SubstitutionEnvironment:
300