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