Package SCons :: Package Script :: Module Main
[hide private]
[frames] | no frames]

Source Code for Module SCons.Script.Main

   1  """SCons.Script 
   2   
   3  This file implements the main() function used by the scons script. 
   4   
   5  Architecturally, this *is* the scons script, and will likely only be 
   6  called from the external "scons" wrapper.  Consequently, anything here 
   7  should not be, or be considered, part of the build engine.  If it's 
   8  something that we expect other software to want to use, it should go in 
   9  some other module.  If it's specific to the "scons" script invocation, 
  10  it goes here. 
  11  """ 
  12   
  13  unsupported_python_version = (2, 3, 0) 
  14  deprecated_python_version = (2, 7, 0) 
  15   
  16  # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 The SCons Foundation 
  17  # 
  18  # Permission is hereby granted, free of charge, to any person obtaining 
  19  # a copy of this software and associated documentation files (the 
  20  # "Software"), to deal in the Software without restriction, including 
  21  # without limitation the rights to use, copy, modify, merge, publish, 
  22  # distribute, sublicense, and/or sell copies of the Software, and to 
  23  # permit persons to whom the Software is furnished to do so, subject to 
  24  # the following conditions: 
  25  # 
  26  # The above copyright notice and this permission notice shall be included 
  27  # in all copies or substantial portions of the Software. 
  28  # 
  29  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 
  30  # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 
  31  # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
  32  # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
  33  # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
  34  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
  35  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
  36   
  37  __revision__ = "src/engine/SCons/Script/Main.py  2013/03/03 09:48:35 garyo" 
  38   
  39  import SCons.compat 
  40   
  41  import os 
  42  import sys 
  43  import time 
  44  import traceback 
  45   
  46  # Strip the script directory from sys.path() so on case-insensitive 
  47  # (Windows) systems Python doesn't think that the "scons" script is the 
  48  # "SCons" package.  Replace it with our own version directory so, if 
  49  # if they're there, we pick up the right version of the build engine 
  50  # modules. 
  51  #sys.path = [os.path.join(sys.prefix, 
  52  #                         'lib', 
  53  #                         'scons-%d' % SCons.__version__)] + sys.path[1:] 
  54   
  55  import SCons.CacheDir 
  56  import SCons.Debug 
  57  import SCons.Defaults 
  58  import SCons.Environment 
  59  import SCons.Errors 
  60  import SCons.Job 
  61  import SCons.Node 
  62  import SCons.Node.FS 
  63  import SCons.Platform 
  64  import SCons.SConf 
  65  import SCons.Script 
  66  import SCons.Taskmaster 
  67  import SCons.Util 
  68  import SCons.Warnings 
  69   
  70  import SCons.Script.Interactive 
  71   
