Package SCons :: Package Node
[hide private]
[frames] | no frames]

Source Code for Package SCons.Node

   1  """SCons.Node 
   2   
   3  The Node package for the SCons software construction utility. 
   4   
   5  This is, in many ways, the heart of SCons. 
   6   
   7  A Node is where we encapsulate all of the dependency information about 
   8  any thing that SCons can build, or about any thing which SCons can use 
   9  to build some other thing.  The canonical "thing," of course, is a file, 
  10  but a Node can also represent something remote (like a web page) or 
  11  something completely abstract (like an Alias). 
  12   
  13  Each specific type of "thing" is specifically represented by a subclass 
  14  of the Node base class:  Node.FS.File for files, Node.Alias for aliases, 
  15  etc.  Dependency information is kept here in the base class, and 
  16  information specific to files/aliases/etc. is in the subclass.  The 
  17  goal, if we've done this correctly, is that any type of "thing" should 
  18  be able to depend on any other type of "thing." 
  19   
  20  """ 
  21   
  22  # 
  23  # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation 
  24  # 
  25  # Permission is hereby granted, free of charge, to any person obtaining 
  26  # a copy of this software and associated documentation files (the 
  27  # "Software"), to deal in the Software without restriction, including 
  28  # without limitation the rights to use, copy, modify, merge, publish, 
  29  # distribute, sublicense, and/or sell copies of the Software, and to 
  30  # permit persons to whom the Software is furnished to do so, subject to 
  31  # the following conditions: 
  32  # 
  33  # The above copyright notice and this permission notice shall be included 
  34  # in all copies or substantial portions of the Software. 
  35  # 
  36  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 
  37  # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 
  38  # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
  39  # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
  40  # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
  41  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
  42  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
  43  # 
  44   
  45  __revision__ = "src/engine/SCons/Node/__init__.py 3765 2008/11/04 08:12:16 scons" 
  46   
  47  import copy 
  48  from itertools import chain, izip 
  49  import string 
  50  import UserList 
  51   
  52  from SCons.Debug import logInstanceCreation 
  53  import SCons.Executor 
  54  import SCons.Memoize 
  55  import SCons.Util 
  56   
  57  from SCons.Debug import Trace 
  58   
