summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/man/scons.124
-rw-r--r--src/CHANGES.txt4
-rw-r--r--src/engine/MANIFEST.in1
-rw-r--r--src/engine/SCons/Script/Main.py1144
-rw-r--r--src/engine/SCons/Script/SConscript.py272
-rw-r--r--src/engine/SCons/Script/__init__.py1285
-rw-r--r--src/engine/SCons/Tool/mslink.py10
-rw-r--r--src/engine/SCons/Tool/msvs.py10
-rw-r--r--test/NodeOps.py2
-rw-r--r--test/Script-import.py60
-rw-r--r--test/option--profile.py19
11 files changed, 1514 insertions, 1317 deletions
diff --git a/doc/man/scons.1 b/doc/man/scons.1
index 7b34e8a..9fc5a6a 100644
--- a/doc/man/scons.1
+++ b/doc/man/scons.1
@@ -1257,6 +1257,15 @@ environment that consists of the tools and values that
.B scons
has determined are appropriate for the local system.
+Builder methods that can be called without an explicit
+environment may be called from custom Python modules that you
+import into an SConscript file by adding the following
+to the Python module:
+
+.ES
+from SCons.Script import *
+.EE
+
All builder methods return a list of Nodes
that represent the target or targets that will be built.
A
@@ -2203,6 +2212,14 @@ environment it looks like:
If you can call the functionality in both ways,
then both forms are listed.
+Global functions may be called from custom Python modules that you
+import into an SConscript file by adding the following
+to the Python module:
+
+.ES
+from SCons.Script import *
+.EE
+
Except where otherwise noted,
the same-named
construction environment method
@@ -4280,6 +4297,13 @@ In addition to the global functions and methods,
supports a number of Python variables
that can be used in SConscript files
to affect how you want the build to be performed.
+These variables may be accessed from custom Python modules that you
+import into an SConscript file by adding the following
+to the Python module:
+
+.ES
+from SCons.Script import *
+.EE
'\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
.TP
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index e13fa39..fb98cce 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -170,6 +170,10 @@ RELEASE 0.97 - XXX
duplicate entries from multiple calls. Add a "unique" keyword
argument to allow the old behavior to be specified.
+ - Allow the library modules imported by an SConscript file to get at
+ all of the normally-available global functions and variables by saying
+ "from SCons.Script import *".
+
From Wayne Lee:
- Avoid "maximum recursion limit" errors when removing $(-$) pairs
diff --git a/src/engine/MANIFEST.in b/src/engine/MANIFEST.in
index 133ccad..5c10cae 100644
--- a/src/engine/MANIFEST.in
+++ b/src/engine/MANIFEST.in
@@ -43,6 +43,7 @@ SCons/Scanner/IDL.py
SCons/Scanner/Prog.py
SCons/SConf.py
SCons/SConsign.py
+SCons/Script/Main.py
SCons/Script/SConscript.py
SCons/Script/__init__.py
SCons/Sig/__init__.py
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)
diff --git a/src/engine/SCons/Script/SConscript.py b/src/engine/SCons/Script/SConscript.py
index 30f6933..e30a979 100644
--- a/src/engine/SCons/Script/SConscript.py
+++ b/src/engine/SCons/Script/SConscript.py
@@ -42,7 +42,7 @@ import SCons.Node.FS
import SCons.Options
import SCons.Platform
import SCons.SConf
-import SCons.Script
+import SCons.Script.Main
import SCons.Tool
import SCons.Util
@@ -57,30 +57,7 @@ import UserList
launch_dir = os.path.abspath(os.curdir)
-help_text = None
-
-def HelpFunction(text):
- global help_text
- if help_text is None:
- help_text = text
- else:
- help_text = help_text + text
-
-Arguments = {}
-ArgList = []
-CommandLineTargets = []
-DefaultCalled = None
-DefaultTargets = []
-GlobalDict = {}
-
-class TargetList(UserList.UserList):
- def _do_nothing(self, *args, **kw):
- pass
- def _add_Default(self, list):
- self.extend(list)
- def _clear(self):
- del self[:]
-BuildTargets = TargetList()
+GlobalDict = None
# global exports set by Export():
global_exports = {}
@@ -88,29 +65,21 @@ global_exports = {}
# chdir flag
sconscript_chdir = 1
-# will be set to 1, if we are reading a SConscript
-sconscript_reading = 0
-
-def _scons_add_args(alist):
- for arg in alist:
- a, b = string.split(arg, '=', 1)
- Arguments[a] = b
- ArgList.append((a, b))
-
-def _scons_add_targets(tlist):
- if tlist:
- CommandLineTargets.extend(tlist)
- BuildTargets.extend(tlist)
- BuildTargets._add_Default = BuildTargets._do_nothing
- BuildTargets._clear = BuildTargets._do_nothing
-
def get_calling_namespaces():
"""Return the locals and globals for the function that called
- into this module in the current callstack."""
+ into this module in the current call stack."""
try: 1/0
except ZeroDivisionError: frame = sys.exc_info()[2].tb_frame
- while frame.f_globals.get("__name__") == __name__: frame = frame.f_back
+ # Find the first frame that *isn't* from this file. This means
+ # that we expect all of the SCons frames that implement an Export()
+ # or SConscript() call to be in this file, so that we can identify
+ # the first non-Script.SConscript frame as the user's local calling
+ # environment, and the locals and globals dictionaries from that
+ # frame as the calling namespaces. See the comment below preceding
+ # the DefaultEnvironmentCall block for even more explanation.
+ while frame.f_globals.get("__name__") == __name__:
+ frame = frame.f_back
return frame.f_locals, frame.f_globals
@@ -136,7 +105,6 @@ def compute_exports(exports):
return retval
-
class Frame:
"""A frame on the SConstruct/SConscript call stack"""
def __init__(self, exports, sconscript):
@@ -151,7 +119,7 @@ class Frame:
self.sconscript = SCons.Node.FS.default_fs.File(str(sconscript))
# the SConstruct/SConscript call stack:
-stack = []
+call_stack = []
# For documentation on the methods in this file, see the scons man-page
@@ -160,14 +128,14 @@ def Return(*vars):
try:
for var in vars:
for v in string.split(var):
- retval.append(stack[-1].globals[v])
+ retval.append(call_stack[-1].globals[v])
except KeyError, x:
raise SCons.Errors.UserError, "Return of non-existent variable '%s'"%x
if len(retval) == 1:
- stack[-1].retval = retval[0]
+ call_stack[-1].retval = retval[0]
else:
- stack[-1].retval = tuple(retval)
+ call_stack[-1].retval = tuple(retval)
stack_bottom = '% Stack boTTom %' # hard to define a variable w/this name :)
@@ -180,13 +148,12 @@ def _SConscript(fs, *files, **kw):
# evaluate each SConscript file
results = []
for fn in files:
- stack.append(Frame(exports,fn))
+ call_stack.append(Frame(exports,fn))
old_sys_path = sys.path
try:
- global sconscript_reading
- sconscript_reading = 1
+ SCons.Script.sconscript_reading = 1
if fn == "-":
- exec sys.stdin in stack[-1].globals
+ exec sys.stdin in call_stack[-1].globals
else:
if isinstance(fn, SCons.Node.Node):
f = fn
@@ -246,16 +213,16 @@ def _SConscript(fs, *files, **kw):
# exceptions that occur when processing this
# SConscript can base the printed frames at this
# level and not show SCons internals as well.
- stack[-1].globals.update({stack_bottom:1})
- exec _file_ in stack[-1].globals
+ call_stack[-1].globals.update({stack_bottom:1})
+ exec _file_ in call_stack[-1].globals
else:
SCons.Warnings.warn(SCons.Warnings.MissingSConscriptWarning,
"Ignoring missing SConscript '%s'" % f.path)
finally:
- sconscript_reading = 0
+ SCons.Script.sconscript_reading = 0
sys.path = old_sys_path
- frame = stack.pop()
+ frame = call_stack.pop()
try:
fs.chdir(frame.prev_dir, change_os_dir=sconscript_chdir)
except OSError:
@@ -414,30 +381,13 @@ class SConsEnvironment(SCons.Environment.Base):
#
def Configure(self, *args, **kw):
- if not SCons.Script.SConscript.sconscript_reading:
+ if not SCons.Script.sconscript_reading:
raise SCons.Errors.UserError, "Calling Configure from Builders is not supported."
kw['_depth'] = kw.get('_depth', 0) + 1
return apply(SCons.Environment.Base.Configure, (self,)+args, kw)
def Default(self, *targets):
- global DefaultCalled
- global DefaultTargets
- DefaultCalled = 1
- for t in targets:
- if t is None:
- # Delete the elements from the list in-place, don't
- # reassign an empty list to DefaultTargets, so that the
- # DEFAULT_TARGETS variable will still point to the
- # same object we point to.
- del DefaultTargets[:]
- BuildTargets._clear()
- elif isinstance(t, SCons.Node.Node):
- DefaultTargets.append(t)
- BuildTargets._add_Default([t])
- else:
- nodes = self.arg2nodes(t, self.fs.Entry)
- DefaultTargets.extend(nodes)
- BuildTargets._add_Default(nodes)
+ SCons.Script._Set_Default_Targets(self, targets)
def EnsureSConsVersion(self, major, minor):
"""Exit abnormally if the SCons version is not late enough."""
@@ -470,25 +420,28 @@ class SConsEnvironment(SCons.Environment.Base):
def GetOption(self, name):
name = self.subst(name)
- return SCons.Script.ssoptions.get(name)
+ return SCons.Script.Main.ssoptions.get(name)
def Help(self, text):
text = self.subst(text, raw=1)
- HelpFunction(text)
+ SCons.Script.HelpFunction(text)
def Import(self, *vars):
try:
+ frame = call_stack[-1]
+ globals = frame.globals
+ exports = frame.exports
for var in vars:
var = self.Split(var)
for v in var:
if v == '*':
- stack[-1].globals.update(global_exports)
- stack[-1].globals.update(stack[-1].exports)
+ globals.update(global_exports)
+ globals.update(exports)
else:
- if stack[-1].exports.has_key(v):
- stack[-1].globals[v] = stack[-1].exports[v]
+ if exports.has_key(v):
+ globals[v] = exports[v]
else:
- stack[-1].globals[v] = global_exports[v]
+ globals[v] = global_exports[v]
except KeyError,x:
raise SCons.Errors.UserError, "Import of non-existent variable '%s'"%x
@@ -523,23 +476,34 @@ class SConsEnvironment(SCons.Environment.Base):
def SetOption(self, name, value):
name = self.subst(name)
- SCons.Script.ssoptions.set(name, value)
+ SCons.Script.Main.ssoptions.set(name, value)
#
#
#
SCons.Environment.Environment = SConsEnvironment
-def Options(files=None, args=Arguments):
- return SCons.Options.Options(files, args)
-
def Configure(*args, **kw):
- if not SCons.Script.SConscript.sconscript_reading:
+ if not SCons.Script.sconscript_reading:
raise SCons.Errors.UserError, "Calling Configure from Builders is not supported."
kw['_depth'] = 1
return apply(SCons.SConf.SConf, args, kw)
+# It's very important that the DefaultEnvironmentCall() class stay in this
+# file, with the get_calling_namespaces() function, the compute_exports()
+# function, the Frame class and the SConsEnvironment.Export() method.
+# These things make up the calling stack leading up to the actual global
+# Export() or SConscript() call that the user issued. We want to allow
+# users to export local variables that they define, like so:
+#
+# def func():
+# x = 1
+# Export('x')
#
+# To support this, the get_calling_namespaces() function assumes that
+# the *first* stack frame that's not from this file is the local frame
+# for the Export() or SConscript() call.
+
_DefaultEnvironmentProxy = None
def get_DefaultEnvironmentProxy():
@@ -565,86 +529,6 @@ class DefaultEnvironmentCall:
method = getattr(proxy, self.method_name)
return apply(method, args, kw)
-# The list of global functions to add to the SConscript name space
-# that end up calling corresponding methods or Builders in the
-# DefaultEnvironment().
-GlobalDefaultEnvironmentFunctions = [
- # Methods from the SConsEnvironment class, above.
- 'Default',
- 'EnsurePythonVersion',
- 'EnsureSConsVersion',
- 'Exit',
- 'Export',
- 'GetLaunchDir',
- 'GetOption',
- 'Help',
- 'Import',
- 'SConscript',
- 'SConscriptChdir',
- 'SetOption',
-
- # Methods from the Environment.Base class.
- 'AddPostAction',
- 'AddPreAction',
- 'Alias',
- 'AlwaysBuild',
- 'BuildDir',
- 'CacheDir',
- 'Clean',
- 'Command',
- 'Depends',
- 'Dir',
- 'Execute',
- 'File',
- 'FindFile',
- 'Flatten',
- 'GetBuildPath',
- 'Ignore',
- 'Install',
- 'InstallAs',
- 'Literal',
- 'Local',
- 'ParseDepends',
- 'Precious',
- 'Repository',
- 'SConsignFile',
- 'SideEffect',
- 'SourceCode',
- 'SourceSignatures',
- 'Split',
- 'TargetSignatures',
- 'Value',
-]
-
-GlobalDefaultBuilders = [
- # Supported builders.
- 'CFile',
- 'CXXFile',
- 'DVI',
- 'Jar',
- 'Java',
- 'JavaH',
- 'Library',
- 'M4',
- 'MSVSProject',
- 'Object',
- 'PCH',
- 'PDF',
- 'PostScript',
- 'Program',
- 'RES',
- 'RMIC',
- 'SharedLibrary',
- 'SharedObject',
- 'StaticLibrary',
- 'StaticObject',
- 'Tar',
- 'TypeLibrary',
- 'Zip',
-]
-
-for name in GlobalDefaultEnvironmentFunctions + GlobalDefaultBuilders:
- GlobalDict[name] = DefaultEnvironmentCall(name)
def BuildDefaultGlobals():
"""
@@ -652,45 +536,15 @@ def BuildDefaultGlobals():
SConstruct and SConscript files.
"""
- globals = {
- # Global functions that don't get executed through the
- # default Environment.
- 'Action' : SCons.Action.Action,
- 'BoolOption' : SCons.Options.BoolOption,
- 'Builder' : SCons.Builder.Builder,
- 'Configure' : Configure,
- 'EnumOption' : SCons.Options.EnumOption,
- 'Environment' : SCons.Environment.Environment,
- 'ListOption' : SCons.Options.ListOption,
- 'Options' : Options,
- 'PackageOption' : SCons.Options.PackageOption,
- 'PathOption' : SCons.Options.PathOption,
- 'Platform' : SCons.Platform.Platform,
- 'Return' : Return,
- 'Scanner' : SCons.Scanner.Base,
- 'Tool' : SCons.Tool.Tool,
- 'WhereIs' : SCons.Util.WhereIs,
-
- # Action factories.
- 'Chmod' : SCons.Defaults.Chmod,
- 'Copy' : SCons.Defaults.Copy,
- 'Delete' : SCons.Defaults.Delete,
- 'Mkdir' : SCons.Defaults.Mkdir,
- 'Move' : SCons.Defaults.Move,
- 'Touch' : SCons.Defaults.Touch,
-
- # Other variables we provide.
- 'ARGUMENTS' : Arguments,
- 'ARGLIST' : ArgList,
- 'BUILD_TARGETS' : BuildTargets,
- 'COMMAND_LINE_TARGETS' : CommandLineTargets,
- 'DEFAULT_TARGETS' : DefaultTargets,
- }
-
- # Functions we might still convert to Environment methods.
- globals['CScan'] = SCons.Defaults.CScan
- globals['DefaultEnvironment'] = SCons.Defaults.DefaultEnvironment
-
- globals.update(GlobalDict)
-
- return globals
+ global GlobalDict
+ if GlobalDict is None:
+ GlobalDict = {}
+
+ import SCons.Script
+ d = SCons.Script.__dict__
+ def not_a_module(m, d=d, mtype=type(SCons.Script)):
+ return type(d[m]) != mtype
+ for m in filter(not_a_module, dir(SCons.Script)):
+ GlobalDict[m] = d[m]
+
+ return GlobalDict.copy()
diff --git a/src/engine/SCons/Script/__init__.py b/src/engine/SCons/Script/__init__.py
index 71c2f03..d6d4912 100644
--- a/src/engine/SCons/Script/__init__.py
+++ b/src/engine/SCons/Script/__init__.py
@@ -39,1114 +39,209 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
import time
start_time = time.time()
-import os
-import os.path
-import random
import string
-import sys
-import traceback
+import UserList
-# 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.Action
+import SCons.Builder
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.Script.SConscript
-import SCons.Sig
-import SCons.Taskmaster
+import SCons.Options
+import SCons.Platform
+import SCons.Scanner
+import SCons.SConf
+import SCons.Tool
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()', 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.SConscript._scons_add_args(xmit_args)
- SCons.Script.SConscript._scons_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)
- SCons.Script.SConscript.print_help = 1
-
- 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:
- if SCons.Script.SConscript.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 SCons.Script.SConscript.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.SConscript.DefaultTargets)
- SCons.Script.SConscript.DefaultTargets[:] = d
- target_top = None
- lookup_top = None
-
- if SCons.Script.SConscript.DefaultCalled:
- targets = SCons.Script.SConscript.DefaultTargets
- else:
- if d is None:
- d = [fs.Dir('.')]
- targets = d
+import SCons.Defaults
+import Main
- if not targets:
- sys.stderr.write("scons: *** No targets specified and no Default() targets found. Stop.\n")
- sys.exit(2)
+main = Main.main
- 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
+import SConscript
+_SConscript = SConscript
- nodes = filter(lambda x: x is not None, map(Entry, targets))
+call_stack = _SConscript.call_stack
- 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:
+#
+Action = SCons.Action.Action
+BoolOption = SCons.Options.BoolOption
+Builder = SCons.Builder.Builder
+Configure = _SConscript.Configure
+EnumOption = SCons.Options.EnumOption
+Environment = SCons.Environment.Environment
+ListOption = SCons.Options.ListOption
+PackageOption = SCons.Options.PackageOption
+PathOption = SCons.Options.PathOption
+Platform = SCons.Platform.Platform
+Return = _SConscript.Return
+Scanner = SCons.Scanner.Base
+Tool = SCons.Tool.Tool
+WhereIs = SCons.Util.WhereIs
+
+# Action factories.
+Chmod = SCons.Defaults.Chmod
+Copy = SCons.Defaults.Copy
+Delete = SCons.Defaults.Delete
+Mkdir = SCons.Defaults.Mkdir
+Move = SCons.Defaults.Move
+Touch = SCons.Defaults.Touch
+
+# Functions we might still convert to Environment methods.
+CScan = SCons.Defaults.CScan
+DefaultEnvironment = SCons.Defaults.DefaultEnvironment
+
+# Other variables we provide.
+class TargetList(UserList.UserList):
+ def _do_nothing(self, *args, **kw):
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)
+ def _add_Default(self, list):
+ self.extend(list)
+ def _clear(self):
+ del self[:]
+
+ARGUMENTS = {}
+ARGLIST = []
+BUILD_TARGETS = TargetList()
+COMMAND_LINE_TARGETS = []
+DEFAULT_TARGETS = []
+
+def _Add_Arguments(alist):
+ for arg in alist:
+ a, b = string.split(arg, '=', 1)
+ ARGUMENTS[a] = b
+ ARGLIST.append((a, b))
+
+def _Add_Targets(tlist):
+ if tlist:
+ COMMAND_LINE_TARGETS.extend(tlist)
+ BUILD_TARGETS.extend(tlist)
+ BUILD_TARGETS._add_Default = BUILD_TARGETS._do_nothing
+ BUILD_TARGETS._clear = BUILD_TARGETS._do_nothing
+
+def _Set_Default_Targets_Has_Been_Called(d, fs):
+ return DEFAULT_TARGETS
+
+def _Set_Default_Targets_Has_Not_Been_Called(d, fs):
+ if d is None:
+ d = [fs.Dir('.')]
+ return d
+
+_Get_Default_Targets = _Set_Default_Targets_Has_Not_Been_Called
+
+def _Set_Default_Targets(env, tlist):
+ global DEFAULT_TARGETS
+ global _Get_Default_Targets
+ _Get_Default_Targets = _Set_Default_Targets_Has_Been_Called
+ for t in tlist:
+ if t is None:
+ # Delete the elements from the list in-place, don't
+ # reassign an empty list to DEFAULT_TARGETS, so that the
+ # variables will still point to the same object we point to.
+ del DEFAULT_TARGETS[:]
+ BUILD_TARGETS._clear()
+ elif isinstance(t, SCons.Node.Node):
+ DEFAULT_TARGETS.append(t)
+ BUILD_TARGETS._add_Default([t])
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('*')
+ nodes = env.arg2nodes(t, env.fs.Entry)
+ DEFAULT_TARGETS.extend(nodes)
+ BUILD_TARGETS._add_Default(nodes)
- if print_objects:
- SCons.Debug.listLoggedInstances('*')
- #SCons.Debug.dumpLoggedInstances('*')
+#
+help_text = None
-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)
+def HelpFunction(text):
+ global help_text
+ if SCons.Script.help_text is None:
+ SCons.Script.help_text = text
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)
+ help_text = help_text + text
- if print_time:
- total_time = time.time()-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
+#
+# Will be set to 1 if we are reading a SConscript.
+sconscript_reading = 0
- sys.exit(exit_status)
+#
+def Options(files=None, args=ARGUMENTS):
+ return SCons.Options.Options(files, args)
+
+# The list of global functions to add to the SConscript name space
+# that end up calling corresponding methods or Builders in the
+# DefaultEnvironment().
+GlobalDefaultEnvironmentFunctions = [
+ # Methods from the SConsEnvironment class, above.
+ 'Default',
+ 'EnsurePythonVersion',
+ 'EnsureSConsVersion',
+ 'Exit',
+ 'Export',
+ 'GetLaunchDir',
+ 'GetOption',
+ 'Help',
+ 'Import',
+ 'SConscript',
+ 'SConscriptChdir',
+ 'SetOption',
+
+ # Methods from the Environment.Base class.
+ 'AddPostAction',
+ 'AddPreAction',
+ 'Alias',
+ 'AlwaysBuild',
+ 'BuildDir',
+ 'CacheDir',
+ 'Clean',
+ 'Command',
+ 'Depends',
+ 'Dir',
+ 'Execute',
+ 'File',
+ 'FindFile',
+ 'Flatten',
+ 'GetBuildPath',
+ 'Ignore',
+ 'Install',
+ 'InstallAs',
+ 'Literal',
+ 'Local',
+ 'ParseDepends',
+ 'Precious',
+ 'Repository',
+ 'SConsignFile',
+ 'SideEffect',
+ 'SourceCode',
+ 'SourceSignatures',
+ 'Split',
+ 'TargetSignatures',
+ 'Value',
+]
+
+GlobalDefaultBuilders = [
+ # Supported builders.
+ 'CFile',
+ 'CXXFile',
+ 'DVI',
+ 'Jar',
+ 'Java',
+ 'JavaH',
+ 'Library',
+ 'M4',
+ 'MSVSProject',
+ 'Object',
+ 'PCH',
+ 'PDF',
+ 'PostScript',
+ 'Program',
+ 'RES',
+ 'RMIC',
+ 'SharedLibrary',
+ 'SharedObject',
+ 'StaticLibrary',
+ 'StaticObject',
+ 'Tar',
+ 'TypeLibrary',
+ 'Zip',
+]
+
+for name in GlobalDefaultEnvironmentFunctions + GlobalDefaultBuilders:
+ exec "%s = _SConscript.DefaultEnvironmentCall(%s)" % (name, repr(name))
diff --git a/src/engine/SCons/Tool/mslink.py b/src/engine/SCons/Tool/mslink.py
index 98258c2..559a679 100644
--- a/src/engine/SCons/Tool/mslink.py
+++ b/src/engine/SCons/Tool/mslink.py
@@ -178,6 +178,16 @@ def generate(env):
except (SCons.Util.RegError, SCons.Errors.InternalError):
pass
+ # For most platforms, a loadable module is the same as a shared
+ # library. Platforms which are different can override these, but
+ # setting them the same means that LoadableModule works everywhere.
+ SCons.Tool.createLoadableModuleBuilder(env)
+ env['LDMODULE'] = '$SHLINK'
+ env['LDMODULEPREFIX'] = '$SHLIBPREFIX'
+ env['LDMODULESUFFIX'] = '$SHLIBSUFFIX'
+ env['LDMODULEFLAGS'] = '$SHLINKFLAGS'
+ env['LDMODULECOM'] = '$SHLINKCOM'
+
def exists(env):
if SCons.Tool.msvs.is_msvs_installed():
# there's at least one version of MSVS installed.
diff --git a/src/engine/SCons/Tool/msvs.py b/src/engine/SCons/Tool/msvs.py
index a173c3e..04e09f5 100644
--- a/src/engine/SCons/Tool/msvs.py
+++ b/src/engine/SCons/Tool/msvs.py
@@ -45,7 +45,7 @@ import types
import SCons.Builder
import SCons.Node.FS
import SCons.Platform.win32
-import SCons.Script.SConscript
+import SCons.Script
import SCons.Util
import SCons.Warnings
@@ -1052,10 +1052,12 @@ def projectEmitter(target, source, env):
dspfile = SCons.Node.FS.default_fs.File(target[0]).srcnode()
dswfile = SCons.Node.FS.default_fs.File(SCons.Util.splitext(str(dspfile))[0] + env.subst('$MSVSSOLUTIONSUFFIX'))
+ # XXX Need to find a way to abstract this; the build engine
+ # shouldn't depend on anything in SCons.Script.
+ stack = SCons.Script.call_stack
if not source:
- source = [SCons.Script.SConscript.stack[-1].sconscript.srcnode()]
-
- source[0].attributes.sconstruct = SCons.Script.SConscript.stack[0].sconscript
+ source = [stack[-1].sconscript.srcnode()]
+ source[0].attributes.sconstruct = stack[0].sconscript
bdswpath = SCons.Util.splitext(str(target[0]))[0] + env.subst('$MSVSSOLUTIONSUFFIX')
bdswfile = SCons.Node.FS.default_fs.File(bdswpath)
diff --git a/test/NodeOps.py b/test/NodeOps.py
index ffb8994..9a28c87 100644
--- a/test/NodeOps.py
+++ b/test/NodeOps.py
@@ -152,7 +152,7 @@ def exists_test(node):
node.is_derived()
node.is_pseudo_derived()
import SCons.Script
- if SCons.Script.options.noexec:
+ if SCons.Script.Main.options.noexec:
if (before,via_node,after) != (False,False,False):
import sys
sys.stderr.write('BuildDir exits() populated during dryrun!\n')
diff --git a/test/Script-import.py b/test/Script-import.py
new file mode 100644
index 0000000..90052a5
--- /dev/null
+++ b/test/Script-import.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+#
+# __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__"
+
+"""
+Test that a module that we import into an SConscript file
+can itself easily import the global SCons variables.
+"""
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.write('SConstruct', """\
+import m1
+""")
+
+test.write("m1.py", """\
+from SCons.Script import *
+SConscript('SConscript')
+""")
+
+test.write('SConscript', """\
+import m2
+""")
+
+test.write("m2.py", """\
+from SCons.Script import *
+Command("file.out", "file.in", Copy("$TARGET", "$SOURCE"))
+""")
+
+test.write("file.in", "file.in\n")
+
+test.run(arguments = '.')
+
+test.must_match("file.out", "file.in\n")
+
+test.pass_test()
diff --git a/test/option--profile.py b/test/option--profile.py
index 5a6e473..412b8ce 100644
--- a/test/option--profile.py
+++ b/test/option--profile.py
@@ -43,15 +43,19 @@ test.fail_test(string.find(test.stdout(), 'Copyright') == -1 and
stats = pstats.Stats(scons_prof)
stats.sort_stats('time')
-sys.stdout = StringIO.StringIO()
+try:
+ save_stdout = sys.stdout
+ sys.stdout = StringIO.StringIO()
-stats.strip_dirs().print_stats()
+ stats.strip_dirs().print_stats()
-s = sys.stdout.getvalue()
+ s = sys.stdout.getvalue()
+finally:
+ sys.stdout = save_stdout
-test.fail_test(string.find(s, '__init__.py') == -1)
+test.fail_test(string.find(s, 'Main.py') == -1)
test.fail_test(string.find(s, 'print_version') == -1)
-test.fail_test(string.find(s, 'SCons.Script.main()') == -1)
+test.fail_test(string.find(s, 'SCons.Script.Main.main()') == -1)
test.fail_test(string.find(s, 'option_parser.py') == -1)
@@ -71,11 +75,10 @@ stats.strip_dirs().print_stats()
s = sys.stdout.getvalue()
-test.fail_test(string.find(s, '__init__.py') == -1)
+test.fail_test(string.find(s, 'Main.py') == -1)
test.fail_test(string.find(s, 'print_version') == -1)
-test.fail_test(string.find(s, 'SCons.Script.main()') == -1)
+test.fail_test(string.find(s, 'SCons.Script.Main.main()') == -1)
test.fail_test(string.find(s, 'option_parser.py') == -1)
test.pass_test()
-