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.py688
1 files changed, 160 insertions, 528 deletions
diff --git a/src/engine/SCons/Script/Main.py b/src/engine/SCons/Script/Main.py
index d80050d..53e5129 100644
--- a/src/engine/SCons/Script/Main.py
+++ b/src/engine/SCons/Script/Main.py
@@ -61,7 +61,6 @@ 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.Script
import SCons.Sig
@@ -70,6 +69,10 @@ import SCons.Util
import SCons.Warnings
#
+
+class SConsPrintHelpException(Exception):
+ pass
+
display = SCons.Util.display
progress_display = SCons.Util.DisplayEngine()
@@ -108,9 +111,9 @@ class BuildTask(SCons.Taskmaster.Task):
def do_failed(self, status=2):
global exit_status
- if ignore_errors:
+ if self.options.ignore_errors:
SCons.Taskmaster.Task.executed(self)
- elif keep_going_on_error:
+ elif self.options.keep_going:
SCons.Taskmaster.Task.fail_continue(self)
exit_status = status
else:
@@ -122,7 +125,7 @@ class BuildTask(SCons.Taskmaster.Task):
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:
+ if not self.options.keep_going:
sys.stderr.write(" Stop.")
sys.stderr.write("\n")
self.do_failed()
@@ -175,7 +178,7 @@ class BuildTask(SCons.Taskmaster.Task):
if e is None:
e = t
s = str(e)
- if t == SCons.Errors.StopError and not keep_going_on_error:
+ if t == SCons.Errors.StopError and not self.options.keep_going:
s = s + ' Stop.'
sys.stderr.write("scons: *** %s\n" % s)
@@ -190,9 +193,9 @@ class BuildTask(SCons.Taskmaster.Task):
def postprocess(self):
if self.top:
t = self.targets[0]
- for tp in tree_printers:
+ for tp in self.options.tree_printers:
tp.display(t)
- if print_includes:
+ if self.options.debug_includes:
tree = t.render_include_tree()
if tree:
print
@@ -202,7 +205,7 @@ class BuildTask(SCons.Taskmaster.Task):
def make_ready(self):
"""Make a task ready for execution"""
SCons.Taskmaster.Task.make_ready(self)
- if self.out_of_date and print_explanations:
+ if self.out_of_date and self.options.debug_explain:
explanation = self.out_of_date[0].explain()
if explanation:
sys.stdout.write("scons: " + explanation)
@@ -316,43 +319,23 @@ class TreePrinter:
# Global variables
-tree_printers = []
-
-keep_going_on_error = 0
-print_explanations = 0
-print_includes = 0
print_objects = 0
print_memoizer = 0
print_stacktrace = 0
print_time = 0
-ignore_errors = 0
sconscript_time = 0
cumulative_command_time = 0
exit_status = 0 # exit status, assume success by default
-repositories = []
num_jobs = None
delayed_warnings = []
-diskcheck_all = SCons.Node.FS.diskcheck_types()
-diskcheck_option_set = None
-
-def diskcheck_convert(value):
- if value is None:
- return []
- if not SCons.Util.is_List(value):
- value = string.split(value, ',')
- result = []
- for v in map(string.lower, value):
- if v == 'all':
- result = diskcheck_all
- elif v == 'none':
- result = []
- elif v in diskcheck_all:
- result.append(v)
- else:
- raise ValueError, v
- return result
+OptionsParser = None
+def AddOption(*args, **kw):
+ if not kw.has_key('default'):
+ kw['default'] = None
+ result = apply(OptionsParser.add_local_option, args, kw)
+ return result
#
class Stats:
def __init__(self):
@@ -482,15 +465,6 @@ def _scons_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>.
@@ -536,12 +510,11 @@ def _setup_warn(arg):
else:
SCons.Warnings.suppressWarningClass(clazz)
-def _SConstruct_exists(dirname=''):
+def _SConstruct_exists(dirname='', repositories=[]):
"""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):
@@ -552,49 +525,44 @@ def _SConstruct_exists(dirname=''):
return sfile
return None
-def _set_globals(options):
- global keep_going_on_error, ignore_errors
- global count_stats
- global print_explanations, print_includes, print_memoizer
- global print_objects, print_stacktrace, print_time
- global tree_printers
- global memory_stats
+def _set_debug_values(options):
+ global print_memoizer, print_objects, print_stacktrace, print_time
- keep_going_on_error = options.keep_going
- try:
- debug_values = options.debug
- if debug_values is None:
- debug_values = []
- except AttributeError:
- pass
- else:
- if "count" in debug_values:
+ debug_values = options.debug
+
+ if "count" in debug_values:
+ # All of the object counts are within "if __debug__:" blocks,
+ # which get stripped when running optimized (with python -O or
+ # from compiled *.pyo files). Provide a warning if __debug__ is
+ # stripped, so it doesn't just look like --debug=count is broken.
+ enable_count = False
+ if __debug__: enable_count = True
+ if enable_count:
count_stats.enable(sys.stdout)
- if "dtree" in debug_values:
- tree_printers.append(TreePrinter(derived=True))
- if "explain" in debug_values:
- print_explanations = 1
- if "findlibs" in debug_values:
- SCons.Scanner.Prog.print_find_libs = "findlibs"
- if "includes" in debug_values:
- print_includes = 1
- if "memoizer" in debug_values:
- print_memoizer = 1
- if "memory" in debug_values:
- memory_stats.enable(sys.stdout)
- if "objects" in debug_values:
- print_objects = 1
- if "presub" in debug_values:
- SCons.Action.print_actions_presub = 1
- if "stacktrace" in debug_values:
- print_stacktrace = 1
- if "stree" in debug_values:
- tree_printers.append(TreePrinter(status=True))
- if "time" in debug_values:
- print_time = 1
- if "tree" in debug_values:
- tree_printers.append(TreePrinter())
- ignore_errors = options.ignore_errors
+ else:
+ msg = "--debug=count is not supported when running SCons\n" + \
+ "\twith the python -O option or optimized (.pyo) modules."
+ SCons.Warnings.warn(SCons.Warnings.NoObjectCountWarning, msg)
+ if "dtree" in debug_values:
+ options.tree_printers.append(TreePrinter(derived=True))
+ options.debug_explain = ("explain" in debug_values)
+ if "findlibs" in debug_values:
+ SCons.Scanner.Prog.print_find_libs = "findlibs"
+ options.debug_includes = ("includes" in debug_values)
+ print_memoizer = ("memoizer" in debug_values)
+ if "memory" in debug_values:
+ memory_stats.enable(sys.stdout)
+ print_objects = ("objects" in debug_values)
+ if "presub" in debug_values:
+ SCons.Action.print_actions_presub = 1
+ if "stacktrace" in debug_values:
+ print_stacktrace = 1
+ if "stree" in debug_values:
+ options.tree_printers.append(TreePrinter(status=True))
+ if "time" in debug_values:
+ print_time = 1
+ if "tree" in debug_values:
+ options.tree_printers.append(TreePrinter())
def _create_path(plist):
path = '.'
@@ -655,410 +623,25 @@ def version_string(label, module):
module.__developer__,
module.__buildsys__)
-class OptParser(OptionParser):
- def __init__(self):
- import __main__
-
- parts = ["SCons by Steven Knight et al.:\n"]
- try:
- parts.append(version_string("script", __main__))
- except KeyboardInterrupt:
- raise
- except:
- # On Windows there is no scons.py, so there is no
- # __main__.__version__, hence there is no script version.
- pass
- parts.append(version_string("engine", SCons))
- 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-debug', action="store",
- dest="cache_debug", metavar="FILE",
- help="Print CacheDir debug info to FILE.")
-
- 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", "memoizer", "memory", "objects",
- "pdb", "presub", "stacktrace", "stree",
- "time", "tree"]
-
- deprecated_debug_options = {
- "nomemoizer" : ' and has no effect',
- }
-
- def opt_debug(option, opt, value, parser, debug_options=debug_options, deprecated_debug_options=deprecated_debug_options):
- if value in debug_options:
- try:
- if parser.values.debug is None:
- parser.values.debug = []
- except AttributeError:
- parser.values.debug = []
- parser.values.debug.append(value)
- elif value in deprecated_debug_options.keys():
- msg = deprecated_debug_options[value]
- w = "The --debug=%s option is deprecated%s." % (value, msg)
- delayed_warnings.append((SCons.Warnings.DeprecatedWarning, w))
- 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_diskcheck(option, opt, value, parser):
- try:
- global diskcheck_option_set
- diskcheck_option_set = diskcheck_convert(value)
- SCons.Node.FS.set_diskcheck(diskcheck_option_set)
- except ValueError, e:
- raise OptionValueError("Warning: `%s' is not a valid diskcheck type" % e)
-
-
- self.add_option('--diskcheck', action="callback", type="string",
- callback=opt_diskcheck, dest='diskcheck',
- metavar="TYPE",
- help="Enable specific on-disk checks.")
-
- 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",
- 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.")
-
- self.add_option('--no-site-dir', action="store_true",
- dest='no_site_dir', default=0,
- help="Don't search or use the usual site_scons dir.")
-
- self.add_option('--profile', action="store",
- dest="profile_file", 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('--site-dir', action="store",
- dest='site_dir', metavar="DIR",
- help="Use DIR instead of the usual site_scons dir.")
-
- self.add_option('--taskmastertrace', action="store",
- dest="taskmastertrace_file", metavar="FILE",
- help="Trace Node evaluation to FILE.")
-
- tree_options = ["all", "derived", "prune", "status"]
-
- def opt_tree(option, opt, value, parser, tree_options=tree_options):
- tp = TreePrinter()
- for o in string.split(value, ','):
- if o == 'all':
- tp.derived = False
- elif o == 'derived':
- tp.derived = True
- elif o == 'prune':
- tp.prune = True
- elif o == 'status':
- tp.status = True
- else:
- raise OptionValueError("Warning: %s is not a valid --tree option" % o)
- tree_printers.append(tp)
-
- self.add_option('--tree', action="callback", type="string",
- callback=opt_tree, nargs=1, metavar="OPTIONS",
- help="Print a dependency tree in various formats: "
- "%s." % string.join(tree_options, ", "))
-
- 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', '--srcdir',
- 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 (and gettable, which for options
- # like 'help' is far more important than being settable).
- self.settable = {
- 'clean' : 0,
- 'diskcheck' : diskcheck_all,
- 'duplicate' : 'hard-soft-copy',
- 'help' : 0,
- 'implicit_cache' : 0,
- 'max_drift' : SCons.Node.FS.default_max_drift,
- 'num_jobs' : 1,
- 'random' : 0,
- }
-
- def get(self, name):
- if not self.settable.has_key(name):
- raise SCons.Errors.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.Errors.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)
- elif name == 'diskcheck':
- try:
- value = diskcheck_convert(value)
- except ValueError, v:
- raise SCons.Errors.UserError, "Not a valid diskcheck value: %s"%v
- if not diskcheck_option_set:
- SCons.Node.FS.set_diskcheck(value)
-
- self.settable[name] = value
-
-
-def _main(args, parser):
+def _main(parser):
global exit_status
+ options = parser.values
+
# Here's where everything really happens.
- # First order of business: set up default warnings and and then
- # handle the user's warning options, so we can warn about anything
- # that happens appropriately.
+ # First order of business: set up default warnings and then
+ # handle the user's warning options, so that we can issue (or
+ # suppress) appropriate warnings about anything that might happen,
+ # as configured by the user.
+
default_warnings = [ SCons.Warnings.CorruptSConsignWarning,
SCons.Warnings.DeprecatedWarning,
SCons.Warnings.DuplicateEnvironmentWarning,
SCons.Warnings.MissingSConscriptWarning,
SCons.Warnings.NoMD5ModuleWarning,
SCons.Warnings.NoMetaclassSupportWarning,
+ SCons.Warnings.NoObjectCountWarning,
SCons.Warnings.NoParallelSupportWarning,
SCons.Warnings.MisleadingKeywordsWarning, ]
for warning in default_warnings:
@@ -1067,9 +650,21 @@ def _main(args, parser):
if options.warn:
_setup_warn(options.warn)
+ # Now that we have the warnings configuration set up, we can actually
+ # issue (or suppress) any warnings about warning-worthy things that
+ # occurred while the command-line options were getting parsed.
+ try:
+ dw = options.delayed_warnings
+ except AttributeError:
+ pass
+ else:
+ delayed_warnings.extend(dw)
for warning_type, message in delayed_warnings:
SCons.Warnings.warn(warning_type, message)
+ if options.diskcheck:
+ SCons.Node.FS.set_diskcheck(options.diskcheck)
+
# Next, we want to create the FS object that represents the outside
# world's file system, as that's central to a lot of initialization.
# To do this, however, we need to be in the directory from which we
@@ -1082,17 +677,11 @@ def _main(args, parser):
except OSError:
sys.stderr.write("Could not change directory to %s\n" % cdir)
- # The SConstruct file may be in a repository, so initialize those
- # before we start the search up our path for one.
- global repositories
- if options.repository:
- repositories.extend(options.repository)
-
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):
+ while script_dir and not _SConstruct_exists(script_dir, options.repository):
script_dir, last_part = os.path.split(script_dir)
if last_part:
target_top = os.path.join(last_part, target_top)
@@ -1107,7 +696,7 @@ def _main(args, parser):
# and make it the build engine default.
fs = SCons.Node.FS.default_fs = SCons.Node.FS.FS()
- for rep in repositories:
+ for rep in options.repository:
fs.Repository(rep)
# Now that we have the FS object, the next order of business is to
@@ -1117,7 +706,7 @@ def _main(args, parser):
if options.file:
scripts.extend(options.file)
if not scripts:
- sfile = _SConstruct_exists()
+ sfile = _SConstruct_exists(repositories=options.repository)
if sfile:
scripts.append(sfile)
@@ -1126,9 +715,7 @@ def _main(args, parser):
# 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()
- exit_status = 0
- return
+ raise SConsPrintHelpException
raise SCons.Errors.UserError, "No SConstruct file found."
if scripts[0] == "-":
@@ -1137,16 +724,11 @@ def _main(args, parser):
d = fs.File(scripts[0]).dir
fs.set_SConstruct_dir(d)
- # Now that we have the FS object and it's intialized, set up (most
- # of) the rest of the options.
- global ssoptions
- ssoptions = SConscriptSettableOptions(options)
-
- _set_globals(options)
+ _set_debug_values(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.noexec:
+ if options.no_exec:
SCons.SConf.dryrun = 1
SCons.Action.execute_actions = None
CleanTask.execute = CleanTask.show
@@ -1185,12 +767,14 @@ def _main(args, parser):
# read and execute have access to them.
targets = []
xmit_args = []
- for a in args:
+ for a in parser.largs:
+ if a[0] == '-':
+ continue
if '=' in a:
xmit_args.append(a)
else:
targets.append(a)
- SCons.Script._Add_Targets(targets)
+ SCons.Script._Add_Targets(targets + parser.rargs)
SCons.Script._Add_Arguments(xmit_args)
sys.stdout = SCons.Util.Unbuffered(sys.stdout)
@@ -1198,6 +782,8 @@ def _main(args, parser):
memory_stats.append('before reading SConscript files:')
count_stats.append(('pre-', 'read'))
+ # And here's where we (finally) read the SConscript files.
+
progress_display("scons: Reading SConscript files ...")
start_time = time.time()
@@ -1215,37 +801,50 @@ def _main(args, parser):
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)
+ progress_display("scons: done reading SConscript files.")
memory_stats.append('after reading SConscript files:')
count_stats.append(('post-', 'read'))
- fs.chdir(fs.Top)
+ SCons.SConf.CreateConfigHBuilder(SCons.Defaults.DefaultEnvironment())
+
+ # Now re-parse the command-line options (any to the left of a '--'
+ # argument, that is) with any user-defined command-line options that
+ # the SConscript files may have added to the parser object. This will
+ # emit the appropriate error message and exit if any unknown option
+ # was specified on the command line.
+
+ parser.preserve_unknown_options = False
+ parser.parse_args(parser.largs, options)
- if ssoptions.get('help'):
+ if options.help:
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)
+ raise SConsPrintHelpException
else:
print help_text
print "Use scons -H for help about command-line options."
exit_status = 0
return
+ # Change directory to the top-level SConstruct directory, then tell
+ # the Node.FS subsystem that we're all done reading the SConscript
+ # files and calling Repository() and BuildDir() and changing
+ # directories and the like, so it can go ahead and start memoizing
+ # the string values of file system nodes.
+
+ fs.chdir(fs.Top)
+
+ SCons.Node.FS.save_strings(1)
+
# 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'))
- fs.set_max_drift(ssoptions.get('max_drift'))
+ SCons.Node.implicit_cache = options.implicit_cache
+ SCons.Node.FS.set_duplicate(options.duplicate)
+ fs.set_max_drift(options.max_drift)
lookup_top = None
if targets or SCons.Script.BUILD_TARGETS != SCons.Script._build_plus_default:
@@ -1324,18 +923,18 @@ def _main(args, parser):
task_class = BuildTask # default action is to build targets
opening_message = "Building targets ..."
closing_message = "done building targets."
- if keep_going_on_error:
+ if options.keep_going:
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'):
+ if options.clean:
task_class = CleanTask
opening_message = "Cleaning targets ..."
closing_message = "done cleaning targets."
- if keep_going_on_error:
+ if options.keep_going:
closing_message = "done cleaning targets (errors occurred during clean)."
else:
failure_message = "cleaning terminated because of errors."
@@ -1367,8 +966,12 @@ def _main(args, parser):
tmtrace = None
taskmaster = SCons.Taskmaster.Taskmaster(nodes, task_class, order, tmtrace)
+ # Let the BuildTask objects get at the options to respond to the
+ # various print_* settings, tree_printer list, etc.
+ BuildTask.options = options
+
global num_jobs
- num_jobs = ssoptions.get('num_jobs')
+ num_jobs = options.num_jobs
jobs = SCons.Job.Jobs(num_jobs, taskmaster)
if num_jobs > 1 and jobs.num_jobs == 1:
msg = "parallel builds are unsupported by this version of Python;\n" + \
@@ -1381,26 +984,26 @@ def _main(args, parser):
try:
jobs.run()
finally:
+ jobs.cleanup()
if exit_status:
progress_display("scons: " + failure_message)
else:
progress_display("scons: " + closing_message)
- if not options.noexec:
+ if not options.no_exec:
SCons.SConsign.write()
memory_stats.append('after building targets:')
count_stats.append(('post-', 'build'))
-def _exec_main():
+def _exec_main(parser, values):
sconsflags = os.environ.get('SCONSFLAGS', '')
all_args = string.split(sconsflags) + sys.argv[1:]
- parser = OptParser()
- global options
- options, args = parser.parse_args(all_args)
+ options, args = parser.parse_args(all_args, values)
+
if type(options.debug) == type([]) and "pdb" in options.debug:
import pdb
- pdb.Pdb().runcall(_main, args, parser)
+ pdb.Pdb().runcall(_main, parser)
elif options.profile_file:
from profile import Profile
@@ -1418,19 +1021,42 @@ def _exec_main():
prof = Profile()
try:
- prof.runcall(_main, args, parser)
+ prof.runcall(_main, parser)
+ except SConsPrintHelpException, e:
+ prof.dump_stats(options.profile_file)
+ raise e
except SystemExit:
pass
prof.dump_stats(options.profile_file)
else:
- _main(args, parser)
+ _main(parser)
def main():
+ global OptionsParser
global exit_status
global first_command_start
+
+ parts = ["SCons by Steven Knight et al.:\n"]
+ try:
+ parts.append(version_string("script", __main__))
+ except KeyboardInterrupt:
+ raise
+ except:
+ # On Windows there is no scons.py, so there is no
+ # __main__.__version__, hence there is no script version.
+ pass
+ parts.append(version_string("engine", SCons))
+ parts.append("__COPYRIGHT__")
+ version = string.join(parts, '')
+
+ import SConsOptions
+ parser = SConsOptions.Parser(version)
+ values = SConsOptions.SConsValues(parser.get_default_values())
+
+ OptionsParser = parser
try:
- _exec_main()
+ _exec_main(parser, values)
except SystemExit, s:
if s:
exit_status = s
@@ -1443,6 +1069,9 @@ def main():
_scons_internal_error()
except SCons.Errors.UserError, e:
_scons_user_error(e)
+ except SConsPrintHelpException:
+ parser.print_help()
+ exit_status = 0
except:
# An exception here is likely a builtin Python exception Python
# code in an SConscript file. Show them precisely what the
@@ -1472,7 +1101,10 @@ def main():
if num_jobs == 1:
ct = cumulative_command_time
else:
- ct = last_command_end - first_command_start
+ if last_command_end is None or first_command_start is None:
+ ct = 0.0
+ else:
+ ct = last_command_end - first_command_start
scons_time = total_time - sconscript_time - ct
print "Total build time: %f seconds"%total_time
print "Total SConscript file execution time: %f seconds"%sconscript_time