summaryrefslogtreecommitdiffstats
path: root/src/engine/SCons/Script/Main.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine/SCons/Script/Main.py')
-rw-r--r--src/engine/SCons/Script/Main.py1144
1 files changed, 1144 insertions, 0 deletions
diff --git a/src/engine/SCons/Script/Main.py b/src/engine/SCons/Script/Main.py
new file mode 100644
index 0000000..1bd6939
--- /dev/null
+++ b/src/engine/SCons/Script/Main.py
@@ -0,0 +1,1144 @@
+"""SCons.Script
+
+This file implements the main() function used by the scons script.
+
+Architecturally, this *is* the scons script, and will likely only be
+called from the external "scons" wrapper. Consequently, anything here
+should not be, or be considered, part of the build engine. If it's
+something that we expect other software to want to use, it should go in
+some other module. If it's specific to the "scons" script invocation,
+it goes here.
+
+"""
+
+#
+# __COPYRIGHT__
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import os
+import os.path
+import random
+import string
+import sys
+import time
+import traceback
+
+# Strip the script directory from sys.path() so on case-insensitive
+# (WIN32) systems Python doesn't think that the "scons" script is the
+# "SCons" package. Replace it with our own version directory so, if
+# if they're there, we pick up the right version of the build engine
+# modules.
+#sys.path = [os.path.join(sys.prefix,
+# 'lib',
+# 'scons-%d' % SCons.__version__)] + sys.path[1:]
+
+import SCons.Debug
+import SCons.Defaults
+import SCons.Environment
+import SCons.Errors
+import SCons.Job
+import SCons.Node
+import SCons.Node.FS
+from SCons.Optik import OptionParser, SUPPRESS_HELP, OptionValueError
+import SCons.SConf
+import SCons.Sig
+import SCons.Taskmaster
+import SCons.Util
+import SCons.Warnings
+
+#
+display = SCons.Util.display
+progress_display = SCons.Util.DisplayEngine()
+
+# Task control.
+#
+class BuildTask(SCons.Taskmaster.Task):
+ """An SCons build task."""
+ def display(self, message):
+ display('scons: ' + message)
+
+ def execute(self):
+ target = self.targets[0]
+ if target.get_state() == SCons.Node.up_to_date:
+ if self.top and target.has_builder():
+ display("scons: `%s' is up to date." % str(self.node))
+ elif target.has_builder() and not hasattr(target.builder, 'status'):
+ if print_time:
+ start_time = time.time()
+ SCons.Taskmaster.Task.execute(self)
+ if print_time:
+ finish_time = time.time()
+ global command_time
+ command_time = command_time+finish_time-start_time
+ print "Command execution time: %f seconds"%(finish_time-start_time)
+
+ def do_failed(self, status=2):
+ global exit_status
+ if ignore_errors:
+ SCons.Taskmaster.Task.executed(self)
+ elif keep_going_on_error:
+ SCons.Taskmaster.Task.fail_continue(self)
+ exit_status = status
+ else:
+ SCons.Taskmaster.Task.fail_stop(self)
+ exit_status = status
+
+ def executed(self):
+ t = self.targets[0]
+ if self.top and not t.has_builder() and not t.side_effect:
+ if not t.exists():
+ sys.stderr.write("scons: *** Do not know how to make target `%s'." % t)
+ if not keep_going_on_error:
+ sys.stderr.write(" Stop.")
+ sys.stderr.write("\n")
+ self.do_failed()
+ else:
+ print "scons: Nothing to be done for `%s'." % t
+ SCons.Taskmaster.Task.executed(self)
+ else:
+ SCons.Taskmaster.Task.executed(self)
+
+ def failed(self):
+ # Handle the failure of a build task. The primary purpose here
+ # is to display the various types of Errors and Exceptions
+ # appropriately.
+ status = 2
+ exc_info = self.exc_info()
+ try:
+ t, e, tb = exc_info
+ except ValueError:
+ t, e = exc_info
+ tb = None
+ if t is None:
+ # The Taskmaster didn't record an exception for this Task;
+ # see if the sys module has one.
+ t, e = sys.exc_info()[:2]
+
+ if t == SCons.Errors.BuildError:
+ fname = e.node
+ if SCons.Util.is_List(e.node):
+ fname = string.join(map(str, e.node), ', ')
+ sys.stderr.write("scons: *** [%s] %s\n" % (fname, e.errstr))
+ if e.errstr == 'Exception':
+ traceback.print_exception(e.args[0], e.args[1], e.args[2])
+ elif t == SCons.Errors.ExplicitExit:
+ status = e.status
+ sys.stderr.write("scons: *** [%s] Explicit exit, status %s\n" % (e.node, e.status))
+ else:
+ if e is None:
+ e = t
+ s = str(e)
+ if t == SCons.Errors.StopError and not keep_going_on_error:
+ s = s + ' Stop.'
+ sys.stderr.write("scons: *** %s\n" % s)
+
+ if tb and print_stacktrace:
+ sys.stderr.write("scons: internal stack trace:\n")
+ traceback.print_tb(tb, file=sys.stderr)
+
+ self.do_failed(status)
+
+ self.exc_clear()
+
+ def postprocess(self):
+ if self.top:
+ t = self.targets[0]
+ if print_tree:
+ print
+ SCons.Util.print_tree(t, get_all_children)
+ if print_stree:
+ print
+ SCons.Util.print_tree(t, get_all_children, showtags=2)
+ if print_dtree:
+ print
+ SCons.Util.print_tree(t, get_derived_children)
+ if print_includes:
+ tree = t.render_include_tree()
+ if tree:
+ print
+ print tree
+ SCons.Taskmaster.Task.postprocess(self)
+
+ def make_ready(self):
+ """Make a task ready for execution"""
+ SCons.Taskmaster.Task.make_ready(self)
+ if self.out_of_date and print_explanations:
+ explanation = self.out_of_date[0].explain()
+ if explanation:
+ sys.stdout.write("scons: " + explanation)
+
+class CleanTask(SCons.Taskmaster.Task):
+ """An SCons clean task."""
+ def show(self):
+ if (self.targets[0].has_builder() or self.targets[0].side_effect) \
+ and not os.path.isdir(str(self.targets[0])):
+ display("Removed " + str(self.targets[0]))
+ if SCons.Environment.CleanTargets.has_key(self.targets[0]):
+ files = SCons.Environment.CleanTargets[self.targets[0]]
+ for f in files:
+ SCons.Util.fs_delete(str(f), 0)
+
+ def remove(self):
+ if self.targets[0].has_builder() or self.targets[0].side_effect:
+ for t in self.targets:
+ try:
+ removed = t.remove()
+ except OSError, e:
+ print "scons: Could not remove '%s':" % str(t), e.strerror
+ else:
+ if removed:
+ display("Removed " + str(t))
+ if SCons.Environment.CleanTargets.has_key(self.targets[0]):
+ files = SCons.Environment.CleanTargets[self.targets[0]]
+ for f in files:
+ SCons.Util.fs_delete(str(f))
+
+ execute = remove
+
+ # Have the taskmaster arrange to "execute" all of the targets, because
+ # we'll figure out ourselves (in remove() or show() above) whether
+ # anything really needs to be done.
+ make_ready = SCons.Taskmaster.Task.make_ready_all
+
+ def prepare(self):
+ pass
+
+class QuestionTask(SCons.Taskmaster.Task):
+ """An SCons task for the -q (question) option."""
+ def prepare(self):
+ pass
+
+ def execute(self):
+ if self.targets[0].get_state() != SCons.Node.up_to_date:
+ global exit_status
+ exit_status = 1
+ self.tm.stop()
+
+ def executed(self):
+ pass
+
+# Global variables
+
+keep_going_on_error = 0
+print_count = 0
+print_dtree = 0
+print_explanations = 0
+print_includes = 0
+print_objects = 0
+print_stacktrace = 0
+print_stree = 0
+print_time = 0
+print_tree = 0
+memory_stats = None
+ignore_errors = 0
+sconscript_time = 0
+command_time = 0
+exit_status = 0 # exit status, assume success by default
+profiling = 0
+repositories = []
+num_jobs = 1 # this is modifed by SConscript.SetJobs()
+
+# utility functions
+
+def get_all_children(node): return node.all_children()
+
+def get_derived_children(node):
+ children = node.all_children(None)
+ return filter(lambda x: x.has_builder(), children)
+
+def _scons_syntax_error(e):
+ """Handle syntax errors. Print out a message and show where the error
+ occurred.
+ """
+ etype, value, tb = sys.exc_info()
+ lines = traceback.format_exception_only(etype, value)
+ for line in lines:
+ sys.stderr.write(line+'\n')
+ sys.exit(2)
+
+def find_deepest_user_frame(tb):
+ """
+ Find the deepest stack frame that is not part of SCons.
+
+ Input is a "pre-processed" stack trace in the form
+ returned by traceback.extract_tb() or traceback.extract_stack()
+ """
+
+ tb.reverse()
+
+ # find the deepest traceback frame that is not part
+ # of SCons:
+ for frame in tb:
+ filename = frame[0]
+ if string.find(filename, os.sep+'SCons'+os.sep) == -1:
+ return frame
+ return tb[0]
+
+def _scons_user_error(e):
+ """Handle user errors. Print out a message and a description of the
+ error, along with the line number and routine where it occured.
+ The file and line number will be the deepest stack frame that is
+ not part of SCons itself.
+ """
+ etype, value, tb = sys.exc_info()
+ filename, lineno, routine, dummy = find_deepest_user_frame(traceback.extract_tb(tb))
+ sys.stderr.write("\nscons: *** %s\n" % value)
+ sys.stderr.write('File "%s", line %d, in %s\n' % (filename, lineno, routine))
+ sys.exit(2)
+
+def _scons_user_warning(e):
+ """Handle user warnings. Print out a message and a description of
+ the warning, along with the line number and routine where it occured.
+ The file and line number will be the deepest stack frame that is
+ not part of SCons itself.
+ """
+ etype, value, tb = sys.exc_info()
+ filename, lineno, routine, dummy = find_deepest_user_frame(traceback.extract_tb(tb))
+ sys.stderr.write("\nscons: warning: %s\n" % e)
+ sys.stderr.write('File "%s", line %d, in %s\n' % (filename, lineno, routine))
+
+def _scons_internal_warning(e):
+ """Slightly different from _scons_user_warning in that we use the
+ *current call stack* rather than sys.exc_info() to get our stack trace.
+ This is used by the warnings framework to print warnings."""
+ filename, lineno, routine, dummy = find_deepest_user_frame(traceback.extract_stack())
+ sys.stderr.write("\nscons: warning: %s\n" % e[0])
+ sys.stderr.write('File "%s", line %d, in %s\n' % (filename, lineno, routine))
+
+def _scons_internal_error():
+ """Handle all errors but user errors. Print out a message telling
+ the user what to do in this case and print a normal trace.
+ """
+ print 'internal error'
+ traceback.print_exc()
+ sys.exit(2)
+
+def _varargs(option, parser):
+ value = None
+ if parser.rargs:
+ arg = parser.rargs[0]
+ if arg[0] != "-":
+ value = arg
+ del parser.rargs[0]
+ return value
+
+def _setup_warn(arg):
+ """The --warn option. An argument to this option
+ should be of the form <warning-class> or no-<warning-class>.
+ The warning class is munged in order to get an actual class
+ name from the SCons.Warnings module to enable or disable.
+ The supplied <warning-class> is split on hyphens, each element
+ is captialized, then smushed back together. Then the string
+ "SCons.Warnings." is added to the front and "Warning" is added
+ to the back to get the fully qualified class name.
+
+ For example, --warn=deprecated will enable the
+ SCons.Warnings.DeprecatedWarning class.
+
+ --warn=no-dependency will disable the
+ SCons.Warnings.DependencyWarning class.
+
+ As a special case, --warn=all and --warn=no-all
+ will enable or disable (respectively) the base
+ class of all warnings, which is SCons.Warning.Warning."""
+
+ elems = string.split(string.lower(arg), '-')
+ enable = 1
+ if elems[0] == 'no':
+ enable = 0
+ del elems[0]
+
+ if len(elems) == 1 and elems[0] == 'all':
+ class_name = "Warning"
+ else:
+ def _capitalize(s):
+ if s[:5] == "scons":
+ return "SCons" + s[5:]
+ else:
+ return string.capitalize(s)
+ class_name = string.join(map(_capitalize, elems), '') + "Warning"
+ try:
+ clazz = getattr(SCons.Warnings, class_name)
+ except AttributeError:
+ sys.stderr.write("No warning type: '%s'\n" % arg)
+ else:
+ if enable:
+ SCons.Warnings.enableWarningClass(clazz)
+ else:
+ SCons.Warnings.suppressWarningClass(clazz)
+
+def _SConstruct_exists(dirname=''):
+ """This function checks that an SConstruct file exists in a directory.
+ If so, it returns the path of the file. By default, it checks the
+ current directory.
+ """
+ global repositories
+ for file in ['SConstruct', 'Sconstruct', 'sconstruct']:
+ sfile = os.path.join(dirname, file)
+ if os.path.isfile(sfile):
+ return sfile
+ if not os.path.isabs(sfile):
+ for rep in repositories:
+ if os.path.isfile(os.path.join(rep, sfile)):
+ return sfile
+ return None
+
+def _set_globals(options):
+ global repositories, keep_going_on_error, ignore_errors
+ global print_count, print_dtree
+ global print_explanations, print_includes
+ global print_objects, print_stacktrace, print_stree
+ global print_time, print_tree
+ global memory_outf, memory_stats
+
+ if options.repository:
+ repositories.extend(options.repository)
+ keep_going_on_error = options.keep_going
+ try:
+ if options.debug:
+ if options.debug == "count":
+ print_count = 1
+ elif options.debug == "dtree":
+ print_dtree = 1
+ elif options.debug == "explain":
+ print_explanations = 1
+ elif options.debug == "findlibs":
+ SCons.Scanner.Prog.print_find_libs = "findlibs"
+ elif options.debug == "includes":
+ print_includes = 1
+ elif options.debug == "memory":
+ memory_stats = []
+ memory_outf = sys.stdout
+ elif options.debug == "objects":
+ print_objects = 1
+ elif options.debug == "presub":
+ SCons.Action.print_actions_presub = 1
+ elif options.debug == "stacktrace":
+ print_stacktrace = 1
+ elif options.debug == "stree":
+ print_stree = 1
+ elif options.debug == "time":
+ print_time = 1
+ elif options.debug == "tree":
+ print_tree = 1
+ except AttributeError:
+ pass
+ ignore_errors = options.ignore_errors
+
+def _create_path(plist):
+ path = '.'
+ for d in plist:
+ if os.path.isabs(d):
+ path = d
+ else:
+ path = path + '/' + d
+ return path
+
+
+class OptParser(OptionParser):
+ def __init__(self):
+ import __main__
+ import SCons
+ parts = ["SCons by Steven Knight et al.:\n"]
+ try:
+ parts.append("\tscript: v%s.%s, %s, by %s on %s\n" % (__main__.__version__,
+ __main__.__build__,
+ __main__.__date__,
+ __main__.__developer__,
+ __main__.__buildsys__))
+ except KeyboardInterrupt:
+ raise
+ except:
+ # On win32 there is no scons.py, so there is no __main__.__version__,
+ # hence there is no script version.
+ pass
+ parts.append("\tengine: v%s.%s, %s, by %s on %s\n" % (SCons.__version__,
+ SCons.__build__,
+ SCons.__date__,
+ SCons.__developer__,
+ SCons.__buildsys__))
+ parts.append("__COPYRIGHT__")
+ OptionParser.__init__(self, version=string.join(parts, ''),
+ usage="usage: scons [OPTION] [TARGET] ...")
+
+ # options ignored for compatibility
+ def opt_ignore(option, opt, value, parser):
+ sys.stderr.write("Warning: ignoring %s option\n" % opt)
+ self.add_option("-b", "-m", "-S", "-t", "--no-keep-going", "--stop",
+ "--touch", action="callback", callback=opt_ignore,
+ help="Ignored for compatibility.")
+
+ self.add_option('-c', '--clean', '--remove', action="store_true",
+ dest="clean",
+ help="Remove specified targets and dependencies.")
+
+ self.add_option('-C', '--directory', type="string", action = "append",
+ metavar="DIR",
+ help="Change to DIR before doing anything.")
+
+ self.add_option('--cache-disable', '--no-cache',
+ action="store_true", dest='cache_disable', default=0,
+ help="Do not retrieve built targets from CacheDir.")
+
+ self.add_option('--cache-force', '--cache-populate',
+ action="store_true", dest='cache_force', default=0,
+ help="Copy already-built targets into the CacheDir.")
+
+ self.add_option('--cache-show',
+ action="store_true", dest='cache_show', default=0,
+ help="Print build actions for files from CacheDir.")
+
+ config_options = ["auto", "force" ,"cache"]
+
+ def opt_config(option, opt, value, parser, c_options=config_options):
+ if value in c_options:
+ parser.values.config = value
+ else:
+ raise OptionValueError("Warning: %s is not a valid config type" % value)
+ self.add_option('--config', action="callback", type="string",
+ callback=opt_config, nargs=1, dest="config",
+ metavar="MODE", default="auto",
+ help="Controls Configure subsystem: "
+ "%s." % string.join(config_options, ", "))
+
+ def opt_not_yet(option, opt, value, parser):
+ sys.stderr.write("Warning: the %s option is not yet implemented\n" % opt)
+ sys.exit(0)
+ self.add_option('-d', action="callback",
+ callback=opt_not_yet,
+ help = "Print file dependency information.")
+
+ self.add_option('-D', action="store_const", const=2, dest="climb_up",
+ help="Search up directory tree for SConstruct, "
+ "build all Default() targets.")
+
+ debug_options = ["count", "dtree", "explain", "findlibs",
+ "includes", "memory", "objects",
+ "pdb", "presub", "stacktrace", "stree",
+ "time", "tree"]
+
+ def opt_debug(option, opt, value, parser, debug_options=debug_options):
+ if value in debug_options:
+ parser.values.debug = value
+ else:
+ raise OptionValueError("Warning: %s is not a valid debug type" % value)
+ self.add_option('--debug', action="callback", type="string",
+ callback=opt_debug, nargs=1, dest="debug",
+ metavar="TYPE",
+ help="Print various types of debugging information: "
+ "%s." % string.join(debug_options, ", "))
+
+ def opt_duplicate(option, opt, value, parser):
+ if not value in SCons.Node.FS.Valid_Duplicates:
+ raise OptionValueError("`%s' is not a valid duplication style." % value)
+ parser.values.duplicate = value
+ # Set the duplicate style right away so it can affect linking
+ # of SConscript files.
+ SCons.Node.FS.set_duplicate(value)
+ self.add_option('--duplicate', action="callback", type="string",
+ callback=opt_duplicate, nargs=1, dest="duplicate",
+ help="Set the preferred duplication methods. Must be one of "
+ + string.join(SCons.Node.FS.Valid_Duplicates, ", "))
+
+ self.add_option('-f', '--file', '--makefile', '--sconstruct',
+ action="append", nargs=1,
+ help="Read FILE as the top-level SConstruct file.")
+
+ self.add_option('-h', '--help', action="store_true", default=0,
+ dest="help_msg",
+ help="Print defined help message, or this one.")
+
+ self.add_option("-H", "--help-options",
+ action="help",
+ help="Print this message and exit.")
+
+ self.add_option('-i', '--ignore-errors', action="store_true",
+ default=0, dest='ignore_errors',
+ help="Ignore errors from build actions.")
+
+ self.add_option('-I', '--include-dir', action="append",
+ dest='include_dir', metavar="DIR",
+ help="Search DIR for imported Python modules.")
+
+ self.add_option('--implicit-cache', action="store_true",
+ dest='implicit_cache',
+ help="Cache implicit dependencies")
+
+ self.add_option('--implicit-deps-changed', action="store_true",
+ default=0, dest='implicit_deps_changed',
+ help="Ignore cached implicit dependencies.")
+ self.add_option('--implicit-deps-unchanged', action="store_true",
+ default=0, dest='implicit_deps_unchanged',
+ help="Ignore changes in implicit dependencies.")
+
+ def opt_j(option, opt, value, parser):
+ value = int(value)
+ parser.values.num_jobs = value
+ self.add_option('-j', '--jobs', action="callback", type="int",
+ callback=opt_j, metavar="N",
+ help="Allow N jobs at once.")
+
+ self.add_option('-k', '--keep-going', action="store_true", default=0,
+ dest='keep_going',
+ help="Keep going when a target can't be made.")
+
+ self.add_option('--max-drift', type="int", action="store",
+ dest='max_drift', metavar="N",
+ help="Set maximum system clock drift to N seconds.")
+
+ self.add_option('-n', '--no-exec', '--just-print', '--dry-run',
+ '--recon', action="store_true", dest='noexec',
+ default=0, help="Don't build; just print commands.")
+
+ def opt_profile(option, opt, value, parser):
+ global profiling
+ if not profiling:
+ profiling = 1
+ import profile
+ profile.run('SCons.Script.Main.main()', value)
+ sys.exit(exit_status)
+ self.add_option('--profile', nargs=1, action="callback",
+ callback=opt_profile, type="string", dest="profile",
+ metavar="FILE",
+ help="Profile SCons and put results in FILE.")
+
+ self.add_option('-q', '--question', action="store_true", default=0,
+ help="Don't build; exit status says if up to date.")
+
+ self.add_option('-Q', dest='no_progress', action="store_true",
+ default=0,
+ help="Suppress \"Reading/Building\" progress messages.")
+
+ self.add_option('--random', dest="random", action="store_true",
+ default=0, help="Build dependencies in random order.")
+
+ self.add_option('-s', '--silent', '--quiet', action="store_true",
+ default=0, help="Don't print commands.")
+
+ self.add_option('-u', '--up', '--search-up', action="store_const",
+ dest="climb_up", default=0, const=1,
+ help="Search up directory tree for SConstruct, "
+ "build targets at or below current directory.")
+ self.add_option('-U', action="store_const", dest="climb_up",
+ default=0, const=3,
+ help="Search up directory tree for SConstruct, "
+ "build Default() targets from local SConscript.")
+
+ self.add_option("-v", "--version",
+ action="version",
+ help="Print the SCons version number and exit.")
+
+ self.add_option('--warn', '--warning', nargs=1, action="store",
+ metavar="WARNING-SPEC",
+ help="Enable or disable warnings.")
+
+ self.add_option('-Y', '--repository', nargs=1, action="append",
+ help="Search REPOSITORY for source and target files.")
+
+ self.add_option('-e', '--environment-overrides', action="callback",
+ callback=opt_not_yet,
+ # help="Environment variables override makefiles."
+ help=SUPPRESS_HELP)
+ self.add_option('-l', '--load-average', '--max-load', action="callback",
+ callback=opt_not_yet, type="int", dest="load_average",
+ # action="store",
+ # help="Don't start multiple jobs unless load is below "
+ # "LOAD-AVERAGE."
+ # type="int",
+ help=SUPPRESS_HELP)
+ self.add_option('--list-derived', action="callback",
+ callback=opt_not_yet,
+ # help="Don't build; list files that would be built."
+ help=SUPPRESS_HELP)
+ self.add_option('--list-actions', action="callback",
+ callback=opt_not_yet,
+ # help="Don't build; list files and build actions."
+ help=SUPPRESS_HELP)
+ self.add_option('--list-where', action="callback",
+ callback=opt_not_yet,
+ # help="Don't build; list files and where defined."
+ help=SUPPRESS_HELP)
+ self.add_option('-o', '--old-file', '--assume-old', action="callback",
+ callback=opt_not_yet, type="string", dest="old_file",
+ # help = "Consider FILE to be old; don't rebuild it."
+ help=SUPPRESS_HELP)
+ self.add_option('--override', action="callback", dest="override",
+ callback=opt_not_yet, type="string",
+ # help="Override variables as specified in FILE."
+ help=SUPPRESS_HELP)
+ self.add_option('-p', action="callback",
+ callback=opt_not_yet,
+ # help="Print internal environments/objects."
+ help=SUPPRESS_HELP)
+ self.add_option('-r', '-R', '--no-builtin-rules',
+ '--no-builtin-variables', action="callback",
+ callback=opt_not_yet,
+ # help="Clear default environments and variables."
+ help=SUPPRESS_HELP)
+ self.add_option('-w', '--print-directory', action="callback",
+ callback=opt_not_yet,
+ # help="Print the current directory."
+ help=SUPPRESS_HELP)
+ self.add_option('--no-print-directory', action="callback",
+ callback=opt_not_yet,
+ # help="Turn off -w, even if it was turned on implicitly."
+ help=SUPPRESS_HELP)
+ self.add_option('--write-filenames', action="callback",
+ callback=opt_not_yet, type="string", dest="write_filenames",
+ # help="Write all filenames examined into FILE."
+ help=SUPPRESS_HELP)
+ self.add_option('-W', '--what-if', '--new-file', '--assume-new',
+ dest="new_file",
+ action="callback", callback=opt_not_yet, type="string",
+ # help="Consider FILE to be changed."
+ help=SUPPRESS_HELP)
+ self.add_option('--warn-undefined-variables', action="callback",
+ callback=opt_not_yet,
+ # help="Warn when an undefined variable is referenced."
+ help=SUPPRESS_HELP)
+
+ def parse_args(self, args=None, values=None):
+ opt, arglist = OptionParser.parse_args(self, args, values)
+ if opt.implicit_deps_changed or opt.implicit_deps_unchanged:
+ opt.implicit_cache = 1
+ return opt, arglist
+
+class SConscriptSettableOptions:
+ """This class wraps an OptParser instance and provides
+ uniform access to options that can be either set on the command
+ line or from a SConscript file. A value specified on the command
+ line always overrides a value set in a SConscript file.
+ Not all command line options are SConscript settable, and the ones
+ that are must be explicitly added to settable dictionary and optionally
+ validated and coerced in the set() method."""
+
+ def __init__(self, options):
+ self.options = options
+
+ # This dictionary stores the defaults for all the SConscript
+ # settable options, as well as indicating which options
+ # are SConscript settable.
+ self.settable = {'num_jobs':1,
+ 'max_drift':SCons.Sig.default_max_drift,
+ 'implicit_cache':0,
+ 'clean':0,
+ 'duplicate':'hard-soft-copy'}
+
+ def get(self, name):
+ if not self.settable.has_key(name):
+ raise SCons.Error.UserError, "This option is not settable from a SConscript file: %s"%name
+ if hasattr(self.options, name) and getattr(self.options, name) is not None:
+ return getattr(self.options, name)
+ else:
+ return self.settable[name]
+
+ def set(self, name, value):
+ if not self.settable.has_key(name):
+ raise SCons.Error.UserError, "This option is not settable from a SConscript file: %s"%name
+
+ if name == 'num_jobs':
+ try:
+ value = int(value)
+ if value < 1:
+ raise ValueError
+ except ValueError:
+ raise SCons.Errors.UserError, "A positive integer is required: %s"%repr(value)
+ elif name == 'max_drift':
+ try:
+ value = int(value)
+ except ValueError:
+ raise SCons.Errors.UserError, "An integer is required: %s"%repr(value)
+ elif name == 'duplicate':
+ try:
+ value = str(value)
+ except ValueError:
+ raise SCons.Errors.UserError, "A string is required: %s"%repr(value)
+ if not value in SCons.Node.FS.Valid_Duplicates:
+ raise SCons.Errors.UserError, "Not a valid duplication style: %s" % value
+ # Set the duplicate stye right away so it can affect linking
+ # of SConscript files.
+ SCons.Node.FS.set_duplicate(value)
+
+ self.settable[name] = value
+
+
+def _main(args, parser):
+ targets = []
+ fs = SCons.Node.FS.default_fs
+
+ # Enable deprecated warnings by default.
+ SCons.Warnings._warningOut = _scons_internal_warning
+ SCons.Warnings.enableWarningClass(SCons.Warnings.CorruptSConsignWarning)
+ SCons.Warnings.enableWarningClass(SCons.Warnings.DeprecatedWarning)
+ SCons.Warnings.enableWarningClass(SCons.Warnings.DuplicateEnvironmentWarning)
+ SCons.Warnings.enableWarningClass(SCons.Warnings.MissingSConscriptWarning)
+ SCons.Warnings.enableWarningClass(SCons.Warnings.NoParallelSupportWarning)
+ # This is good for newbies, and hopefully most everyone else too.
+ SCons.Warnings.enableWarningClass(SCons.Warnings.MisleadingKeywordsWarning)
+
+ global ssoptions
+ ssoptions = SConscriptSettableOptions(options)
+
+ _set_globals(options)
+ SCons.Node.implicit_cache = options.implicit_cache
+ SCons.Node.implicit_deps_changed = options.implicit_deps_changed
+ SCons.Node.implicit_deps_unchanged = options.implicit_deps_unchanged
+ if options.warn:
+ _setup_warn(options.warn)
+ if options.noexec:
+ SCons.SConf.dryrun = 1
+ SCons.Action.execute_actions = None
+ CleanTask.execute = CleanTask.show
+ if options.question:
+ SCons.SConf.dryrun = 1
+ SCons.SConf.SetCacheMode(options.config)
+ SCons.SConf.SetProgressDisplay(progress_display)
+
+ if options.no_progress or options.silent:
+ progress_display.set_mode(0)
+ if options.silent:
+ display.set_mode(0)
+ if options.silent:
+ SCons.Action.print_actions = None
+ if options.cache_disable:
+ def disable(self): pass
+ fs.CacheDir = disable
+ if options.cache_force:
+ fs.cache_force = 1
+ if options.cache_show:
+ fs.cache_show = 1
+ if options.directory:
+ cdir = _create_path(options.directory)
+ try:
+ os.chdir(cdir)
+ except OSError:
+ sys.stderr.write("Could not change directory to %s\n" % cdir)
+
+ xmit_args = []
+ for a in args:
+ if '=' in a:
+ xmit_args.append(a)
+ else:
+ targets.append(a)
+ SCons.Script._Add_Arguments(xmit_args)
+ SCons.Script._Add_Targets(targets)
+
+ target_top = None
+ if options.climb_up:
+ target_top = '.' # directory to prepend to targets
+ script_dir = os.getcwd() # location of script
+ while script_dir and not _SConstruct_exists(script_dir):
+ script_dir, last_part = os.path.split(script_dir)
+ if last_part:
+ target_top = os.path.join(last_part, target_top)
+ else:
+ script_dir = ''
+ if script_dir:
+ display("scons: Entering directory `%s'" % script_dir)
+ os.chdir(script_dir)
+ else:
+ raise SCons.Errors.UserError, "No SConstruct file found."
+
+ fs.set_toplevel_dir(os.getcwd())
+
+ scripts = []
+ if options.file:
+ scripts.extend(options.file)
+ if not scripts:
+ sfile = _SConstruct_exists()
+ if sfile:
+ scripts.append(sfile)
+
+ if options.help_msg:
+ if not scripts:
+ # There's no SConstruct, but they specified -h.
+ # Give them the options usage now, before we fail
+ # trying to read a non-existent SConstruct file.
+ parser.print_help()
+ sys.exit(0)
+
+ if not scripts:
+ raise SCons.Errors.UserError, "No SConstruct file found."
+
+ if scripts[0] == "-":
+ d = fs.getcwd()
+ else:
+ d = fs.File(scripts[0]).dir
+ fs.set_SConstruct_dir(d)
+
+ class Unbuffered:
+ def __init__(self, file):
+ self.file = file
+ def write(self, arg):
+ self.file.write(arg)
+ self.file.flush()
+ def __getattr__(self, attr):
+ return getattr(self.file, attr)
+
+ sys.stdout = Unbuffered(sys.stdout)
+
+ if options.include_dir:
+ sys.path = options.include_dir + sys.path
+
+ global repositories
+ for rep in repositories:
+ fs.Repository(rep)
+
+ if not memory_stats is None: memory_stats.append(SCons.Debug.memory())
+
+ progress_display("scons: Reading SConscript files ...")
+
+ start_time = time.time()
+ try:
+ for script in scripts:
+ SCons.Script._SConscript._SConscript(fs, script)
+ except SCons.Errors.StopError, e:
+ # We had problems reading an SConscript file, such as it
+ # couldn't be copied in to the BuildDir. Since we're just
+ # reading SConscript files and haven't started building
+ # things yet, stop regardless of whether they used -i or -k
+ # or anything else.
+ global exit_status
+ sys.stderr.write("scons: *** %s Stop.\n" % e)
+ exit_status = 2
+ sys.exit(exit_status)
+ global sconscript_time
+ sconscript_time = time.time() - start_time
+ SCons.SConf.CreateConfigHBuilder(SCons.Defaults.DefaultEnvironment())
+ progress_display("scons: done reading SConscript files.")
+
+ # Tell the Node.FS subsystem that we're all done reading the
+ # SConscript files and calling Repository() and BuildDir() and the
+ # like, so it can go ahead and start memoizing the string values of
+ # file system nodes.
+ SCons.Node.FS.save_strings(1)
+
+ if not memory_stats is None: memory_stats.append(SCons.Debug.memory())
+
+ fs.chdir(fs.Top)
+
+ if options.help_msg:
+ help_text = SCons.Script.help_text
+ if help_text is None:
+ # They specified -h, but there was no Help() inside the
+ # SConscript files. Give them the options usage.
+ parser.print_help(sys.stdout)
+ else:
+ print help_text
+ print "Use scons -H for help about command-line options."
+ sys.exit(0)
+
+ # Now that we've read the SConscripts we can set the options
+ # that are SConscript settable:
+ SCons.Node.implicit_cache = ssoptions.get('implicit_cache')
+ SCons.Node.FS.set_duplicate(ssoptions.get('duplicate'))
+
+ lookup_top = None
+ if targets:
+ # They specified targets on the command line, so if they
+ # used -u, -U or -D, we have to look up targets relative
+ # to the top, but we build whatever they specified.
+ if target_top:
+ lookup_top = fs.Dir(target_top)
+ target_top = None
+ else:
+ # There are no targets specified on the command line,
+ # so if they used -u, -U or -D, we may have to restrict
+ # what actually gets built.
+ d = None
+ if target_top:
+ if options.climb_up == 1:
+ # -u, local directory and below
+ target_top = fs.Dir(target_top)
+ lookup_top = target_top
+ elif options.climb_up == 2:
+ # -D, all Default() targets
+ target_top = None
+ lookup_top = None
+ elif options.climb_up == 3:
+ # -U, local SConscript Default() targets
+ target_top = fs.Dir(target_top)
+ def check_dir(x, target_top=target_top):
+ if hasattr(x, 'cwd') and not x.cwd is None:
+ cwd = x.cwd.srcnode()
+ return cwd == target_top
+ else:
+ # x doesn't have a cwd, so it's either not a target,
+ # or not a file, so go ahead and keep it as a default
+ # target and let the engine sort it out:
+ return 1
+ d = filter(check_dir, SCons.Script.DEFAULT_TARGETS)
+ SCons.Script.DEFAULT_TARGETS[:] = d
+ target_top = None
+ lookup_top = None
+
+ targets = SCons.Script._Get_Default_Targets(d, fs)
+
+ if not targets:
+ sys.stderr.write("scons: *** No targets specified and no Default() targets found. Stop.\n")
+ sys.exit(2)
+
+ def Entry(x, ltop=lookup_top, ttop=target_top, fs=fs):
+ if isinstance(x, SCons.Node.Node):
+ node = x
+ else:
+ node = SCons.Node.Alias.default_ans.lookup(x)
+ if node is None:
+ node = fs.Entry(x, directory=ltop, create=1)
+ if ttop and not node.is_under(ttop):
+ if isinstance(node, SCons.Node.FS.Dir) and ttop.is_under(node):
+ node = ttop
+ else:
+ node = None
+ return node
+
+ nodes = filter(lambda x: x is not None, map(Entry, targets))
+
+ task_class = BuildTask # default action is to build targets
+ opening_message = "Building targets ..."
+ closing_message = "done building targets."
+ if keep_going_on_error:
+ failure_message = "done building targets (errors occurred during build)."
+ else:
+ failure_message = "building terminated because of errors."
+ if options.question:
+ task_class = QuestionTask
+ try:
+ if ssoptions.get('clean'):
+ task_class = CleanTask
+ opening_message = "Cleaning targets ..."
+ closing_message = "done cleaning targets."
+ if keep_going_on_error:
+ closing_message = "done cleaning targets (errors occurred during clean)."
+ else:
+ failure_message = "cleaning terminated because of errors."
+ except AttributeError:
+ pass
+
+ SCons.Environment.CalculatorArgs['max_drift'] = ssoptions.get('max_drift')
+
+ if options.random:
+ def order(dependencies):
+ """Randomize the dependencies."""
+ # This is cribbed from the implementation of
+ # random.shuffle() in Python 2.X.
+ d = dependencies
+ for i in xrange(len(d)-1, 0, -1):
+ j = int(random.random() * (i+1))
+ d[i], d[j] = d[j], d[i]
+ return d
+ else:
+ def order(dependencies):
+ """Leave the order of dependencies alone."""
+ return dependencies
+
+ progress_display("scons: " + opening_message)
+ taskmaster = SCons.Taskmaster.Taskmaster(nodes, task_class, order)
+
+ nj = ssoptions.get('num_jobs')
+ jobs = SCons.Job.Jobs(nj, taskmaster)
+ if nj > 1 and jobs.num_jobs == 1:
+ msg = "parallel builds are unsupported by this version of Python;\n" + \
+ "\tignoring -j or num_jobs option.\n"
+ SCons.Warnings.warn(SCons.Warnings.NoParallelSupportWarning, msg)
+
+ if not memory_stats is None: memory_stats.append(SCons.Debug.memory())
+
+ try:
+ jobs.run()
+ finally:
+ if exit_status:
+ progress_display("scons: " + failure_message)
+ else:
+ progress_display("scons: " + closing_message)
+ if not options.noexec:
+ SCons.SConsign.write()
+
+ if not memory_stats is None:
+ memory_stats.append(SCons.Debug.memory())
+ when = [
+ 'before SConscript files',
+ 'after SConscript files',
+ 'before building',
+ 'after building',
+ ]
+ for i in xrange(len(when)):
+ memory_outf.write('Memory %s: %d\n' % (when[i], memory_stats[i]))
+
+ if print_count:
+ SCons.Debug.countLoggedInstances('*')
+
+ if print_objects:
+ SCons.Debug.listLoggedInstances('*')
+ #SCons.Debug.dumpLoggedInstances('*')
+
+def _exec_main():
+ all_args = sys.argv[1:]
+ try:
+ all_args = string.split(os.environ['SCONSFLAGS']) + all_args
+ except KeyError:
+ # it's OK if there's no SCONSFLAGS
+ pass
+ parser = OptParser()
+ global options
+ options, args = parser.parse_args(all_args)
+ if options.debug == "pdb":
+ import pdb
+ pdb.Pdb().runcall(_main, args, parser)
+ else:
+ _main(args, parser)
+
+def main():
+ global exit_status
+
+ try:
+ _exec_main()
+ except SystemExit, s:
+ if s:
+ exit_status = s
+ except KeyboardInterrupt:
+ print "Build interrupted."
+ sys.exit(2)
+ except SyntaxError, e:
+ _scons_syntax_error(e)
+ except SCons.Errors.InternalError:
+ _scons_internal_error()
+ except SCons.Errors.UserError, e:
+ _scons_user_error(e)
+ except:
+ # An exception here is likely a builtin Python exception Python
+ # code in an SConscript file. Show them precisely what the
+ # problem was and where it happened.
+ SCons.Script._SConscript.SConscript_exception()
+ sys.exit(2)
+
+ if print_time:
+ total_time = time.time()-SCons.Script.start_time
+ scons_time = total_time-sconscript_time-command_time
+ print "Total build time: %f seconds"%total_time
+ print "Total SConscript file execution time: %f seconds"%sconscript_time
+ print "Total SCons execution time: %f seconds"%scons_time
+ print "Total command execution time: %f seconds"%command_time
+
+ sys.exit(exit_status)