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