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