3 This file implements the main() function used by the scons script.
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,
17 # Permission is hereby granted, free of charge, to any person obtaining
18 # a copy of this software and associated documentation files (the
19 # "Software"), to deal in the Software without restriction, including
20 # without limitation the rights to use, copy, modify, merge, publish,
21 # distribute, sublicense, and/or sell copies of the Software, and to
22 # permit persons to whom the Software is furnished to do so, subject to
23 # the following conditions:
25 # The above copyright notice and this permission notice shall be included
26 # in all copies or substantial portions of the Software.
28 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
29 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
30 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
32 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
33 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
34 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
40 start_time = time.time()
49 # Strip the script directory from sys.path() so on case-insensitive
50 # (WIN32) systems Python doesn't think that the "scons" script is the
51 # "SCons" package. Replace it with our own version directory so, if
52 # if they're there, we pick up the right version of the build engine
54 #sys.path = [os.path.join(sys.prefix,
56 # 'scons-%d' % SCons.__version__)] + sys.path[1:]
62 from SCons.Optik import OptionParser, SUPPRESS_HELP, OptionValueError
63 import SCons.Script.SConscript
65 import SCons.Taskmaster
66 from SCons.Util import display
72 class BuildTask(SCons.Taskmaster.Task):
73 """An SCons build task."""
75 target = self.targets[0]
76 if target.get_state() == SCons.Node.up_to_date:
77 if self.top and target.has_builder():
78 display('scons: "%s" is up to date.' % str(target))
79 elif target.has_builder() and not hasattr(target.builder, 'status'):
81 start_time = time.time()
82 SCons.Taskmaster.Task.execute(self)
84 finish_time = time.time()
86 command_time = command_time+finish_time-start_time
87 print "Command execution time: %f seconds"%(finish_time-start_time)
89 def do_failed(self, status=2):
92 SCons.Taskmaster.Task.executed(self)
93 elif keep_going_on_error:
94 SCons.Taskmaster.Task.fail_continue(self)
97 SCons.Taskmaster.Task.fail_stop(self)
102 if self.top and not t.has_builder() and not t.side_effect:
104 sys.stderr.write("scons: *** Do not know how to make target `%s'." % t)
105 if not keep_going_on_error:
106 sys.stderr.write(" Stop.")
107 sys.stderr.write("\n")
110 print "scons: Nothing to be done for `%s'." % t
111 SCons.Taskmaster.Task.executed(self)
113 SCons.Taskmaster.Task.executed(self)
115 # print the tree here instead of in execute() because
116 # this method is serialized, but execute isn't:
117 if print_tree and self.top:
119 print SCons.Util.render_tree(self.targets[0], get_all_children)
120 if print_dtree and self.top:
122 print SCons.Util.render_tree(self.targets[0], get_derived_children)
123 if print_includes and self.top:
125 tree = t.render_include_tree()
133 if sys.exc_type == SCons.Errors.BuildError:
134 sys.stderr.write("scons: *** [%s] %s\n" % (e.node, e.errstr))
135 if e.errstr == 'Exception':
136 traceback.print_exception(e.args[0], e.args[1], e.args[2])
137 elif sys.exc_type == SCons.Errors.UserError:
138 # We aren't being called out of a user frame, so
139 # don't try to walk the stack, just print the error.
140 sys.stderr.write("\nscons: *** %s\n" % e)
141 elif sys.exc_type == SCons.Errors.StopError:
143 if not keep_going_on_error:
145 sys.stderr.write("scons: *** %s\n" % s)
146 elif sys.exc_type == SCons.Errors.ExplicitExit:
148 sys.stderr.write("scons: *** [%s] Explicit exit, status %s\n" % (e.node, e.status))
152 sys.stderr.write("scons: *** %s\n" % e)
154 self.do_failed(status)
156 class CleanTask(SCons.Taskmaster.Task):
157 """An SCons clean task."""
159 if (self.targets[0].has_builder() or self.targets[0].side_effect) \
160 and not os.path.isdir(str(self.targets[0])):
161 display("Removed " + str(self.targets[0]))
162 if SCons.Script.SConscript.clean_targets.has_key(self.targets[0]):
163 files = SCons.Script.SConscript.clean_targets[self.targets[0]]
165 SCons.Util.fs_delete(str(f), 0)
168 if self.targets[0].has_builder() or self.targets[0].side_effect:
169 for t in self.targets:
173 print "scons: Could not remove '%s':" % str(t), e.strerror
176 display("Removed " + str(t))
177 if SCons.Script.SConscript.clean_targets.has_key(self.targets[0]):
178 files = SCons.Script.SConscript.clean_targets[self.targets[0]]
180 SCons.Util.fs_delete(str(f))
187 class QuestionTask(SCons.Taskmaster.Task):
188 """An SCons task for the -q (question) option."""
193 if self.targets[0].get_state() != SCons.Node.up_to_date:
203 keep_going_on_error = 0
211 exit_status = 0 # exit status, assume success by default
215 num_jobs = 1 # this is modifed by SConscript.SetJobs()
217 # Exceptions for this module
218 class PrintHelp(Exception):
223 def get_num_jobs(options):
224 if hasattr(options, 'num_jobs'):
225 return options.num_jobs
229 def get_all_children(node): return node.all_children(None)
231 def get_derived_children(node):
232 children = node.all_children(None)
233 return filter(lambda x: x.has_builder(), children)
235 def _scons_syntax_error(e):
236 """Handle syntax errors. Print out a message and show where the error
239 etype, value, tb = sys.exc_info()
240 lines = traceback.format_exception_only(etype, value)
242 sys.stderr.write(line+'\n')
245 def find_deepest_user_frame(tb):
247 Find the deepest stack frame that is not part of SCons.
249 Input is a "pre-processed" stack trace in the form
250 returned by traceback.extract_tb() or traceback.extract_stack()
255 # find the deepest traceback frame that is not part
259 if string.find(filename, os.sep+'SCons'+os.sep) == -1:
263 def _scons_user_error(e):
264 """Handle user errors. Print out a message and a description of the
265 error, along with the line number and routine where it occured.
266 The file and line number will be the deepest stack frame that is
267 not part of SCons itself.
269 etype, value, tb = sys.exc_info()
270 filename, lineno, routine, dummy = find_deepest_user_frame(traceback.extract_tb(tb))
271 sys.stderr.write("\nscons: *** %s\n" % value)
272 sys.stderr.write('File "%s", line %d, in %s\n' % (filename, lineno, routine))
275 def _scons_user_warning(e):
276 """Handle user warnings. Print out a message and a description of
277 the warning, along with the line number and routine where it occured.
278 The file and line number will be the deepest stack frame that is
279 not part of SCons itself.
281 etype, value, tb = sys.exc_info()
282 filename, lineno, routine, dummy = find_deepest_user_frame(traceback.extract_tb(tb))
283 sys.stderr.write("\nscons: warning: %s\n" % e)
284 sys.stderr.write('File "%s", line %d, in %s\n' % (filename, lineno, routine))
286 def _scons_internal_warning(e):
287 """Slightly different from _scons_user_warning in that we use the
288 *current call stack* rather than sys.exc_info() to get our stack trace.
289 This is used by the warnings framework to print warnings."""
290 filename, lineno, routine, dummy = find_deepest_user_frame(traceback.extract_stack())
291 sys.stderr.write("\nscons: warning: %s\n" % e)
292 sys.stderr.write('File "%s", line %d, in %s\n' % (filename, lineno, routine))
294 def _scons_other_errors():
295 """Handle all errors but user errors. Print out a message telling
296 the user what to do in this case and print a normal trace.
299 traceback.print_exc()
302 def _varargs(option, parser):
305 arg = parser.rargs[0]
311 def _setup_warn(arg):
312 """The --warn option. An argument to this option
313 should be of the form <warning-class> or no-<warning-class>.
314 The warning class is munged in order to get an actual class
315 name from the SCons.Warnings module to enable or disable.
316 The supplied <warning-class> is split on hyphens, each element
317 is captialized, then smushed back together. Then the string
318 "SCons.Warnings." is added to the front and "Warning" is added
319 to the back to get the fully qualified class name.
321 For example, --warn=deprecated will enable the
322 SCons.Warnings.DeprecatedWarning class.
324 --warn=no-dependency will disable the
325 SCons.Warnings.DependencyWarning class.
327 As a special case, --warn=all and --warn=no-all
328 will enable or disable (respectively) the base
329 class of all warnings, which is SCons.Warning.Warning."""
331 elems = string.split(string.lower(arg), '-')
337 if len(elems) == 1 and elems[0] == 'all':
338 class_name = "Warning"
340 class_name = string.join(map(string.capitalize, elems), '') + \
343 clazz = getattr(SCons.Warnings, class_name)
344 except AttributeError:
345 sys.stderr.write("No warning type: '%s'\n" % arg)
348 SCons.Warnings.enableWarningClass(clazz)
350 SCons.Warnings.suppressWarningClass(clazz)
352 def _SConstruct_exists(dirname=''):
353 """This function checks that an SConstruct file exists in a directory.
354 If so, it returns the path of the file. By default, it checks the
358 for file in ['SConstruct', 'Sconstruct', 'sconstruct']:
359 sfile = os.path.join(dirname, file)
360 if os.path.isfile(sfile):
362 if not os.path.isabs(sfile):
363 for rep in repositories:
364 if os.path.isfile(os.path.join(rep, sfile)):
368 def _set_globals(options):
369 global repositories, keep_going_on_error, print_tree, print_dtree
370 global print_time, ignore_errors, print_includes
372 if options.repository:
373 repositories.extend(options.repository)
374 keep_going_on_error = options.keep_going
377 if options.debug == "tree":
379 elif options.debug == "dtree":
381 elif options.debug == "time":
383 elif options.debug == "includes":
385 except AttributeError:
387 ignore_errors = options.ignore_errors
389 def _create_path(plist):
395 path = path + '/' + d
399 class OptParser(OptionParser):
403 parts = ["SCons by Steven Knight et al.:\n"]
405 parts.append("\tscript: v%s.%s, %s, by %s on %s\n" % (__main__.__version__,
408 __main__.__developer__,
409 __main__.__buildsys__))
411 # On win32 there is no scons.py, so there is no __main__.__version__,
412 # hence there is no script version.
414 parts.append("\tengine: v%s.%s, %s, by %s on %s\n" % (SCons.__version__,
419 parts.append("__COPYRIGHT__")
420 OptionParser.__init__(self, version=string.join(parts, ''),
421 usage="usage: scons [OPTION] [TARGET] ...")
423 # options ignored for compatibility
424 def opt_ignore(option, opt, value, parser):
425 sys.stderr.write("Warning: ignoring %s option\n" % opt)
426 self.add_option("-b", "-m", "-S", "-t", "--no-keep-going", "--stop",
427 "--touch", action="callback", callback=opt_ignore,
428 help="Ignored for compatibility.")
430 self.add_option('-c', '--clean', '--remove', action="store_true",
431 default=0, dest="clean",
432 help="Remove specified targets and dependencies.")
434 self.add_option('-C', '--directory', type="string", action = "append",
435 help="Change to DIRECTORY before doing anything.")
437 self.add_option('--cache-disable', '--no-cache',
438 action="store_true", dest='cache_disable', default=0,
439 help="Do not retrieve built targets from CacheDir.")
441 self.add_option('--cache-force', '--cache-populate',
442 action="store_true", dest='cache_force', default=0,
443 help="Copy already-built targets into the CacheDir.")
445 self.add_option('--cache-show',
446 action="store_true", dest='cache_show', default=0,
447 help="Print build actions for files from CacheDir.")
449 def opt_not_yet(option, opt, value, parser):
450 sys.stderr.write("Warning: the %s option is not yet implemented\n" % opt)
452 self.add_option('-d', action="callback",
453 callback=opt_not_yet,
454 help = "Print file dependency information.")
456 self.add_option('-D', action="store_const", const=2, dest="climb_up",
457 help="Search up directory tree for SConstruct, "
458 "build all Default() targets.")
460 def opt_debug(option, opt, value, parser):
462 if os.name == 'java':
463 python = os.path.join(sys.prefix, 'jython')
465 python = sys.executable
466 args = [ python, "pdb.py" ] + \
467 filter(lambda x: x != "--debug=pdb", sys.argv)
468 if sys.platform == 'win32':
469 args[1] = os.path.join(sys.prefix, "lib", "pdb.py")
470 sys.exit(os.spawnve(os.P_WAIT, args[0], args, os.environ))
472 args[1] = os.path.join(sys.prefix,
474 "python" + sys.version[0:3],
476 os.execvpe(args[0], args, os.environ)
477 elif value in ["tree", "dtree", "time", "includes"]:
478 setattr(parser.values, 'debug', value)
480 raise OptionValueError("Warning: %s is not a valid debug type" % value)
481 self.add_option('--debug', action="callback", type="string",
482 callback=opt_debug, nargs=1, dest="debug",
483 help="Print various types of debugging information.")
485 self.add_option('-f', '--file', '--makefile', '--sconstruct',
486 action="append", nargs=1,
487 help="Read FILE as the top-level SConstruct file.")
489 self.add_option('-h', '--help', action="store_true", default=0,
491 help="Print defined help message, or this one.")
493 self.add_option("-H", "--help-options",
495 help="Print this message and exit.")
497 self.add_option('-i', '--ignore-errors', action="store_true",
498 default=0, dest='ignore_errors',
499 help="Ignore errors from build actions.")
501 self.add_option('-I', '--include-dir', action="append",
502 dest='include_dir', metavar="DIRECTORY",
503 help="Search DIRECTORY for imported Python modules.")
505 self.add_option('--implicit-cache', action="store_true", default=0,
506 dest='implicit_cache',
507 help="Cache implicit dependencies")
509 self.add_option('--implicit-deps-changed', action="store_true",
510 default=0, dest='implicit_deps_changed',
511 help="Ignore the cached implicit deps.")
512 self.add_option('--implicit-deps-unchanged', action="store_true",
513 default=0, dest='implicit_deps_unchanged',
514 help="Ignore changes in implicit deps.")
516 def opt_j(option, opt, value, parser):
518 setattr(parser.values, 'num_jobs', value)
519 self.add_option('-j', '--jobs', action="callback", type="int",
520 callback=opt_j, metavar="N",
521 help="Allow N jobs at once.")
523 self.add_option('-k', '--keep-going', action="store_true", default=0,
525 help="Keep going when a target can't be made.")
527 self.add_option('--max-drift', type="int", action="store",
529 help="Set the maximum system clock drift to be"
530 " MAX_DRIFT seconds.")
532 self.add_option('-n', '--no-exec', '--just-print', '--dry-run',
533 '--recon', action="store_true", dest='noexec',
534 default=0, help="Don't build; just print commands.")
536 def opt_profile(option, opt, value, parser):
541 profile.run('SCons.Script.main()', value)
542 sys.exit(exit_status)
543 self.add_option('--profile', nargs=1, action="callback",
544 callback=opt_profile, type="string", dest="profile",
545 help="Profile SCons and put results in PROFILE.")
547 self.add_option('-q', '--question', action="store_true", default=0,
548 help="Don't build; exit status says if up to date.")
550 self.add_option('-Q', dest='no_progress', action="store_true",
552 help="Don't print SCons progress messages.")
554 self.add_option('--random', dest="random", action="store_true",
555 default=0, help="Build dependencies in random order.")
557 self.add_option('-s', '--silent', '--quiet', action="store_true",
558 default=0, help="Don't print commands.")
560 self.add_option('-u', '--up', '--search-up', action="store_const",
561 dest="climb_up", default=0, const=1,
562 help="Search up directory tree for SConstruct, "
563 "build targets at or below current directory.")
564 self.add_option('-U', action="store_const", dest="climb_up",
566 help="Search up directory tree for SConstruct, "
567 "build Default() targets from local SConscript.")
569 self.add_option("-v", "--version",
571 help="Print the SCons version number and exit.")
573 self.add_option('--warn', '--warning', nargs=1, action="store",
574 metavar="WARNING-SPEC",
575 help="Enable or disable warnings.")
577 self.add_option('-Y', '--repository', nargs=1, action="append",
578 help="Search REPOSITORY for source and target files.")
580 self.add_option('-e', '--environment-overrides', action="callback",
581 callback=opt_not_yet,
582 # help="Environment variables override makefiles."
584 self.add_option('-l', '--load-average', '--max-load', action="callback",
585 callback=opt_not_yet, type="int", dest="load_average",
587 # help="Don't start multiple jobs unless load is below "
591 self.add_option('--list-derived', action="callback",
592 callback=opt_not_yet,
593 # help="Don't build; list files that would be built."
595 self.add_option('--list-actions', action="callback",
596 callback=opt_not_yet,
597 # help="Don't build; list files and build actions."
599 self.add_option('--list-where', action="callback",
600 callback=opt_not_yet,
601 # help="Don't build; list files and where defined."
603 self.add_option('-o', '--old-file', '--assume-old', action="callback",
604 callback=opt_not_yet, type="string", dest="old_file",
605 # help = "Consider FILE to be old; don't rebuild it."
607 self.add_option('--override', action="callback", dest="override",
608 callback=opt_not_yet, type="string",
609 # help="Override variables as specified in FILE."
611 self.add_option('-p', action="callback",
612 callback=opt_not_yet,
613 # help="Print internal environments/objects."
615 self.add_option('-r', '-R', '--no-builtin-rules',
616 '--no-builtin-variables', action="callback",
617 callback=opt_not_yet,
618 # help="Clear default environments and variables."
620 self.add_option('-w', '--print-directory', action="callback",
621 callback=opt_not_yet,
622 # help="Print the current directory."
624 self.add_option('--no-print-directory', action="callback",
625 callback=opt_not_yet,
626 # help="Turn off -w, even if it was turned on implicitly."
628 self.add_option('--write-filenames', action="callback",
629 callback=opt_not_yet, type="string", dest="write_filenames",
630 # help="Write all filenames examined into FILE."
632 self.add_option('-W', '--what-if', '--new-file', '--assume-new',
634 action="callback", callback=opt_not_yet, type="string",
635 # help="Consider FILE to be changed."
637 self.add_option('--warn-undefined-variables', action="callback",
638 callback=opt_not_yet,
639 # help="Warn when an undefined variable is referenced."
642 def parse_args(self, args=None, values=None):
643 opt, arglist = OptionParser.parse_args(self, args, values)
644 if opt.implicit_deps_changed or opt.implicit_deps_unchanged:
645 opt.implicit_cache = 1
652 # Enable deprecated warnings by default.
653 SCons.Warnings._warningOut = _scons_internal_warning
654 SCons.Warnings.enableWarningClass(SCons.Warnings.DeprecatedWarning)
655 SCons.Warnings.enableWarningClass(SCons.Warnings.CorruptSConsignWarning)
657 all_args = sys.argv[1:]
659 all_args = string.split(os.environ['SCONSFLAGS']) + all_args
661 # it's OK if there's no SCONSFLAGS
665 options, args = parser.parse_args(all_args)
668 def raisePrintHelp(text):
669 raise PrintHelp, text
670 SCons.Script.SConscript.HelpFunction = raisePrintHelp
672 _set_globals(options)
673 SCons.Node.implicit_cache = options.implicit_cache
674 SCons.Node.implicit_deps_changed = options.implicit_deps_changed
675 SCons.Node.implicit_deps_unchanged = options.implicit_deps_unchanged
677 _setup_warn(options.warn)
679 SCons.Action.execute_actions = None
680 CleanTask.execute = CleanTask.show
681 if options.no_progress or options.silent:
684 SCons.Action.print_actions = None
685 if options.cache_disable:
686 def disable(self): pass
687 SCons.Node.FS.default_fs.CacheDir = disable
688 if options.cache_force:
689 SCons.Node.FS.default_fs.cache_force = 1
690 if options.cache_show:
691 SCons.Node.FS.default_fs.cache_show = 1
692 if options.directory:
693 cdir = _create_path(options.directory)
697 sys.stderr.write("Could not change directory to %s\n" % cdir)
705 SCons.Script.SConscript._scons_add_args(xmit_args)
709 target_top = '.' # directory to prepend to targets
710 script_dir = os.getcwd() # location of script
711 while script_dir and not _SConstruct_exists(script_dir):
712 script_dir, last_part = os.path.split(script_dir)
714 target_top = os.path.join(last_part, target_top)
718 display("scons: Entering directory %s" % script_dir)
721 raise SCons.Errors.UserError, "No SConstruct file found."
723 SCons.Node.FS.default_fs.set_toplevel_dir(os.getcwd())
727 scripts.extend(options.file)
729 sfile = _SConstruct_exists()
731 scripts.append(sfile)
735 # There's no SConstruct, but they specified -h.
736 # Give them the options usage now, before we fail
737 # trying to read a non-existent SConstruct file.
740 SCons.Script.SConscript.print_help = 1
743 raise SCons.Errors.UserError, "No SConstruct file found."
745 SCons.Node.FS.default_fs.set_SConstruct(scripts[0])
748 def __init__(self, file):
750 def write(self, arg):
753 def __getattr__(self, attr):
754 return getattr(self.file, attr)
756 sys.stdout = Unbuffered(sys.stdout)
758 if options.include_dir:
759 sys.path = options.include_dir + sys.path
762 for rep in repositories:
763 SCons.Node.FS.default_fs.Repository(rep)
765 display("scons: Reading SConscript files ...")
767 start_time = time.time()
769 for script in scripts:
770 SCons.Script.SConscript.SConscript(script)
771 except SCons.Errors.StopError, e:
772 # We had problems reading an SConscript file, such as it
773 # couldn't be copied in to the BuildDir. Since we're just
774 # reading SConscript files and haven't started building
775 # things yet, stop regardless of whether they used -i or -k
776 # or anything else, but don't say "Stop." on the message.
778 sys.stderr.write("scons: *** %s\n" % e)
780 sys.exit(exit_status)
781 global sconscript_time
782 sconscript_time = time.time() - start_time
783 except PrintHelp, text:
784 display("scons: done reading SConscript files.")
786 print "Use scons -H for help about command-line options."
788 display("scons: done reading SConscript files.")
790 SCons.Node.FS.default_fs.chdir(SCons.Node.FS.default_fs.Top)
793 # They specified -h, but there was no Help() inside the
794 # SConscript files. Give them the options usage.
795 parser.print_help(sys.stdout)
799 target_top = SCons.Node.FS.default_fs.Dir(target_top)
801 if options.climb_up == 2 and not targets:
802 # -D with default targets
804 elif options.climb_up == 3 and not targets:
805 # -U with default targets
806 default_targets = SCons.Script.SConscript.default_targets
807 def check_dir(x, target_top=target_top):
808 if hasattr(x, 'cwd') and not x.cwd is None:
809 cwd = x.cwd.srcnode()
810 return cwd == target_top
812 # x doesn't have a cwd, so it's either not a target,
813 # or not a file, so go ahead and keep it as a default
814 # target and let the engine sort it out:
816 default_targets = filter(check_dir, default_targets)
817 SCons.Script.SConscript.default_targets = default_targets
821 targets = SCons.Script.SConscript.default_targets
823 targets = [SCons.Node.FS.default_fs.Dir('.')]
826 sys.stderr.write("scons: *** No targets specified and no Default() targets found. Stop.\n")
829 def Entry(x, top = target_top):
830 if isinstance(x, SCons.Node.Node):
833 node = SCons.Node.Alias.default_ans.lookup(x)
835 node = SCons.Node.FS.default_fs.Entry(x,
838 if top and not node.is_under(top):
839 if isinstance(node, SCons.Node.FS.Dir) and top.is_under(node):
845 nodes = filter(lambda x: x is not None, map(Entry, targets))
848 task_class = BuildTask # default action is to build targets
850 task_class = QuestionTask
853 task_class = CleanTask
854 class CleanCalculator:
855 def bsig(self, node):
857 def csig(self, node):
859 def current(self, node, sig):
863 calc = CleanCalculator()
864 except AttributeError:
868 if options.max_drift is not None:
869 if sig_module is not None:
870 SCons.Sig.default_calc = SCons.Sig.Calculator(module=sig_module,
871 max_drift=options.max_drift)
873 SCons.Sig.default_calc = SCons.Sig.Calculator(max_drift=options.max_drift)
874 elif sig_module is not None:
875 SCons.Sig.default_calc = SCons.Sig.Calculator(module=sig_module)
877 calc = SCons.Sig.default_calc
880 def order(dependencies):
881 """Randomize the dependencies."""
882 # This is cribbed from the implementation of
883 # random.shuffle() in Python 2.X.
885 for i in xrange(len(d)-1, 0, -1):
886 j = int(random.random() * (i+1))
887 d[i], d[j] = d[j], d[i]
890 def order(dependencies):
891 """Leave the order of dependencies alone."""
894 display("scons: Building targets ...")
895 taskmaster = SCons.Taskmaster.Taskmaster(nodes, task_class, calc, order)
897 jobs = SCons.Job.Jobs(get_num_jobs(options), taskmaster)
902 display("scons: done building targets.")
910 except SystemExit, s:
913 except KeyboardInterrupt:
914 print "Build interrupted."
916 except SyntaxError, e:
917 _scons_syntax_error(e)
918 except SCons.Errors.UserError, e:
921 _scons_other_errors()
924 total_time = time.time()-start_time
925 scons_time = total_time-sconscript_time-command_time
926 print "Total build time: %f seconds"%total_time
927 print "Total SConscript file execution time: %f seconds"%sconscript_time
928 print "Total SCons execution time: %f seconds"%scons_time
929 print "Total command execution time: %f seconds"%command_time
931 sys.exit(exit_status)