72 -def fetch_win32_parallel_msg():
73 # A subsidiary function that exists solely to isolate this import 74 # so we don't have to pull it in on all platforms, and so that an 75 # in-line "import" statement in the _main() function below doesn't 76 # cause warnings about local names shadowing use of the 'SCons' 77 # globl in nest scopes and UnboundLocalErrors and the like in some 78 # versions (2.1) of Python. 79 import SCons.Platform.win32 80 return SCons.Platform.win32.parallel_msg
81 82 # 83
84 -class SConsPrintHelpException(Exception):
85 pass
86 87 display = SCons.Util.display 88 progress_display = SCons.Util.DisplayEngine() 89 90 first_command_start = None 91 last_command_end = None 92
93 -class Progressor(object):
94 prev = '' 95 count = 0 96 target_string = '$TARGET' 97
98 - def __init__(self, obj, interval=1, file=None, overwrite=False):
99 if file is None: 100 file = sys.stdout 101 102 self.obj = obj 103 self.file = file 104 self.interval = interval 105 self.overwrite = overwrite 106 107 if callable(obj): 108 self.func = obj 109 elif SCons.Util.is_List(obj): 110 self.func = self.spinner 111 elif obj.find(self.target_string) != -1: 112 self.func = self.replace_string 113 else: 114 self.func = self.string
115
116 - def write(self, s):
117 self.file.write(s) 118 self.file.flush() 119 self.prev = s
120
121 - def erase_previous(self):
122 if self.prev: 123 length = len(self.prev) 124 if self.prev[-1] in ('\n', '\r'): 125 length = length - 1 126 self.write(' ' * length + '\r') 127 self.prev = ''
128
129 - def spinner(self, node):
130 self.write(self.obj[self.count % len(self.obj)])
131
132 - def string(self, node):
133 self.write(self.obj)
134
135 - def replace_string(self, node):
136 self.write(self.obj.replace(self.target_string, str(node)))
137
138 - def __call__(self, node):
139 self.count = self.count + 1 140 if (self.count % self.interval) == 0: 141 if self.overwrite: 142 self.erase_previous() 143 self.func(node)
144 145 ProgressObject = SCons.Util.Null() 146
147 -def Progress(*args, **kw):
148 global ProgressObject 149 ProgressObject = Progressor(*args, **kw)
150 151 # Task control. 152 # 153 154 _BuildFailures = [] 155
156 -def GetBuildFailures():
157 return _BuildFailures
158
159 -class BuildTask(SCons.Taskmaster.OutOfDateTask):
160 """An SCons build task.""" 161 progress = ProgressObject 162
163 - def display(self, message):
164 display('scons: ' + message)
165
166 - def prepare(self):
167 self.progress(self.targets[0]) 168 return SCons.Taskmaster.OutOfDateTask.prepare(self)
169
170 - def needs_execute(self):
171 if SCons.Taskmaster.OutOfDateTask.needs_execute(self): 172 return True 173 if self.top and self.targets[0].has_builder(): 174 display("scons: `%s' is up to date." % str(self.node)) 175 return False
176
177 - def execute(self):
178 if print_time: 179 start_time = time.time() 180 global first_command_start 181 if first_command_start is None: 182 first_command_start = start_time 183 SCons.Taskmaster.OutOfDateTask.execute(self) 184 if print_time: 185 global cumulative_command_time 186 global last_command_end 187 finish_time = time.time() 188 last_command_end = finish_time 189 cumulative_command_time = cumulative_command_time+finish_time-start_time 190 sys.stdout.write("Command execution time: %s: %f seconds\n"%(str(self.node), finish_time-start_time))
191
192 - def do_failed(self, status=2):
193 _BuildFailures.append(self.exception[1]) 194 global exit_status 195 global this_build_status 196 if self.options.ignore_errors: 197 SCons.Taskmaster.OutOfDateTask.executed(self) 198 elif self.options.keep_going: 199 SCons.Taskmaster.OutOfDateTask.fail_continue(self) 200 exit_status = status 201 this_build_status = status 202 else: 203 SCons.Taskmaster.OutOfDateTask.fail_stop(self) 204 exit_status = status 205 this_build_status = status
206
207 - def executed(self):
208 t = self.targets[0] 209 if self.top and not t.has_builder() and not t.side_effect: 210 if not t.exists(): 211 if t.__class__.__name__ in ('File', 'Dir', 'Entry'): 212 errstr="Do not know how to make %s target `%s' (%s)." % (t.__class__.__name__, t, t.abspath) 213 else: # Alias or Python or ... 214 errstr="Do not know how to make %s target `%s'." % (t.__class__.__name__, t) 215 sys.stderr.write("scons: *** " + errstr) 216 if not self.options.keep_going: 217 sys.stderr.write(" Stop.") 218 sys.stderr.write("\n") 219 try: 220 raise SCons.Errors.BuildError(t, errstr) 221 except KeyboardInterrupt: 222 raise 223 except: 224 self.exception_set() 225 self.do_failed() 226 else: 227 print "scons: Nothing to be done for `%s'." % t 228 SCons.Taskmaster.OutOfDateTask.executed(self) 229 else: 230 SCons.Taskmaster.OutOfDateTask.executed(self)
231
232 - def failed(self):
233 # Handle the failure of a build task. The primary purpose here 234 # is to display the various types of Errors and Exceptions 235 # appropriately. 236 exc_info = self.exc_info() 237 try: 238 t, e, tb = exc_info 239 except ValueError: 240 t, e = exc_info 241 tb = None 242 243 if t is None: 244 # The Taskmaster didn't record an exception for this Task; 245 # see if the sys module has one. 246 try: 247 t, e, tb = sys.exc_info()[:] 248 except ValueError: 249 t, e = exc_info 250 tb = None 251 252 # Deprecated string exceptions will have their string stored 253 # in the first entry of the tuple. 254 if e is None: 255 e = t 256 257 buildError = SCons.Errors.convert_to_BuildError(e) 258 if not buildError.node: 259 buildError.node = self.node 260 261 node = buildError.node 262 if not SCons.Util.is_List(node): 263 node = [ node ] 264 nodename = ', '.join(map(str, node)) 265 266 errfmt = "scons: *** [%s] %s\n" 267 sys.stderr.write(errfmt % (nodename, buildError)) 268 269 if (buildError.exc_info[2] and buildError.exc_info[1] and 270 not isinstance( 271 buildError.exc_info[1], 272 (EnvironmentError, SCons.Errors.StopError, 273 SCons.Errors.UserError))): 274 type, value, trace = buildError.exc_info 275 traceback.print_exception(type, value, trace) 276 elif tb and print_stacktrace: 277 sys.stderr.write("scons: internal stack trace:\n") 278 traceback.print_tb(tb, file=sys.stderr) 279 280 self.exception = (e, buildError, tb) # type, value, traceback 281 self.do_failed(buildError.exitstatus) 282 283 self.exc_clear()
284
285 - def postprocess(self):
286 if self.top: 287 t = self.targets[0] 288 for tp in self.options.tree_printers: 289 tp.display(t) 290 if self.options.debug_includes: 291 tree = t.render_include_tree() 292 if tree: 293 print 294 print tree 295 SCons.Taskmaster.OutOfDateTask.postprocess(self)
296
297 - def make_ready(self):
298 """Make a task ready for execution""" 299 SCons.Taskmaster.OutOfDateTask.make_ready(self) 300 if self.out_of_date and self.options.debug_explain: 301 explanation = self.out_of_date[0].explain() 302 if explanation: 303 sys.stdout.write("scons: " + explanation)
304
305 -class CleanTask(SCons.Taskmaster.AlwaysTask):
306 """An SCons clean task."""
307 - def fs_delete(self, path, pathstr, remove=1):
308 try: 309 if os.path.lexists(path): 310 if os.path.isfile(path) or os.path.islink(path): 311 if remove: os.unlink(path) 312 display("Removed " + pathstr) 313 elif os.path.isdir(path) and not os.path.islink(path): 314 # delete everything in the dir 315 for e in sorted(os.listdir(path)): 316 p = os.path.join(path, e) 317 s = os.path.join(pathstr, e) 318 if os.path.isfile(p): 319 if remove: os.unlink(p) 320 display("Removed " + s) 321 else: 322 self.fs_delete(p, s, remove) 323 # then delete dir itself 324 if remove: os.rmdir(path) 325 display("Removed directory " + pathstr) 326 else: 327 errstr = "Path '%s' exists but isn't a file or directory." 328 raise SCons.Errors.UserError(errstr % (pathstr)) 329 except SCons.Errors.UserError, e: 330 print e 331 except (IOError, OSError), e: 332 print "scons: Could not remove '%s':" % pathstr, e.strerror
333
334 - def show(self):
335 target = self.targets[0] 336 if (target.has_builder() or target.side_effect) and not target.noclean: 337 for t in self.targets: 338 if not t.isdir(): 339 display("Removed " + str(t)) 340 if target in SCons.Environment.CleanTargets: 341 files = SCons.Environment.CleanTargets[target] 342 for f in files: 343 self.fs_delete(f.abspath, str(f), 0)
344
345 - def remove(self):
346 target = self.targets[0] 347 if (target.has_builder() or target.side_effect) and not target.noclean: 348 for t in self.targets: 349 try: 350 removed = t.remove() 351 except OSError, e: 352 # An OSError may indicate something like a permissions 353 # issue, an IOError would indicate something like 354 # the file not existing. In either case, print a 355 # message and keep going to try to remove as many 356 # targets aa possible. 357 print "scons: Could not remove '%s':" % str(t), e.strerror 358 else: 359 if removed: 360 display("Removed " + str(t)) 361 if target in SCons.Environment.CleanTargets: 362 files = SCons.Environment.CleanTargets[target] 363 for f in files: 364 self.fs_delete(f.abspath, str(f))
365 366 execute = remove 367 368 # We want the Taskmaster to update the Node states (and therefore 369 # handle reference counts, etc.), but we don't want to call 370 # back to the Node's post-build methods, which would do things 371 # we don't want, like store .sconsign information. 372 executed = SCons.Taskmaster.Task.executed_without_callbacks 373 374 # Have the taskmaster arrange to "execute" all of the targets, because 375 # we'll figure out ourselves (in remove() or show() above) whether 376 # anything really needs to be done. 377 make_ready = SCons.Taskmaster.Task.make_ready_all 378
379 - def prepare(self):
380 pass
381
382 -class QuestionTask(SCons.Taskmaster.AlwaysTask):
383 """An SCons task for the -q (question) option."""
384 - def prepare(self):
385 pass
386
387 - def execute(self):
388 if self.targets[0].get_state() != SCons.Node.up_to_date or \ 389 (self.top and not self.targets[0].exists()): 390 global exit_status 391 global this_build_status 392 exit_status = 1 393 this_build_status = 1 394 self.tm.stop()
395
396 - def executed(self):
397 pass
398 399
400 -class TreePrinter(object):
401 - def __init__(self, derived=False, prune=False, status=False):
402 self.derived = derived 403 self.prune = prune 404 self.status = status
405 - def get_all_children(self, node):
406 return node.all_children()
407 - def get_derived_children(self, node):
408 children = node.all_children(None) 409 return [x for x in children if x.has_builder()]
410 - def display(self, t):
411 if self.derived: 412 func = self.get_derived_children 413 else: 414 func = self.get_all_children 415 s = self.status and 2 or 0 416 SCons.Util.print_tree(t, func, prune=self.prune, showtags=s)
417 418
419 -def python_version_string():
420 return sys.version.split()[0]
421
422 -def python_version_unsupported(version=sys.version_info):
423 return version < unsupported_python_version
424
425 -def python_version_deprecated(version=sys.version_info):
426 return version < deprecated_python_version
427 428 429 # Global variables 430 431 print_objects = 0 432 print_memoizer = 0 433 print_stacktrace = 0 434 print_time = 0 435 sconscript_time = 0 436 cumulative_command_time = 0 437 exit_status = 0 # final exit status, assume success by default 438 this_build_status = 0 # "exit status" of an individual build 439 num_jobs = None 440 delayed_warnings = [] 441
442 -class FakeOptionParser(object):
443 """ 444 A do-nothing option parser, used for the initial OptionsParser variable. 445 446 During normal SCons operation, the OptionsParser is created right 447 away by the main() function. Certain tests scripts however, can 448 introspect on different Tool modules, the initialization of which 449 can try to add a new, local option to an otherwise uninitialized 450 OptionsParser object. This allows that introspection to happen 451 without blowing up. 452 453 """
454 - class FakeOptionValues(object):
455 - def __getattr__(self, attr):
456 return None
457 values = FakeOptionValues()
458 - def add_local_option(self, *args, **kw):
459 pass
460 461 OptionsParser = FakeOptionParser() 462
463 -def AddOption(*args, **kw):
464 if 'default' not in kw: 465 kw['default'] = None 466 result = OptionsParser.add_local_option(*args, **kw) 467 return result
468
469 -def GetOption(name):
470 return getattr(OptionsParser.values, name)
471
472 -def SetOption(name, value):
473 return OptionsParser.values.set_option(name, value)
474 475 #
476 -class Stats(object):
477 - def __init__(self):
478 self.stats = [] 479 self.labels = [] 480 self.append = self.do_nothing 481 self.print_stats = self.do_nothing
482 - def enable(self, outfp):
483 self.outfp = outfp 484 self.append = self.do_append 485 self.print_stats = self.do_print
486 - def do_nothing(self, *args, **kw):
487 pass
488
489 -class CountStats(Stats):
490 - def do_append(self, label):
491 self.labels.append(label) 492 self.stats.append(SCons.Debug.fetchLoggedInstances())
493 - def do_print(self):
494 stats_table = {} 495 for s in self.stats: 496 for n in [t[0] for t in s]: 497 stats_table[n] = [0, 0, 0, 0] 498 i = 0 499 for s in self.stats: 500 for n, c in s: 501 stats_table[n][i] = c 502 i = i + 1 503 self.outfp.write("Object counts:\n") 504 pre = [" "] 505 post = [" %s\n"] 506 l = len(self.stats) 507 fmt1 = ''.join(pre + [' %7s']*l + post) 508 fmt2 = ''.join(pre + [' %7d']*l + post) 509 labels = self.labels[:l] 510 labels.append(("", "Class")) 511 self.outfp.write(fmt1 % tuple([x[0] for x in labels])) 512 self.outfp.write(fmt1 % tuple([x[1] for x in labels])) 513 for k in sorted(stats_table.keys()): 514 r = stats_table[k][:l] + [k] 515 self.outfp.write(fmt2 % tuple(r))
516 517 count_stats = CountStats() 518
519 -class MemStats(Stats):
520 - def do_append(self, label):
521 self.labels.append(label) 522 self.stats.append(SCons.Debug.memory())
523 - def do_print(self):
524 fmt = 'Memory %-32s %12d\n' 525 for label, stats in zip(self.labels, self.stats): 526 self.outfp.write(fmt % (label, stats))
527 528 memory_stats = MemStats() 529 530 # utility functions 531
532 -def _scons_syntax_error(e):
533 """Handle syntax errors. Print out a message and show where the error 534 occurred. 535 """ 536 etype, value, tb = sys.exc_info() 537 lines = traceback.format_exception_only(etype, value) 538 for line in lines: 539 sys.stderr.write(line+'\n') 540 sys.exit(2)
541
542 -def find_deepest_user_frame(tb):
543 """ 544 Find the deepest stack frame that is not part of SCons. 545 546 Input is a "pre-processed" stack trace in the form 547 returned by traceback.extract_tb() or traceback.extract_stack() 548 """ 549 550 tb.reverse() 551 552 # find the deepest traceback frame that is not part 553 # of SCons: 554 for frame in tb: 555 filename = frame[0] 556 if filename.find(os.sep+'SCons'+os.sep) == -1: 557 return frame 558 return tb[0]
559
560 -def _scons_user_error(e):
561 """Handle user errors. Print out a message and a description of the 562 error, along with the line number and routine where it occured. 563 The file and line number will be the deepest stack frame that is 564 not part of SCons itself. 565 """ 566 global print_stacktrace 567 etype, value, tb = sys.exc_info() 568 if print_stacktrace: 569 traceback.print_exception(etype, value, tb) 570 filename, lineno, routine, dummy = find_deepest_user_frame(traceback.extract_tb(tb)) 571 sys.stderr.write("\nscons: *** %s\n" % value) 572 sys.stderr.write('File "%s", line %d, in %s\n' % (filename, lineno, routine)) 573 sys.exit(2)
574
575 -def _scons_user_warning(e):
576 """Handle user warnings. Print out a message and a description of 577 the warning, along with the line number and routine where it occured. 578 The file and line number will be the deepest stack frame that is 579 not part of SCons itself. 580 """ 581 etype, value, tb = sys.exc_info() 582 filename, lineno, routine, dummy = find_deepest_user_frame(traceback.extract_tb(tb)) 583 sys.stderr.write("\nscons: warning: %s\n" % e) 584 sys.stderr.write('File "%s", line %d, in %s\n' % (filename, lineno, routine))
585
586 -def _scons_internal_warning(e):
587 """Slightly different from _scons_user_warning in that we use the 588 *current call stack* rather than sys.exc_info() to get our stack trace. 589 This is used by the warnings framework to print warnings.""" 590 filename, lineno, routine, dummy = find_deepest_user_frame(traceback.extract_stack()) 591 sys.stderr.write("\nscons: warning: %s\n" % e.args[0]) 592 sys.stderr.write('File "%s", line %d, in %s\n' % (filename, lineno, routine))
593
594 -def _scons_internal_error():
595 """Handle all errors but user errors. Print out a message telling 596 the user what to do in this case and print a normal trace. 597 """ 598 print 'internal error' 599 traceback.print_exc() 600 sys.exit(2)
601
602 -def _SConstruct_exists(dirname='', repositories=[], filelist=None):
603 """This function checks that an SConstruct file exists in a directory. 604 If so, it returns the path of the file. By default, it checks the 605 current directory. 606 """ 607 if not filelist: 608 filelist = ['SConstruct', 'Sconstruct', 'sconstruct'] 609 for file in filelist: 610 sfile = os.path.join(dirname, file) 611 if os.path.isfile(sfile): 612 return sfile 613 if not os.path.isabs(sfile): 614 for rep in repositories: 615 if os.path.isfile(os.path.join(rep, sfile)): 616 return sfile 617 return None
618
619 -def _set_debug_values(options):
620 global print_memoizer, print_objects, print_stacktrace, print_time 621 622 debug_values = options.debug 623 624 if "count" in debug_values: 625 # All of the object counts are within "if __debug__:" blocks, 626 # which get stripped when running optimized (with python -O or 627 # from compiled *.pyo files). Provide a warning if __debug__ is 628 # stripped, so it doesn't just look like --debug=count is broken. 629 enable_count = False 630 if __debug__: enable_count = True 631 if enable_count: 632 count_stats.enable(sys.stdout) 633 else: 634 msg = "--debug=count is not supported when running SCons\n" + \ 635 "\twith the python -O option or optimized (.pyo) modules." 636 SCons.Warnings.warn(SCons.Warnings.NoObjectCountWarning, msg) 637 if "dtree" in debug_values: 638 options.tree_printers.append(TreePrinter(derived=True)) 639 options.debug_explain = ("explain" in debug_values) 640 if "findlibs" in debug_values: 641 SCons.Scanner.Prog.print_find_libs = "findlibs" 642 options.debug_includes = ("includes" in debug_values) 643 print_memoizer = ("memoizer" in debug_values) 644 if "memory" in debug_values: 645 memory_stats.enable(sys.stdout) 646 print_objects = ("objects" in debug_values) 647 if "presub" in debug_values: 648 SCons.Action.print_actions_presub = 1 649 if "stacktrace" in debug_values: 650 print_stacktrace = 1 651 if "stree" in debug_values: 652 options.tree_printers.append(TreePrinter(status=True)) 653 if "time" in debug_values: 654 print_time = 1 655 if "tree" in debug_values: 656 options.tree_printers.append(TreePrinter()) 657 if "prepare" in debug_values: 658 SCons.Taskmaster.print_prepare = 1 659 if "duplicate" in debug_values: 660 SCons.Node.FS.print_duplicate = 1
661
662 -def _create_path(plist):
663 path = '.' 664 for d in plist: 665 if os.path.isabs(d): 666 path = d 667 else: 668 path = path + '/' + d 669 return path
670
671 -def _load_site_scons_dir(topdir, site_dir_name=None):
672 """Load the site_scons dir under topdir. 673 Prepends site_scons to sys.path, imports site_scons/site_init.py, 674 and prepends site_scons/site_tools to default toolpath.""" 675 if site_dir_name: 676 err_if_not_found = True # user specified: err if missing 677 else: 678 site_dir_name = "site_scons" 679 err_if_not_found = False 680 681 site_dir = os.path.join(topdir, site_dir_name) 682 if not os.path.exists(site_dir): 683 if err_if_not_found: 684 raise SCons.Errors.UserError("site dir %s not found."%site_dir) 685 return 686 687 site_init_filename = "site_init.py" 688 site_init_modname = "site_init" 689 site_tools_dirname = "site_tools" 690 # prepend to sys.path 691 sys.path = [os.path.abspath(site_dir)] + sys.path 692 site_init_file = os.path.join(site_dir, site_init_filename) 693 site_tools_dir = os.path.join(site_dir, site_tools_dirname) 694 if os.path.exists(site_init_file): 695 import imp, re 696 # TODO(2.4): turn this into try:-except:-finally: 697 try: 698 try: 699 fp, pathname, description = imp.find_module(site_init_modname, 700 [site_dir]) 701 # Load the file into SCons.Script namespace. This is 702 # opaque and clever; m is the module object for the 703 # SCons.Script module, and the exec ... in call executes a 704 # file (or string containing code) in the context of the 705 # module's dictionary, so anything that code defines ends 706 # up adding to that module. This is really short, but all 707 # the error checking makes it longer. 708 try: 709 m = sys.modules['SCons.Script'] 710 except Exception, e: 711 fmt = 'cannot import site_init.py: missing SCons.Script module %s' 712 raise SCons.Errors.InternalError(fmt % repr(e)) 713 try: 714 sfx = description[0] 715 modname = os.path.basename(pathname)[:-len(sfx)] 716 site_m = {"__file__": pathname, "__name__": modname, "__doc__": None} 717 re_special = re.compile("__[^_]+__") 718 for k in m.__dict__.keys(): 719 if not re_special.match(k): 720 site_m[k] = m.__dict__[k] 721 722 # This is the magic. 723 exec fp in site_m 724 except KeyboardInterrupt: 725 raise 726 except Exception, e: 727 fmt = '*** Error loading site_init file %s:\n' 728 sys.stderr.write(fmt % repr(site_init_file)) 729 raise 730 else: 731 for k in site_m: 732 if not re_special.match(k): 733 m.__dict__[k] = site_m[k] 734 except KeyboardInterrupt: 735 raise 736 except ImportError, e: 737 fmt = '*** cannot import site init file %s:\n' 738 sys.stderr.write(fmt % repr(site_init_file)) 739 raise 740 finally: 741 if fp: 742 fp.close() 743 if os.path.exists(site_tools_dir): 744 # prepend to DefaultToolpath 745 SCons.Tool.DefaultToolpath.insert(0, os.path.abspath(site_tools_dir))
746
747 -def _load_all_site_scons_dirs(topdir, verbose=None):
748 """Load all of the predefined site_scons dir. 749 Order is significant; we load them in order from most generic 750 (machine-wide) to most specific (topdir). 751 The verbose argument is only for testing. 752 """ 753 platform = SCons.Platform.platform_default() 754 755 def homedir(d): 756 return os.path.expanduser('~/'+d)
757 758 if platform == 'win32' or platform == 'cygwin': 759 # Note we use $ here instead of %...% because older 760 # pythons (prior to 2.6?) didn't expand %...% on Windows. 761 # This set of dirs should work on XP, Vista, 7 and later. 762 sysdirs=[ 763 os.path.expandvars('$ALLUSERSPROFILE\\Application Data\\scons'), 764 os.path.expandvars('$USERPROFILE\\Local Settings\\Application Data\\scons')] 765 appdatadir = os.path.expandvars('$APPDATA\\scons') 766 if appdatadir not in sysdirs: 767 sysdirs.append(appdatadir) 768 sysdirs.append(homedir('.scons')) 769 770 elif platform == 'darwin': # MacOS X 771 sysdirs=['/Library/Application Support/SCons', 772 '/opt/local/share/scons', # (for MacPorts) 773 '/sw/share/scons', # (for Fink) 774 homedir('Library/Application Support/SCons'), 775 homedir('.scons')] 776 elif platform == 'sunos': # Solaris 777 sysdirs=['/opt/sfw/scons', 778 '/usr/share/scons', 779 homedir('.scons')] 780 else: # Linux, HPUX, etc. 781 # assume posix-like, i.e. platform == 'posix' 782 sysdirs=['/usr/share/scons', 783 homedir('.scons')] 784 785 dirs=sysdirs + [topdir] 786 for d in dirs: 787 if verbose: # this is used by unit tests. 788 print "Loading site dir ", d 789 _load_site_scons_dir(d) 790
791 -def test_load_all_site_scons_dirs(d):
792 _load_all_site_scons_dirs(d, True)
793
794 -def version_string(label, module):
795 version = module.__version__ 796 build = module.__build__ 797 if build: 798 if build[0] != '.': 799 build = '.' + build 800 version = version + build 801 fmt = "\t%s: v%s, %s, by %s on %s\n" 802 return fmt % (label, 803 version, 804 module.__date__, 805 module.__developer__, 806 module.__buildsys__)
807
808 -def path_string(label, module):
809 path = module.__path__ 810 return "\t%s path: %s\n"%(label,path)
811
812 -def _main(parser):
813 global exit_status 814 global this_build_status 815 816 options = parser.values 817 818 # Here's where everything really happens. 819 820 # First order of business: set up default warnings and then 821 # handle the user's warning options, so that we can issue (or 822 # suppress) appropriate warnings about anything that might happen, 823 # as configured by the user. 824 825 default_warnings = [ SCons.Warnings.WarningOnByDefault, 826 SCons.Warnings.DeprecatedWarning, 827 ] 828 829 for warning in default_warnings: 830 SCons.Warnings.enableWarningClass(warning) 831 SCons.Warnings._warningOut = _scons_internal_warning 832 SCons.Warnings.process_warn_strings(options.warn) 833 834 # Now that we have the warnings configuration set up, we can actually 835 # issue (or suppress) any warnings about warning-worthy things that 836 # occurred while the command-line options were getting parsed. 837 try: 838 dw = options.delayed_warnings 839 except AttributeError: 840 pass 841 else: 842 delayed_warnings.extend(dw) 843 for warning_type, message in delayed_warnings: 844 SCons.Warnings.warn(warning_type, message) 845 846 if options.diskcheck: 847 SCons.Node.FS.set_diskcheck(options.diskcheck) 848 849 # Next, we want to create the FS object that represents the outside 850 # world's file system, as that's central to a lot of initialization. 851 # To do this, however, we need to be in the directory from which we 852 # want to start everything, which means first handling any relevant 853 # options that might cause us to chdir somewhere (-C, -D, -U, -u). 854 if options.directory: 855 script_dir = os.path.abspath(_create_path(options.directory)) 856 else: 857 script_dir = os.getcwd() 858 859 target_top = None 860 if options.climb_up: 861 target_top = '.' # directory to prepend to targets 862 while script_dir and not _SConstruct_exists(script_dir, 863 options.repository, 864 options.file): 865 script_dir, last_part = os.path.split(script_dir) 866 if last_part: 867 target_top = os.path.join(last_part, target_top) 868 else: 869 script_dir = '' 870 871 if script_dir and script_dir != os.getcwd(): 872 if not options.silent: 873 display("scons: Entering directory `%s'" % script_dir) 874 try: 875 os.chdir(script_dir) 876 except OSError: 877 sys.stderr.write("Could not change directory to %s\n" % script_dir) 878 879 # Now that we're in the top-level SConstruct directory, go ahead 880 # and initialize the FS object that represents the file system, 881 # and make it the build engine default. 882 fs = SCons.Node.FS.get_default_fs() 883 884 for rep in options.repository: 885 fs.Repository(rep) 886 887 # Now that we have the FS object, the next order of business is to 888 # check for an SConstruct file (or other specified config file). 889 # If there isn't one, we can bail before doing any more work. 890 scripts = [] 891 if options.file: 892 scripts.extend(options.file) 893 if not scripts: 894 sfile = _SConstruct_exists(repositories=options.repository, 895 filelist=options.file) 896 if sfile: 897 scripts.append(sfile) 898 899 if not scripts: 900 if options.help: 901 # There's no SConstruct, but they specified -h. 902 # Give them the options usage now, before we fail 903 # trying to read a non-existent SConstruct file. 904 raise SConsPrintHelpException 905 raise SCons.Errors.UserError("No SConstruct file found.") 906 907 if scripts[0] == "-": 908 d = fs.getcwd() 909 else: 910 d = fs.File(scripts[0]).dir 911 fs.set_SConstruct_dir(d) 912 913 _set_debug_values(options) 914 SCons.Node.implicit_cache = options.implicit_cache 915 SCons.Node.implicit_deps_changed = options.implicit_deps_changed 916 SCons.Node.implicit_deps_unchanged = options.implicit_deps_unchanged 917 918 if options.no_exec: 919 SCons.SConf.dryrun = 1 920 SCons.Action.execute_actions = None 921 if options.question: 922 SCons.SConf.dryrun = 1 923 if options.clean: 924 SCons.SConf.SetBuildType('clean') 925 if options.help: 926 SCons.SConf.SetBuildType('help') 927 SCons.SConf.SetCacheMode(options.config) 928 SCons.SConf.SetProgressDisplay(progress_display) 929 930 if options.no_progress or options.silent: 931 progress_display.set_mode(0) 932 933 if options.site_dir: 934 _load_site_scons_dir(d.path, options.site_dir) 935 elif not options.no_site_dir: 936 _load_all_site_scons_dirs(d.path) 937 938 if options.include_dir: 939 sys.path = options.include_dir + sys.path 940 941 # That should cover (most of) the options. Next, set up the variables 942 # that hold command-line arguments, so the SConscript files that we 943 # read and execute have access to them. 944 targets = [] 945 xmit_args = [] 946 for a in parser.largs: 947 if a[:1] == '-': 948 continue 949 if '=' in a: 950 xmit_args.append(a) 951 else: 952 targets.append(a) 953 SCons.Script._Add_Targets(targets + parser.rargs) 954 SCons.Script._Add_Arguments(xmit_args) 955 956 # If stdout is not a tty, replace it with a wrapper object to call flush 957 # after every write. 958 # 959 # Tty devices automatically flush after every newline, so the replacement 960 # isn't necessary. Furthermore, if we replace sys.stdout, the readline 961 # module will no longer work. This affects the behavior during 962 # --interactive mode. --interactive should only be used when stdin and 963 # stdout refer to a tty. 964 if not hasattr(sys.stdout, 'isatty') or not sys.stdout.isatty(): 965 sys.stdout = SCons.Util.Unbuffered(sys.stdout) 966 if not hasattr(sys.stderr, 'isatty') or not sys.stderr.isatty(): 967 sys.stderr = SCons.Util.Unbuffered(sys.stderr) 968 969 memory_stats.append('before reading SConscript files:') 970 count_stats.append(('pre-', 'read')) 971 972 # And here's where we (finally) read the SConscript files. 973 974 progress_display("scons: Reading SConscript files ...") 975 976 start_time = time.time() 977 try: 978 for script in scripts: 979 SCons.Script._SConscript._SConscript(fs, script) 980 except SCons.Errors.StopError, e: 981 # We had problems reading an SConscript file, such as it 982 # couldn't be copied in to the VariantDir. Since we're just 983 # reading SConscript files and haven't started building 984 # things yet, stop regardless of whether they used -i or -k 985 # or anything else. 986 sys.stderr.write("scons: *** %s Stop.\n" % e) 987 exit_status = 2 988 sys.exit(exit_status) 989 global sconscript_time 990 sconscript_time = time.time() - start_time 991 992 progress_display("scons: done reading SConscript files.") 993 994 memory_stats.append('after reading SConscript files:') 995 count_stats.append(('post-', 'read')) 996 997 # Re-{enable,disable} warnings in case they disabled some in 998 # the SConscript file. 999 # 1000 # We delay enabling the PythonVersionWarning class until here so that, 1001 # if they explicity disabled it in either in the command line or in 1002 # $SCONSFLAGS, or in the SConscript file, then the search through 1003 # the list of deprecated warning classes will find that disabling 1004 # first and not issue the warning. 1005 #SCons.Warnings.enableWarningClass(SCons.Warnings.PythonVersionWarning) 1006 SCons.Warnings.process_warn_strings(options.warn) 1007 1008 # Now that we've read the SConscript files, we can check for the 1009 # warning about deprecated Python versions--delayed until here 1010 # in case they disabled the warning in the SConscript files. 1011 if python_version_deprecated(): 1012 msg = "Support for pre-%s Python version (%s) is deprecated.\n" + \ 1013 " If this will cause hardship, contact dev@scons.tigris.org." 1014 deprecated_version_string = ".".join(map(str, deprecated_python_version)) 1015 SCons.Warnings.warn(SCons.Warnings.PythonVersionWarning, 1016 msg % (deprecated_version_string, python_version_string())) 1017 1018 if not options.help: 1019 SCons.SConf.CreateConfigHBuilder(SCons.Defaults.DefaultEnvironment()) 1020 1021 # Now re-parse the command-line options (any to the left of a '--' 1022 # argument, that is) with any user-defined command-line options that 1023 # the SConscript files may have added to the parser object. This will 1024 # emit the appropriate error message and exit if any unknown option 1025 # was specified on the command line. 1026 1027 parser.preserve_unknown_options = False 1028 parser.parse_args(parser.largs, options) 1029 1030 if options.help: 1031 help_text = SCons.Script.help_text 1032 if help_text is None: 1033 # They specified -h, but there was no Help() inside the 1034 # SConscript files. Give them the options usage. 1035 raise SConsPrintHelpException 1036 else: 1037 print help_text 1038 print "Use scons -H for help about command-line options." 1039 exit_status = 0 1040 return 1041 1042 # Change directory to the top-level SConstruct directory, then tell 1043 # the Node.FS subsystem that we're all done reading the SConscript 1044 # files and calling Repository() and VariantDir() and changing 1045 # directories and the like, so it can go ahead and start memoizing 1046 # the string values of file system nodes. 1047 1048 fs.chdir(fs.Top) 1049 1050 SCons.Node.FS.save_strings(1) 1051 1052 # Now that we've read the SConscripts we can set the options 1053 # that are SConscript settable: 1054 SCons.Node.implicit_cache = options.implicit_cache 1055 SCons.Node.FS.set_duplicate(options.duplicate) 1056 fs.set_max_drift(options.max_drift) 1057 1058 SCons.Job.explicit_stack_size = options.stack_size 1059 1060 if options.md5_chunksize: 1061 SCons.Node.FS.File.md5_chunksize = options.md5_chunksize 1062 1063 platform = SCons.Platform.platform_module() 1064 1065 if options.interactive: 1066 SCons.Script.Interactive.interact(fs, OptionsParser, options, 1067 targets, target_top) 1068 1069 else: 1070 1071 # Build the targets 1072 nodes = _build_targets(fs, options, targets, target_top) 1073 if not nodes: 1074 exit_status = 2
1075
1076 -def _build_targets(fs, options, targets, target_top):
1077 1078 global this_build_status 1079 this_build_status = 0 1080 1081 progress_display.set_mode(not (options.no_progress or options.silent)) 1082 display.set_mode(not options.silent) 1083 SCons.Action.print_actions = not options.silent 1084 SCons.Action.execute_actions = not options.no_exec 1085 SCons.Node.FS.do_store_info = not options.no_exec 1086 SCons.SConf.dryrun = options.no_exec 1087 1088 if options.diskcheck: 1089 SCons.Node.FS.set_diskcheck(options.diskcheck) 1090 1091 SCons.CacheDir.cache_enabled = not options.cache_disable 1092 SCons.CacheDir.cache_debug = options.cache_debug 1093 SCons.CacheDir.cache_force = options.cache_force 1094 SCons.CacheDir.cache_show = options.cache_show 1095 1096 if options.no_exec: 1097 CleanTask.execute = CleanTask.show 1098 else: 1099 CleanTask.execute = CleanTask.remove 1100 1101 lookup_top = None 1102 if targets or SCons.Script.BUILD_TARGETS != SCons.Script._build_plus_default: 1103 # They specified targets on the command line or modified 1104 # BUILD_TARGETS in the SConscript file(s), so if they used -u, 1105 # -U or -D, we have to look up targets relative to the top, 1106 # but we build whatever they specified. 1107 if target_top: 1108 lookup_top = fs.Dir(target_top) 1109 target_top = None 1110 1111 targets = SCons.Script.BUILD_TARGETS 1112 else: 1113 # There are no targets specified on the command line, 1114 # so if they used -u, -U or -D, we may have to restrict 1115 # what actually gets built. 1116 d = None 1117 if target_top: 1118 if options.climb_up == 1: 1119 # -u, local directory and below 1120 target_top = fs.Dir(target_top) 1121 lookup_top = target_top 1122 elif options.climb_up == 2: 1123 # -D, all Default() targets 1124 target_top = None 1125 lookup_top = None 1126 elif options.climb_up == 3: 1127 # -U, local SConscript Default() targets 1128 target_top = fs.Dir(target_top) 1129 def check_dir(x, target_top=target_top): 1130 if hasattr(x, 'cwd') and not x.cwd is None: 1131 cwd = x.cwd.srcnode() 1132 return cwd == target_top 1133 else: 1134 # x doesn't have a cwd, so it's either not a target, 1135 # or not a file, so go ahead and keep it as a default 1136 # target and let the engine sort it out: 1137 return 1
1138 d = list(filter(check_dir, SCons.Script.DEFAULT_TARGETS)) 1139 SCons.Script.DEFAULT_TARGETS[:] = d 1140 target_top = None 1141 lookup_top = None 1142 1143 targets = SCons.Script._Get_Default_Targets(d, fs) 1144 1145 if not targets: 1146 sys.stderr.write("scons: *** No targets specified and no Default() targets found. Stop.\n") 1147 return None 1148 1149 def Entry(x, ltop=lookup_top, ttop=target_top, fs=fs): 1150 if isinstance(x, SCons.Node.Node): 1151 node = x 1152 else: 1153 node = None 1154 # Why would ltop be None? Unfortunately this happens. 1155 if ltop is None: ltop = '' 1156 # Curdir becomes important when SCons is called with -u, -C, 1157 # or similar option that changes directory, and so the paths 1158 # of targets given on the command line need to be adjusted. 1159 curdir = os.path.join(os.getcwd(), str(ltop)) 1160 for lookup in SCons.Node.arg2nodes_lookups: 1161 node = lookup(x, curdir=curdir) 1162 if node is not None: 1163 break 1164 if node is None: 1165 node = fs.Entry(x, directory=ltop, create=1) 1166 if ttop and not node.is_under(ttop): 1167 if isinstance(node, SCons.Node.FS.Dir) and ttop.is_under(node): 1168 node = ttop 1169 else: 1170 node = None 1171 return node 1172 1173 nodes = [_f for _f in map(Entry, targets) if _f] 1174 1175 task_class = BuildTask # default action is to build targets 1176 opening_message = "Building targets ..." 1177 closing_message = "done building targets." 1178 if options.keep_going: 1179 failure_message = "done building targets (errors occurred during build)." 1180 else: 1181 failure_message = "building terminated because of errors." 1182 if options.question: 1183 task_class = QuestionTask 1184 try: 1185 if options.clean: 1186 task_class = CleanTask 1187 opening_message = "Cleaning targets ..." 1188 closing_message = "done cleaning targets." 1189 if options.keep_going: 1190 failure_message = "done cleaning targets (errors occurred during clean)." 1191 else: 1192 failure_message = "cleaning terminated because of errors." 1193 except AttributeError: 1194 pass 1195 1196 task_class.progress = ProgressObject 1197 1198 if options.random: 1199 def order(dependencies): 1200 """Randomize the dependencies.""" 1201 import random 1202 # This is cribbed from the implementation of 1203 # random.shuffle() in Python 2.X. 1204 d = dependencies 1205 for i in range(len(d)-1, 0, -1): 1206 j = int(random.random() * (i+1)) 1207 d[i], d[j] = d[j], d[i] 1208 return d 1209 else: 1210 def order(dependencies): 1211 """Leave the order of dependencies alone.""" 1212 return dependencies 1213 1214 if options.taskmastertrace_file == '-': 1215 tmtrace = sys.stdout 1216 elif options.taskmastertrace_file: 1217 tmtrace = open(options.taskmastertrace_file, 'wb') 1218 else: 1219 tmtrace = None 1220 taskmaster = SCons.Taskmaster.Taskmaster(nodes, task_class, order, tmtrace) 1221 1222 # Let the BuildTask objects get at the options to respond to the 1223 # various print_* settings, tree_printer list, etc. 1224 BuildTask.options = options 1225 1226 global num_jobs 1227 num_jobs = options.num_jobs 1228 jobs = SCons.Job.Jobs(num_jobs, taskmaster) 1229 if num_jobs > 1: 1230 msg = None 1231 if jobs.num_jobs == 1: 1232 msg = "parallel builds are unsupported by this version of Python;\n" + \ 1233 "\tignoring -j or num_jobs option.\n" 1234 elif sys.platform == 'win32': 1235 msg = fetch_win32_parallel_msg() 1236 if msg: 1237 SCons.Warnings.warn(SCons.Warnings.NoParallelSupportWarning, msg) 1238 1239 memory_stats.append('before building targets:') 1240 count_stats.append(('pre-', 'build')) 1241 1242 def jobs_postfunc( 1243 jobs=jobs, 1244 options=options, 1245 closing_message=closing_message, 1246 failure_message=failure_message 1247 ): 1248 if jobs.were_interrupted(): 1249 if not options.no_progress and not options.silent: 1250 sys.stderr.write("scons: Build interrupted.\n") 1251 global exit_status 1252 global this_build_status 1253 exit_status = 2 1254 this_build_status = 2 1255 1256 if this_build_status: 1257 progress_display("scons: " + failure_message) 1258 else: 1259 progress_display("scons: " + closing_message) 1260 if not options.no_exec: 1261 if jobs.were_interrupted(): 1262 progress_display("scons: writing .sconsign file.") 1263 SCons.SConsign.write() 1264 1265 progress_display("scons: " + opening_message) 1266 jobs.run(postfunc = jobs_postfunc) 1267 1268 memory_stats.append('after building targets:') 1269 count_stats.append(('post-', 'build')) 1270 1271 return nodes 1272
1273 -def _exec_main(parser, values):
1274 sconsflags = os.environ.get('SCONSFLAGS', '') 1275 all_args = sconsflags.split() + sys.argv[1:] 1276 1277 options, args = parser.parse_args(all_args, values) 1278 1279 if isinstance(options.debug, list) and "pdb" in options.debug: 1280 import pdb 1281 pdb.Pdb().runcall(_main, parser) 1282 elif options.profile_file: 1283 # compat layer imports "cProfile" for us if it's available. 1284 from profile import Profile 1285 1286 # Some versions of Python 2.4 shipped a profiler that had the 1287 # wrong 'c_exception' entry in its dispatch table. Make sure 1288 # we have the right one. (This may put an unnecessary entry 1289 # in the table in earlier versions of Python, but its presence 1290 # shouldn't hurt anything). 1291 try: 1292 dispatch = Profile.dispatch 1293 except AttributeError: 1294 pass 1295 else: 1296 dispatch['c_exception'] = Profile.trace_dispatch_return 1297 1298 prof = Profile() 1299 try: 1300 prof.runcall(_main, parser) 1301 except SConsPrintHelpException, e: 1302 prof.dump_stats(options.profile_file) 1303 raise e 1304 except SystemExit: 1305 pass 1306 prof.dump_stats(options.profile_file) 1307 else: 1308 _main(parser)
1309
1310 -def main():
1311 global OptionsParser 1312 global exit_status 1313 global first_command_start 1314 1315 # Check up front for a Python version we do not support. We 1316 # delay the check for deprecated Python versions until later, 1317 # after the SConscript files have been read, in case they 1318 # disable that warning. 1319 if python_version_unsupported(): 1320 msg = "scons: *** SCons version %s does not run under Python version %s.\n" 1321 sys.stderr.write(msg % (SCons.__version__, python_version_string())) 1322 sys.exit(1) 1323 1324 parts = ["SCons by Steven Knight et al.:\n"] 1325 try: 1326 import __main__ 1327 parts.append(version_string("script", __main__)) 1328 except (ImportError, AttributeError): 1329 # On Windows there is no scons.py, so there is no 1330 # __main__.__version__, hence there is no script version. 1331 pass 1332 parts.append(version_string("engine", SCons)) 1333 parts.append(path_string("engine", SCons)) 1334 parts.append("Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 The SCons Foundation") 1335 version = ''.join(parts) 1336 1337 import SConsOptions 1338 parser = SConsOptions.Parser(version) 1339 values = SConsOptions.SConsValues(parser.get_default_values()) 1340 1341 OptionsParser = parser 1342 1343 try: 1344 _exec_main(parser, values) 1345 except SystemExit, s: 1346 if s: 1347 exit_status = s 1348 except KeyboardInterrupt: 1349 print("scons: Build interrupted.") 1350 sys.exit(2) 1351 except SyntaxError, e: 1352 _scons_syntax_error(e) 1353 except SCons.Errors.InternalError: 1354 _scons_internal_error() 1355 except SCons.Errors.UserError, e: 1356 _scons_user_error(e) 1357 except SConsPrintHelpException: 1358 parser.print_help() 1359 exit_status = 0 1360 except SCons.Errors.BuildError, e: 1361 exit_status = e.exitstatus 1362 except: 1363 # An exception here is likely a builtin Python exception Python 1364 # code in an SConscript file. Show them precisely what the 1365 # problem was and where it happened. 1366 SCons.Script._SConscript.SConscript_exception() 1367 sys.exit(2) 1368 1369 memory_stats.print_stats() 1370 count_stats.print_stats() 1371 1372 if print_objects: 1373 SCons.Debug.listLoggedInstances('*') 1374 #SCons.Debug.dumpLoggedInstances('*') 1375 1376 if print_memoizer: 1377 SCons.Memoize.Dump("Memoizer (memory cache) hits and misses:") 1378 1379 # Dump any development debug info that may have been enabled. 1380 # These are purely for internal debugging during development, so 1381 # there's no need to control them with --debug= options; they're 1382 # controlled by changing the source code. 1383 SCons.Debug.dump_caller_counts() 1384 SCons.Taskmaster.dump_stats() 1385 1386 if print_time: 1387 total_time = time.time() - SCons.Script.start_time 1388 if num_jobs == 1: 1389 ct = cumulative_command_time 1390 else: 1391 if last_command_end is None or first_command_start is None: 1392 ct = 0.0 1393 else: 1394 ct = last_command_end - first_command_start 1395 scons_time = total_time - sconscript_time - ct 1396 print "Total build time: %f seconds"%total_time 1397 print "Total SConscript file execution time: %f seconds"%sconscript_time 1398 print "Total SCons execution time: %f seconds"%scons_time 1399 print "Total command execution time: %f seconds"%ct 1400 1401 sys.exit(exit_status)
1402 1403 # Local Variables: 1404 # tab-width:4 1405 # indent-tabs-mode:nil 1406 # End: 1407 # vim: set expandtab tabstop=4 shiftwidth=4: 1408