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