59 -def classname(obj):
60 return string.split(str(obj.__class__), '.')[-1]
61 62 # Node states 63 # 64 # These are in "priority" order, so that the maximum value for any 65 # child/dependency of a node represents the state of that node if 66 # it has no builder of its own. The canonical example is a file 67 # system directory, which is only up to date if all of its children 68 # were up to date. 69 no_state = 0 70 pending = 1 71 executing = 2 72 up_to_date = 3 73 executed = 4 74 failed = 5 75 76 StateString = { 77 0 : "no_state", 78 1 : "pending", 79 2 : "executing", 80 3 : "up_to_date", 81 4 : "executed", 82 5 : "failed", 83 } 84 85 # controls whether implicit dependencies are cached: 86 implicit_cache = 0 87 88 # controls whether implicit dep changes are ignored: 89 implicit_deps_unchanged = 0 90 91 # controls whether the cached implicit deps are ignored: 92 implicit_deps_changed = 0 93 94 # A variable that can be set to an interface-specific function be called 95 # to annotate a Node with information about its creation.
96 -def do_nothing(node): pass
97 98 Annotate = do_nothing 99 100 # Classes for signature info for Nodes. 101
102 -class NodeInfoBase:
103 """ 104 The generic base class for signature information for a Node. 105 106 Node subclasses should subclass NodeInfoBase to provide their own 107 logic for dealing with their own Node-specific signature information. 108 """ 109 current_version_id = 1
110 - def __init__(self, node):
111 # Create an object attribute from the class attribute so it ends up 112 # in the pickled data in the .sconsign file. 113 self._version_id = self.current_version_id
114 - def update(self, node):
115 try: 116 field_list = self.field_list 117 except AttributeError: 118 return 119 for f in field_list: 120 try: 121 delattr(self, f) 122 except AttributeError: 123 pass 124 try: 125 func = getattr(node, 'get_' + f) 126 except AttributeError: 127 pass 128 else: 129 setattr(self, f, func())
130 - def convert(self, node, val):
131 pass
132 - def merge(self, other):
133 self.__dict__.update(other.__dict__)
134 - def format(self, field_list=None, names=0):
135 if field_list is None: 136 try: 137 field_list = self.field_list 138 except AttributeError: 139 field_list = self.__dict__.keys() 140 field_list.sort() 141 fields = [] 142 for field in field_list: 143 try: 144 f = getattr(self, field) 145 except AttributeError: 146 f = None 147 f = str(f) 148 if names: 149 f = field + ': ' + f 150 fields.append(f) 151 return fields
152
153 -class BuildInfoBase:
154 """ 155 The generic base class for build information for a Node. 156 157 This is what gets stored in a .sconsign file for each target file. 158 It contains a NodeInfo instance for this node (signature information 159 that's specific to the type of Node) and direct attributes for the 160 generic build stuff we have to track: sources, explicit dependencies, 161 implicit dependencies, and action information. 162 """ 163 current_version_id = 1
164 - def __init__(self, node):
165 # Create an object attribute from the class attribute so it ends up 166 # in the pickled data in the .sconsign file. 167 self._version_id = self.current_version_id 168 self.bsourcesigs = [] 169 self.bdependsigs = [] 170 self.bimplicitsigs = [] 171 self.bactsig = None
172 - def merge(self, other):
173 self.__dict__.update(other.__dict__)
174
175 -class Node:
176 """The base Node class, for entities that we know how to 177 build, or use to build other Nodes. 178 """ 179 180 if SCons.Memoize.use_memoizer: 181 __metaclass__ = SCons.Memoize.Memoized_Metaclass 182 183 memoizer_counters = [] 184
185 - class Attrs:
186 pass
187
188 - def __init__(self):
189 if __debug__: logInstanceCreation(self, 'Node.Node') 190 # Note that we no longer explicitly initialize a self.builder 191 # attribute to None here. That's because the self.builder 192 # attribute may be created on-the-fly later by a subclass (the 193 # canonical example being a builder to fetch a file from a 194 # source code system like CVS or Subversion). 195 196 # Each list of children that we maintain is accompanied by a 197 # dictionary used to look up quickly whether a node is already 198 # present in the list. Empirical tests showed that it was 199 # fastest to maintain them as side-by-side Node attributes in 200 # this way, instead of wrapping up each list+dictionary pair in 201 # a class. (Of course, we could always still do that in the 202 # future if we had a good reason to...). 203 self.sources = [] # source files used to build node 204 self.sources_set = set() 205 self._specific_sources = False 206 self.depends = [] # explicit dependencies (from Depends) 207 self.depends_set = set() 208 self.ignore = [] # dependencies to ignore 209 self.ignore_set = set() 210 self.prerequisites = SCons.Util.UniqueList() 211 self.implicit = None # implicit (scanned) dependencies (None means not scanned yet) 212 self.waiting_parents = set() 213 self.waiting_s_e = set() 214 self.ref_count = 0 215 self.wkids = None # Kids yet to walk, when it's an array 216 217 self.env = None 218 self.state = no_state 219 self.precious = None 220 self.noclean = 0 221 self.nocache = 0 222 self.always_build = None 223 self.includes = None 224 self.attributes = self.Attrs() # Generic place to stick information about the Node. 225 self.side_effect = 0 # true iff this node is a side effect 226 self.side_effects = [] # the side effects of building this target 227 self.linked = 0 # is this node linked to the variant directory? 228 229 self.clear_memoized_values() 230 231 # Let the interface in which the build engine is embedded 232 # annotate this Node with its own info (like a description of 233 # what line in what file created the node, for example). 234 Annotate(self)
235
236 - def disambiguate(self, must_exist=None):
237 return self
238
239 - def get_suffix(self):
240 return ''
241 242 memoizer_counters.append(SCons.Memoize.CountValue('get_build_env')) 243
244 - def get_build_env(self):
245 """Fetch the appropriate Environment to build this node. 246 """ 247 try: 248 return self._memo['get_build_env'] 249 except KeyError: 250 pass 251 result = self.get_executor().get_build_env() 252 self._memo['get_build_env'] = result 253 return result
254
255 - def get_build_scanner_path(self, scanner):
256 """Fetch the appropriate scanner path for this node.""" 257 return self.get_executor().get_build_scanner_path(scanner)
258
259 - def set_executor(self, executor):
260 """Set the action executor for this node.""" 261 self.executor = executor
262
263 - def get_executor(self, create=1):
264 """Fetch the action executor for this node. Create one if 265 there isn't already one, and requested to do so.""" 266 try: 267 executor = self.executor 268 except AttributeError: 269 if not create: 270 raise 271 try: 272 act = self.builder.action 273 except AttributeError: 274 executor = SCons.Executor.Null(targets=[self]) 275 else: 276 executor = SCons.Executor.Executor(act, 277 self.env or self.builder.env, 278 [self.builder.overrides], 279 [self], 280 self.sources) 281 self.executor = executor 282 return executor
283
284 - def executor_cleanup(self):
285 """Let the executor clean up any cached information.""" 286 try: 287 executor = self.get_executor(create=None) 288 except AttributeError: 289 pass 290 else: 291 executor.cleanup()
292
293 - def reset_executor(self):
294 "Remove cached executor; forces recompute when needed." 295 try: 296 delattr(self, 'executor') 297 except AttributeError: 298 pass
299
300 - def retrieve_from_cache(self):
301 """Try to retrieve the node's content from a cache 302 303 This method is called from multiple threads in a parallel build, 304 so only do thread safe stuff here. Do thread unsafe stuff in 305 built(). 306 307 Returns true iff the node was successfully retrieved. 308 """ 309 return 0
310 311 # 312 # Taskmaster interface subsystem 313 # 314
315 - def make_ready(self):
316 """Get a Node ready for evaluation. 317 318 This is called before the Taskmaster decides if the Node is 319 up-to-date or not. Overriding this method allows for a Node 320 subclass to be disambiguated if necessary, or for an implicit 321 source builder to be attached. 322 """ 323 pass
324
325 - def prepare(self):
326 """Prepare for this Node to be built. 327 328 This is called after the Taskmaster has decided that the Node 329 is out-of-date and must be rebuilt, but before actually calling 330 the method to build the Node. 331 332 This default implementation checks that explicit or implicit 333 dependencies either exist or are derived, and initializes the 334 BuildInfo structure that will hold the information about how 335 this node is, uh, built. 336 337 (The existence of source files is checked separately by the 338 Executor, which aggregates checks for all of the targets built 339 by a specific action.) 340 341 Overriding this method allows for for a Node subclass to remove 342 the underlying file from the file system. Note that subclass 343 methods should call this base class method to get the child 344 check and the BuildInfo structure. 345 """ 346 for d in self.depends: 347 if d.missing(): 348 msg = "Explicit dependency `%s' not found, needed by target `%s'." 349 raise SCons.Errors.StopError, msg % (d, self) 350 if not self.implicit is None: 351 for i in self.implicit: 352 if i.missing(): 353 msg = "Implicit dependency `%s' not found, needed by target `%s'." 354 raise SCons.Errors.StopError, msg % (i, self) 355 self.binfo = self.get_binfo()
356
357 - def build(self, **kw):
358 """Actually build the node. 359 360 This is called by the Taskmaster after it's decided that the 361 Node is out-of-date and must be rebuilt, and after the prepare() 362 method has gotten everything, uh, prepared. 363 364 This method is called from multiple threads in a parallel build, 365 so only do thread safe stuff here. Do thread unsafe stuff 366 in built(). 367 368 """ 369 try: 370 apply(self.get_executor(), (self,), kw) 371 except SCons.Errors.BuildError, e: 372 e.node = self 373 raise
374
375 - def built(self):
376 """Called just after this node is successfully built.""" 377 378 # Clear the implicit dependency caches of any Nodes 379 # waiting for this Node to be built. 380 for parent in self.waiting_parents: 381 parent.implicit = None 382 383 self.clear() 384 385 self.ninfo.update(self)
386
387 - def visited(self):
388 """Called just after this node has been visited (with or 389 without a build).""" 390 try: 391 binfo = self.binfo 392 except AttributeError: 393 # Apparently this node doesn't need build info, so 394 # don't bother calculating or storing it. 395 pass 396 else: 397 self.ninfo.update(self) 398 self.store_info()
399 400 # 401 # 402 # 403
404 - def add_to_waiting_s_e(self, node):
405 self.waiting_s_e.add(node)
406
407 - def add_to_waiting_parents(self, node):
408 """ 409 Returns the number of nodes added to our waiting parents list: 410 1 if we add a unique waiting parent, 0 if not. (Note that the 411 returned values are intended to be used to increment a reference 412 count, so don't think you can "clean up" this function by using 413 True and False instead...) 414 """