Commits

Anonymous committed f9b5a3a

Create the Script directory

Comments (0)

Files changed (13)

 .B -h 
 argument is given to
 .BR scons .
-This function can be called multiple times to print multiple help messages.
+.B scons
+will exit after printing out the help text.
 
 .TP
 .RI BuildDir( build_dir ", " src_dir )
 /usr/lib/scons/SCons/Scanner/Prog.pyc
 /usr/lib/scons/SCons/Scanner/__init__.py
 /usr/lib/scons/SCons/Scanner/__init__.pyc
-/usr/lib/scons/SCons/Script.py
-/usr/lib/scons/SCons/Script.pyc
+/usr/lib/scons/SCons/Script/__init__.py
+/usr/lib/scons/SCons/Script/__init__.pyc
+/usr/lib/scons/SCons/Script/SConscript.py
+/usr/lib/scons/SCons/Script/SConscript.pyc
 /usr/lib/scons/SCons/Sig/MD5.py
 /usr/lib/scons/SCons/Sig/MD5.pyc
 /usr/lib/scons/SCons/Sig/TimeStamp.py

src/engine/MANIFEST.in

 SCons/Scanner/__init__.py
 SCons/Scanner/C.py
 SCons/Scanner/Prog.py
-SCons/SConscript.py
-SCons/Script.py
+SCons/Script/SConscript.py
+SCons/Script/__init__.py
 SCons/Sig/__init__.py
 SCons/Sig/MD5.py
 SCons/Sig/TimeStamp.py

src/engine/SCons/SConscript.py

-"""engine.SCons.SConscript
-
-This module defines the Python API provided to SConscript and SConstruct 
-files.
-
-"""
-
-#
-# Copyright (c) 2001 Steven Knight
-#
-# 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__ = "src/engine/SCons/SConscript.py __REVISION__ __DATE__ __DEVELOPER__"
-
-import SCons.Errors
-import SCons.Builder
-import SCons.Defaults
-import SCons.Node
-import SCons.Node.FS
-import SCons.Environment
-import string
-import sys
-
-default_targets = []
-help_option = None
-
-# global exports set by Export():
-global_exports = {}
-
-class Frame:
-    """A frame on the SConstruct/SConscript call stack"""
-    def __init__(self, exports):
-        self.globals = BuildDefaultGlobals()
-        self.retval = None 
-        self.prev_dir = SCons.Node.FS.default_fs.getcwd()
-        self.exports = {} # exports from the calling SConscript
-
-        try:
-            if type(exports) == type([]):
-                for export in exports:
-                    self.exports[export] = stack[-1].globals[export]
-            else:
-                for export in string.split(exports):
-                    self.exports[export] = stack[-1].globals[export]
-        except KeyError, x:
-            raise SCons.Errors.UserError, "Export of non-existant variable '%s'"%x
-
-        
-# the SConstruct/SConscript call stack:
-stack = []
-
-# For documentation on the methods in this file, see the scons man-page
-
-def Return(*vars):
-    retval = []
-    try:
-        for var in vars:
-            for v in string.split(var):
-                retval.append(stack[-1].globals[v])
-    except KeyError, x:
-        raise SCons.Errors.UserError, "Return of non-existant variable '%s'"%x
-        
-    if len(retval) == 1:
-        stack[-1].retval = retval[0]
-    else:
-        stack[-1].retval = tuple(retval)
-
-def SConscript(script, exports=[]):
-    retval = ()
-
-    # push:
-    stack.append(Frame(exports))
-
-    # call:
-    if script == "-":
-        exec sys.stdin in stack[-1].globals
-    else:
-        f = SCons.Node.FS.default_fs.File(script)
-        if f.exists():
-            file = open(str(f), "r")
-            SCons.Node.FS.default_fs.chdir(f.dir)
-            exec file in stack[-1].globals
-        else:
-            sys.stderr.write("Ignoring missing SConscript '%s'\n" % f.path)
-    
-
-    # pop:
-    frame = stack.pop()
-    SCons.Node.FS.default_fs.chdir(frame.prev_dir)
-    
-    return frame.retval
-    
-def Default(*targets):
-    for t in targets:
-        if isinstance(t, SCons.Node.Node):
-            default_targets.append(t)
-        else:
-            for s in string.split(t):
-                default_targets.append(s)
-
-def Help(text):
-    global help_option
-    if help_option == 'h':
-        print text
-        print "Use scons -H for help about command-line options."
-        sys.exit(0)
-
-def BuildDir(build_dir, src_dir):
-    SCons.Node.FS.default_fs.BuildDir(build_dir, src_dir)
-
-def GetBuildPath(files):
-    nodes = SCons.Util.scons_str2nodes(files,
-                                       SCons.Node.FS.default_fs.Entry)
-    ret = map(str, nodes)
-    if len(ret) == 1:
-        return ret[0]
-    return ret
-
-def Export(*vars):
-    try:
-        for var in vars:
-            for v in string.split(var):
-                global_exports[v] = stack[-1].globals[v]
-    except KeyError, x:
-        raise SCons.Errors.UserError, "Export of non-existant variable '%s'"%x
-
-def Import(*vars):
-    try:
-        for var in vars:
-            for v in string.split(var):
-                if stack[-1].exports.has_key(v):
-                    stack[-1].globals[v] = stack[-1].exports[v]
-                else:
-                    stack[-1].globals[v] = global_exports[v]
-    except KeyError,x:
-        raise SCons.Errors.UserError, "Import of non-existant variable '%s'"%x
-
-def BuildDefaultGlobals():
-    """
-    Create a dictionary containing all the default globals for 
-    SConscruct and SConscript files.
-    """
-
-    globals = {}
-    globals['Builder'] = SCons.Builder.Builder
-    globals['Environment'] = SCons.Environment.Environment
-    globals['Object'] = SCons.Defaults.Object
-    globals['Program'] = SCons.Defaults.Program
-    globals['Library'] = SCons.Defaults.Library
-    globals['CScan'] = SCons.Defaults.CScan
-    globals['SConscript'] = SConscript
-    globals['Default'] = Default
-    globals['Help'] = Help
-    globals['BuildDir'] = BuildDir
-    globals['GetBuildPath'] = GetBuildPath
-    globals['Export'] = Export
-    globals['Import'] = Import
-    globals['Return'] = Return
-    return globals

src/engine/SCons/SConscriptTests.py

-#
-# Copyright (c) 2001 Steven Knight
-#
-# 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__ = "src/engine/SCons/SConscriptTests.py __REVISION__ __DATE__ __DEVELOPER__"
-
-import SCons.SConscript
-
-# all of the SConscript.py tests are in test/SConscript.py 

src/engine/SCons/Script.py

-"""engine.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 (c) 2001 Steven Knight
-#
-# 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 getopt
-import os
-import os.path
-import string
-import sys
-import traceback
-import copy
-
-# 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-__VERSION__')] + sys.path[1:]
-
-import SCons.Node
-import SCons.Node.FS
-import SCons.Job
-from SCons.Errors import *
-import SCons.Sig
-import SCons.Sig.MD5
-from SCons.Taskmaster import Taskmaster
-import SCons.Builder
-import SCons.SConscript
-
-
-#
-# Task control.
-#
-class BuildTask(SCons.Taskmaster.Task):
-    """An SCons build task."""
-    def execute(self):
-        if self.target.get_state() == SCons.Node.up_to_date:
-            if self.top:
-                print 'scons: "%s" is up to date.' % str(self.target)
-        else:
-            try:
-                self.target.build()
-            except BuildError, e:
-                sys.stderr.write("scons: *** [%s] Error %s\n" % (e.node, str(e.stat)))
-                raise
-
-    def failed(self):
-        global ignore_errors
-        if ignore_errors:
-            SCons.Taskmaster.Task.executed(self)
-        elif keep_going_on_error:
-            SCons.Taskmaster.Task.fail_continue(self)
-        else:
-            SCons.Taskmaster.Task.fail_stop(self)
-
-class CleanTask(SCons.Taskmaster.Task):
-    """An SCons clean task."""
-    def execute(self):
-        if self.target.builder:
-	    os.unlink(self.target.path)
-	    print "Removed " + self.target.path
-
-
-# Global variables
-
-include_dirs = []
-num_jobs = 1
-scripts = []
-task_class = BuildTask	# default action is to build targets
-current_func = None
-calc = None
-ignore_errors = 0
-keep_going_on_error = 0
-
-
-# utility functions
-
-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')
-
-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.
-    """
-    etype, value, tb = sys.exc_info()
-    while tb.tb_next is not None:
-        tb = tb.tb_next
-    lineno = traceback.tb_lineno(tb)
-    filename = tb.tb_frame.f_code.co_filename
-    routine = tb.tb_frame.f_code.co_name
-    sys.stderr.write("\nSCons error: %s\n" % value)
-    sys.stderr.write('File "%s", line %d, in %s\n' % (filename, lineno, routine))
-
-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.
-    """
-    etype, value, tb = sys.exc_info()
-    while tb.tb_next is not None:
-        tb = tb.tb_next
-    lineno = traceback.tb_lineno(tb)
-    filename = tb.tb_frame.f_code.co_filename
-    routine = tb.tb_frame.f_code.co_name
-    sys.stderr.write("\nSCons warning: %s\n" % e)
-    sys.stderr.write('File "%s", line %d, in %s\n' % (filename, lineno, routine))
-
-def _scons_other_errors():
-    """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 'other errors'
-    traceback.print_exc()
-
-
-
-#
-# After options are initialized, the following variables are
-# filled in:
-#
-option_list = []	# list of Option objects
-short_opts = ""		# string of short (single-character) options
-long_opts = []		# array of long (--) options
-opt_func = {}		# mapping of option strings to functions
-
-def options_init():
-    """Initialize command-line options processing.
-    
-    This is in a subroutine mainly so we can easily single-step over
-    it in the debugger.
-    """
-
-    class Option:
-	"""Class for command-line option information.
-
-	This exists to provide a central location for everything
-	describing a command-line option, so that we can change
-	options without having to update the code to handle the
-	option in one place, the -h help message in another place,
-	etc.  There are no methods here, only attributes.
-
-	You can initialize an Option with the following:
-
-	func	The function that will be called when this
-		option is processed on the command line.
-		Calling sequence is:
-
-			func(opt, arg)
-
-		If there is no func, then this Option probably
-		stores an optstring to be printed.
-
-	helpline
-		The string to be printed in -h output.  If no
-		helpline is specified but a help string is
-		specified (the usual case), a helpline will be
-		constructed automatically from the short, long,
-		arg, and help attributes.  (In practice, then,
-		setting helpline without setting func allows you
-		to print arbitrary lines of text in the -h
-		output.)
-
-	short	The string for short, single-hyphen
-		command-line options.
-		Do not include the hyphen:
-
-			'a' for -a, 'xy' for -x and -y, etc.
-
-	long	An array of strings for long, double-hyphen
-		command-line options.  Do not include
-		the hyphens:
-
-			['my-option', 'verbose']
-
-	arg	If this option takes an argument, this string
-		specifies how you want it to appear in the
-		-h output ('DIRECTORY', 'FILE', etc.).
-
-	help	The help string that will be printed for
-		this option in the -h output.  Must be
-		49 characters or fewer.
-
-	future	If non-zero, this indicates that this feature
-		will be supported in a future release, not
-		the currently planned one.  SCons will
-		recognize the option, but it won't show up
-		in the -h output.
-
-	The following attribute is derived from the supplied attributes:
-
-	optstring
-		A string, with hyphens, describing the flags
-		for this option, as constructed from the
-		specified short, long and arg attributes.
-
-	All Option objects are stored in the global option_list list,
-	in the order in which they're created.  This is the list
-	that's used to generate -h output, so the order in which the
-	objects are created is the order in which they're printed.
-
-	The upshot is that specifying a command-line option and having
-	everything work correctly is a matter of defining a function to
-	process its command-line argument (set the right flag, update
-	the right value), and then creating an appropriate Option object
-	at the correct point in the code below.
-	"""
-
-	def __init__(self, func = None, helpline = None,
-		 short = None, long = None, arg = None,
-		 help = None, future = None):
-	    self.func = func
-	    self.short = short
-	    self.long = long
-	    self.arg = arg
-	    self.help = help
-	    opts = []
-	    if self.short:
-		for c in self.short:
-		    if arg:
-			c = c + " " + arg
-		    opts = opts + ['-' + c]
-	    if self.long:
-		l = self.long
-		if arg:
-		    l = map(lambda x,a=arg: x + "=" + a, self.long)
-		opts = opts + map(lambda x: '--' + x, l)
-	    self.optstring = string.join(opts, ', ')
-	    if helpline:
-		self.helpline = helpline
-	    elif help and not future:
-		if len(self.optstring) <= 26:
-		    sep = " " * (28 - len(self.optstring))
-		else:
-		    sep = self.helpstring = "\n" + " " * 30
-		self.helpline = "  " + self.optstring + sep + self.help
-	    else:
-		self.helpline = None
-	    global option_list
-	    option_list.append(self)
-
-    # Generic routine for to-be-written options, used by multiple
-    # options below.
-
-    def opt_not_yet(opt, arg):
-        sys.stderr.write("Warning:  the %s option is not yet implemented\n"
-			  % opt)
-
-    # In the following instantiations, the help string should be no
-    # longer than 49 characters.  Use the following as a guide:
-    #	help = "1234567890123456789012345678901234567890123456789"
-
-    def opt_ignore(opt, arg):
-	sys.stderr.write("Warning:  ignoring %s option\n" % opt)
-
-    Option(func = opt_ignore,
-	short = 'bmSt', long = ['no-keep-going', 'stop', 'touch'],
-	help = "Ignored for compatibility.")
-
-    def opt_c(opt, arg):
-        global task_class, calc
-        task_class = CleanTask
-        class CleanCalculator:
-            def bsig(self, node):
-                return None
-            def csig(self, node):
-                return None
-            def current(self, node, sig):
-                return 0
-            def write(self):
-                pass
-        calc = CleanCalculator()
-
-    Option(func = opt_c,
-	short = 'c', long = ['clean', 'remove'],
-	help = "Remove specified targets and dependencies.")
-
-    Option(func = opt_not_yet, future = 1,
-	long = ['cache-disable', 'no-cache'],
-	help = "Do not retrieve built targets from Cache.")
-
-    Option(func = opt_not_yet, future = 1,
-	long = ['cache-force', 'cache-populate'],
-	help = "Copy already-built targets into the Cache.")
-
-    Option(func = opt_not_yet, future = 1,
-	long = ['cache-show'],
-	help = "Print what would have built Cached targets.")
-
-    def opt_C(opt, arg):
-	try:
-	    os.chdir(arg)
-            SCons.Node.FS.default_fs.set_toplevel_dir(os.getcwd())
-	except:
-	    sys.stderr.write("Could not change directory to 'arg'\n")
-
-    Option(func = opt_C,
-	short = 'C', long = ['directory'], arg = 'DIRECTORY',
-	help = "Change to DIRECTORY before doing anything.")
-
-    Option(func = opt_not_yet,
-	short = 'd',
-	help = "Print file dependency information.")
-
-    Option(func = opt_not_yet, future = 1,
-	long = ['debug'], arg = 'FLAGS',
-	help = "Print various types of debugging information.")
-
-    Option(func = opt_not_yet, future = 1,
-	short = 'e', long = ['environment-overrides'],
-	help = "Environment variables override makefiles.")
-
-    def opt_f(opt, arg):
-	global scripts
-        scripts.append(arg)
-
-    Option(func = opt_f,
-	short = 'f', long = ['file', 'makefile', 'sconstruct'], arg = 'FILE',
-	help = "Read FILE as the top-level SConstruct file.")
-
-    def opt_help(opt, arg):
-        SCons.SConscript.help_option = 'h'
-
-    Option(func = opt_help,
-	short = 'h', long = ['help'],
-	help = "Print defined help message, or this one.")
-
-    def opt_help_options(opt, arg):
-        SCons.SConscript.help_option = 'H'
-
-    Option(func = opt_help_options,
-	short = 'H', long = ['help-options'],
-	help = "Print this message and exit.")
-
-    def opt_i(opt, arg):
-        global ignore_errors
-        ignore_errors = 1
-
-    Option(func = opt_i,
-	short = 'i', long = ['ignore-errors'],
-	help = "Ignore errors from build actions.")
-
-    def opt_I(opt, arg):
-	global include_dirs
-	include_dirs = include_dirs + [arg]
-
-    Option(func = opt_I,
-	short = 'I', long = ['include-dir'], arg = 'DIRECTORY',
-	help = "Search DIRECTORY for imported Python modules.")
-
-    def opt_j(opt, arg):
-	global num_jobs
-	try:
-            num_jobs = int(arg)
-	except:
-            print UsageString()
-            sys.exit(1)
-
-	if num_jobs <= 0:
-            print UsageString()
-            sys.exit(1)
-
-    Option(func = opt_j,
-	short = 'j', long = ['jobs'], arg = 'N',
-	help = "Allow N jobs at once.")
-
-    def opt_k(opt, arg):
-        global keep_going_on_error
-        keep_going_on_error = 1
-
-    Option(func = opt_k,
-	short = 'k', long = ['keep-going'],
-	help = "Keep going when a target can't be made.")
-
-    Option(func = opt_not_yet, future = 1,
-	short = 'l', long = ['load-average', 'max-load'], arg = 'N',
-	help = "Don't start multiple jobs unless load is below N.")
-
-    Option(func = opt_not_yet, future = 1,
-	long = ['list-derived'],
-	help = "Don't build; list files that would be built.")
-
-    Option(func = opt_not_yet, future = 1,
-	long = ['list-actions'],
-	help = "Don't build; list files and build actions.")
-
-    Option(func = opt_not_yet, future = 1,
-	long = ['list-where'],
-	help = "Don't build; list files and where defined.")
-
-    def opt_n(opt, arg):
-	SCons.Builder.execute_actions = None
-
-    Option(func = opt_n,
-	short = 'n', long = ['no-exec', 'just-print', 'dry-run', 'recon'],
-	help = "Don't build; just print commands.")
-
-    Option(func = opt_not_yet, future = 1,
-	short = 'o', long = ['old-file', 'assume-old'], arg = 'FILE',
-	help = "Consider FILE to be old; don't rebuild it.")
-
-    Option(func = opt_not_yet, future = 1,
-	long = ['override'], arg = 'FILE',
-	help = "Override variables as specified in FILE.")
-
-    Option(func = opt_not_yet, future = 1,
-	short = 'p',
-	help = "Print internal environments/objects.")
-
-    Option(func = opt_not_yet, future = 1,
-	short = 'q', long = ['question'],
-	help = "Don't build; exit status says if up to date.")
-
-    Option(func = opt_not_yet, future = 1,
-	short = 'rR', long = ['no-builtin-rules', 'no-builtin-variables'],
-	help = "Clear default environments and variables.")
-
-    Option(func = opt_not_yet, future = 1,
-	long = ['random'],
-	help = "Build dependencies in random order.")
-
-    def opt_s(opt, arg):
-	SCons.Builder.print_actions = None
-
-    Option(func = opt_s,
-	short = 's', long = ['silent', 'quiet'],
-	help = "Don't print commands.")
-
-    Option(func = opt_not_yet, future = 1,
-	short = 'u', long = ['up', 'search-up'],
-	help = "Search up directory tree for SConstruct.")
-
-    def option_v(opt, arg):
-        import SCons
-	print "SCons by Steven Knight et al.:"
-	print "\tscript version __VERSION__"
-	print "\tbuild engine version %s" % SCons.__version__
-	print "Copyright 2001 Steven Knight"
-	sys.exit(0)
-
-    Option(func = option_v,
-	short = 'v', long = ['version'],
-	help = "Print the SCons version number and exit.")
-
-    Option(func = opt_not_yet, future = 1,
-	short = 'w', long = ['print-directory'],
-	help = "Print the current directory.")
-
-    Option(func = opt_not_yet, future = 1,
-	long = ['no-print-directory'],
-	help = "Turn off -w, even if it was turned on implicitly.")
-
-    Option(func = opt_not_yet, future = 1,
-	long = ['write-filenames'], arg = 'FILE',
-	help = "Write all filenames examined into FILE.")
-
-    Option(func = opt_not_yet, future = 1,
-	short = 'W', long = ['what-if', 'new-file', 'assume-new'], arg = 'FILE',
-	help = "Consider FILE to be changed.")
-
-    Option(func = opt_not_yet, future = 1,
-	long = ['warn-undefined-variables'],
-	help = "Warn when an undefined variable is referenced.")
-
-    Option(func = opt_not_yet, future = 1,
-	short = 'Y', long = ['repository'], arg = 'REPOSITORY',
-	help = "Search REPOSITORY for source and target files.")
-
-    global short_opts
-    global long_opts
-    global opt_func
-    for o in option_list:
-	if o.short:
-	    if o.func:
-		for c in o.short:
-		    opt_func['-' + c] = o.func
-	    short_opts = short_opts + o.short
-	    if o.arg:
-		short_opts = short_opts + ":"
-	if o.long:
-	    if o.func:
-		for l in o.long:
-		    opt_func['--' + l] = o.func
-	    if o.arg:
-		long_opts = long_opts + map(lambda a: a + "=", o.long)
-	    else:
-		long_opts = long_opts + o.long
-
-options_init()
-
-
-
-def UsageString():
-    help_opts = filter(lambda x: x.helpline, option_list)
-    s = "Usage: scons [OPTION] [TARGET] ...\n" + "Options:\n" + \
-	string.join(map(lambda x: x.helpline, help_opts), "\n") + "\n"
-    return s
-
-
-
-def _main():
-    global scripts, num_jobs, task_class, calc
-
-    targets = []
-
-    # It looks like 2.0 changed the name of the exception class
-    # raised by getopt.
-    try:
-	getopt_err = getopt.GetoptError
-    except:
-	getopt_err = getopt.error
-
-    try:
-	cmd_opts, t = getopt.getopt(string.split(os.environ['SCONSFLAGS']),
-					  short_opts, long_opts)
-    except KeyError:
-	# It's all right if there's no SCONSFLAGS environment variable.
-	pass
-    except getopt_err, x:
-	_scons_user_warning("SCONSFLAGS " + str(x))
-    else:
-	for opt, arg in cmd_opts:
-	    opt_func[opt](opt, arg)
-
-    try:
-	cmd_opts, targets = getopt.getopt(sys.argv[1:], short_opts, long_opts)
-    except getopt_err, x:
-	_scons_user_error(x)
-    else:
-	for opt, arg in cmd_opts:
-	    opt_func[opt](opt, arg)
-
-    if not scripts:
-        for file in ['SConstruct', 'Sconstruct', 'sconstruct']:
-            if os.path.isfile(file):
-                scripts.append(file)
-                break
-
-    if SCons.SConscript.help_option == 'H':
-	print UsageString()
-	sys.exit(0)
-
-    if not scripts:
-        if SCons.SConscript.help_option == 'h':
-            # 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.
-	    print UsageString()
-	    sys.exit(0)
-	else:
-	    raise UserError, "No SConstruct file found."
-
-    sys.path = include_dirs + sys.path
-
-    for script in scripts:
-        SCons.SConscript.SConscript(script)
-
-    SCons.Node.FS.default_fs.chdir(SCons.Node.FS.default_fs.Top)
-
-    if SCons.SConscript.help_option == 'h':
-	# They specified -h, but there was no Help() inside the
-	# SConscript files.  Give them the options usage.
-	print UsageString()
-	sys.exit(0)
-
-    if not targets:
-        targets = SCons.SConscript.default_targets
-	
-    def Entry(x):
-	if isinstance(x, SCons.Node.Node):
-	    return x
-	else:
-	    return SCons.Node.FS.default_fs.Entry(x)
-	
-    nodes = map(Entry, targets)
-
-    if not calc:
-        calc = SCons.Sig.Calculator(SCons.Sig.MD5)
-
-    taskmaster = SCons.Taskmaster.Taskmaster(nodes, task_class, calc)
-
-    jobs = SCons.Job.Jobs(num_jobs, taskmaster)
-    jobs.start()
-    jobs.wait()
-
-    SCons.Sig.write()
-
-def main():
-    try:
-	_main()
-    except SystemExit:
-        pass
-    except KeyboardInterrupt:
-        print "Build interrupted."
-    except SyntaxError, e:
-        _scons_syntax_error(e)
-    except UserError, e:
-        _scons_user_error(e)
-    except:
-        _scons_other_errors()
-
-

src/engine/SCons/Script/SConscript.py

+"""engine.SCons.SConscript
+
+This module defines the Python API provided to SConscript and SConstruct 
+files.
+
+"""
+
+#
+# Copyright (c) 2001 Steven Knight
+#
+# 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__ = "src/engine/SCons/SConscript.py __REVISION__ __DATE__ __DEVELOPER__"
+
+import SCons.Errors
+import SCons.Builder
+import SCons.Defaults
+import SCons.Node
+import SCons.Node.FS
+import SCons.Environment
+import string
+import sys
+
+default_targets = []
+print_help = 0
+
+# global exports set by Export():
+global_exports = {}
+
+class Frame:
+    """A frame on the SConstruct/SConscript call stack"""
+    def __init__(self, exports):
+        self.globals = BuildDefaultGlobals()
+        self.retval = None 
+        self.prev_dir = SCons.Node.FS.default_fs.getcwd()
+        self.exports = {} # exports from the calling SConscript
+
+        try:
+            if type(exports) == type([]):
+                for export in exports:
+                    self.exports[export] = stack[-1].globals[export]
+            else:
+                for export in string.split(exports):
+                    self.exports[export] = stack[-1].globals[export]
+        except KeyError, x:
+            raise SCons.Errors.UserError, "Export of non-existant variable '%s'"%x
+
+        
+# the SConstruct/SConscript call stack:
+stack = []
+
+# For documentation on the methods in this file, see the scons man-page
+
+def Return(*vars):
+    retval = []
+    try:
+        for var in vars:
+            for v in string.split(var):
+                retval.append(stack[-1].globals[v])
+    except KeyError, x:
+        raise SCons.Errors.UserError, "Return of non-existant variable '%s'"%x
+        
+    if len(retval) == 1:
+        stack[-1].retval = retval[0]
+    else:
+        stack[-1].retval = tuple(retval)
+
+def SConscript(script, exports=[]):
+    retval = ()
+
+    # push:
+    stack.append(Frame(exports))
+
+    # call:
+    if script == "-":
+        exec sys.stdin in stack[-1].globals
+    else:
+        f = SCons.Node.FS.default_fs.File(script)
+        if f.exists():
+            file = open(str(f), "r")
+            SCons.Node.FS.default_fs.chdir(f.dir)
+            exec file in stack[-1].globals
+        else:
+            sys.stderr.write("Ignoring missing SConscript '%s'\n" % f.path)
+    
+
+    # pop:
+    frame = stack.pop()
+    SCons.Node.FS.default_fs.chdir(frame.prev_dir)
+    
+    return frame.retval
+    
+def Default(*targets):
+    for t in targets:
+        if isinstance(t, SCons.Node.Node):
+            default_targets.append(t)
+        else:
+            for s in string.split(t):
+                default_targets.append(s)
+
+def Help(text):
+    if print_help:
+        print text
+        print "Use scons -H for help about command-line options."
+        sys.exit(0)
+
+def BuildDir(build_dir, src_dir):
+    SCons.Node.FS.default_fs.BuildDir(build_dir, src_dir)
+
+def GetBuildPath(files):
+    nodes = SCons.Util.scons_str2nodes(files,
+                                       SCons.Node.FS.default_fs.Entry)
+    ret = map(str, nodes)
+    if len(ret) == 1:
+        return ret[0]
+    return ret
+
+def Export(*vars):
+    try:
+        for var in vars:
+            for v in string.split(var):
+                global_exports[v] = stack[-1].globals[v]
+    except KeyError, x:
+        raise SCons.Errors.UserError, "Export of non-existant variable '%s'"%x
+
+def Import(*vars):
+    try:
+        for var in vars:
+            for v in string.split(var):
+                if stack[-1].exports.has_key(v):
+                    stack[-1].globals[v] = stack[-1].exports[v]
+                else:
+                    stack[-1].globals[v] = global_exports[v]
+    except KeyError,x:
+        raise SCons.Errors.UserError, "Import of non-existant variable '%s'"%x
+
+def BuildDefaultGlobals():
+    """
+    Create a dictionary containing all the default globals for 
+    SConscruct and SConscript files.
+    """
+
+    globals = {}
+    globals['Builder'] = SCons.Builder.Builder
+    globals['Environment'] = SCons.Environment.Environment
+    globals['Object'] = SCons.Defaults.Object
+    globals['Program'] = SCons.Defaults.Program
+    globals['Library'] = SCons.Defaults.Library
+    globals['CScan'] = SCons.Defaults.CScan
+    globals['SConscript'] = SConscript
+    globals['Default'] = Default
+    globals['Help'] = Help
+    globals['BuildDir'] = BuildDir
+    globals['GetBuildPath'] = GetBuildPath
+    globals['Export'] = Export
+    globals['Import'] = Import
+    globals['Return'] = Return
+    return globals

src/engine/SCons/Script/SConscriptTests.py

+#
+# Copyright (c) 2001 Steven Knight
+#
+# 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__ = "src/engine/SCons/SConscriptTests.py __REVISION__ __DATE__ __DEVELOPER__"
+
+import SCons.Script.SConscript
+
+# all of the SConscript.py tests are in test/SConscript.py 

src/engine/SCons/Script/__init__.py

+"""engine.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 (c) 2001 Steven Knight
+#
+# 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 getopt
+import os
+import os.path
+import string
+import sys
+import traceback
+import copy
+
+# 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-__VERSION__')] + sys.path[1:]
+
+import SCons.Node
+import SCons.Node.FS
+import SCons.Job
+from SCons.Errors import *
+import SCons.Sig
+import SCons.Sig.MD5
+from SCons.Taskmaster import Taskmaster
+import SCons.Builder
+import SCons.Script.SConscript
+
+
+#
+# Task control.
+#
+class BuildTask(SCons.Taskmaster.Task):
+    """An SCons build task."""
+    def execute(self):
+        if self.target.get_state() == SCons.Node.up_to_date:
+            if self.top:
+                print 'scons: "%s" is up to date.' % str(self.target)
+        else:
+            try:
+                self.target.build()
+            except BuildError, e:
+                sys.stderr.write("scons: *** [%s] Error %s\n" % (e.node, str(e.stat)))
+                raise
+
+    def failed(self):
+        global ignore_errors
+        if ignore_errors:
+            SCons.Taskmaster.Task.executed(self)
+        elif keep_going_on_error:
+            SCons.Taskmaster.Task.fail_continue(self)
+        else:
+            SCons.Taskmaster.Task.fail_stop(self)
+
+class CleanTask(SCons.Taskmaster.Task):
+    """An SCons clean task."""
+    def execute(self):
+        if self.target.builder:
+	    os.unlink(self.target.path)
+	    print "Removed " + self.target.path
+
+
+# Global variables
+
+include_dirs = []
+num_jobs = 1
+scripts = []
+task_class = BuildTask	# default action is to build targets
+current_func = None
+calc = None
+ignore_errors = 0
+keep_going_on_error = 0
+help_option = None
+
+# utility functions
+
+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')
+
+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.
+    """
+    etype, value, tb = sys.exc_info()
+    while tb.tb_next is not None:
+        tb = tb.tb_next
+    lineno = traceback.tb_lineno(tb)
+    filename = tb.tb_frame.f_code.co_filename
+    routine = tb.tb_frame.f_code.co_name
+    sys.stderr.write("\nSCons error: %s\n" % value)
+    sys.stderr.write('File "%s", line %d, in %s\n' % (filename, lineno, routine))
+
+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.
+    """
+    etype, value, tb = sys.exc_info()
+    while tb.tb_next is not None:
+        tb = tb.tb_next
+    lineno = traceback.tb_lineno(tb)
+    filename = tb.tb_frame.f_code.co_filename
+    routine = tb.tb_frame.f_code.co_name
+    sys.stderr.write("\nSCons warning: %s\n" % e)
+    sys.stderr.write('File "%s", line %d, in %s\n' % (filename, lineno, routine))
+
+def _scons_other_errors():
+    """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 'other errors'
+    traceback.print_exc()
+
+
+
+#
+# After options are initialized, the following variables are
+# filled in:
+#
+option_list = []	# list of Option objects
+short_opts = ""		# string of short (single-character) options
+long_opts = []		# array of long (--) options
+opt_func = {}		# mapping of option strings to functions
+
+def options_init():
+    """Initialize command-line options processing.
+    
+    This is in a subroutine mainly so we can easily single-step over
+    it in the debugger.
+    """
+
+    class Option:
+	"""Class for command-line option information.
+
+	This exists to provide a central location for everything
+	describing a command-line option, so that we can change
+	options without having to update the code to handle the
+	option in one place, the -h help message in another place,
+	etc.  There are no methods here, only attributes.
+
+	You can initialize an Option with the following:
+
+	func	The function that will be called when this
+		option is processed on the command line.
+		Calling sequence is:
+
+			func(opt, arg)
+
+		If there is no func, then this Option probably
+		stores an optstring to be printed.
+
+	helpline
+		The string to be printed in -h output.  If no
+		helpline is specified but a help string is
+		specified (the usual case), a helpline will be
+		constructed automatically from the short, long,
+		arg, and help attributes.  (In practice, then,
+		setting helpline without setting func allows you
+		to print arbitrary lines of text in the -h
+		output.)
+
+	short	The string for short, single-hyphen
+		command-line options.
+		Do not include the hyphen:
+
+			'a' for -a, 'xy' for -x and -y, etc.
+
+	long	An array of strings for long, double-hyphen
+		command-line options.  Do not include
+		the hyphens:
+
+			['my-option', 'verbose']
+
+	arg	If this option takes an argument, this string
+		specifies how you want it to appear in the
+		-h output ('DIRECTORY', 'FILE', etc.).
+
+	help	The help string that will be printed for
+		this option in the -h output.  Must be
+		49 characters or fewer.
+
+	future	If non-zero, this indicates that this feature
+		will be supported in a future release, not
+		the currently planned one.  SCons will
+		recognize the option, but it won't show up
+		in the -h output.
+
+	The following attribute is derived from the supplied attributes:
+
+	optstring
+		A string, with hyphens, describing the flags
+		for this option, as constructed from the
+		specified short, long and arg attributes.
+
+	All Option objects are stored in the global option_list list,
+	in the order in which they're created.  This is the list
+	that's used to generate -h output, so the order in which the
+	objects are created is the order in which they're printed.
+
+	The upshot is that specifying a command-line option and having
+	everything work correctly is a matter of defining a function to
+	process its command-line argument (set the right flag, update
+	the right value), and then creating an appropriate Option object
+	at the correct point in the code below.
+	"""
+
+	def __init__(self, func = None, helpline = None,
+		 short = None, long = None, arg = None,
+		 help = None, future = None):
+	    self.func = func
+	    self.short = short
+	    self.long = long
+	    self.arg = arg
+	    self.help = help
+	    opts = []
+	    if self.short:
+		for c in self.short:
+		    if arg:
+			c = c + " " + arg
+		    opts = opts + ['-' + c]
+	    if self.long:
+		l = self.long
+		if arg:
+		    l = map(lambda x,a=arg: x + "=" + a, self.long)
+		opts = opts + map(lambda x: '--' + x, l)
+	    self.optstring = string.join(opts, ', ')
+	    if helpline:
+		self.helpline = helpline
+	    elif help and not future:
+		if len(self.optstring) <= 26:
+		    sep = " " * (28 - len(self.optstring))
+		else:
+		    sep = self.helpstring = "\n" + " " * 30
+		self.helpline = "  " + self.optstring + sep + self.help
+	    else:
+		self.helpline = None
+	    global option_list
+	    option_list.append(self)
+
+    # Generic routine for to-be-written options, used by multiple
+    # options below.
+
+    def opt_not_yet(opt, arg):
+        sys.stderr.write("Warning:  the %s option is not yet implemented\n"
+			  % opt)
+
+    # In the following instantiations, the help string should be no
+    # longer than 49 characters.  Use the following as a guide:
+    #	help = "1234567890123456789012345678901234567890123456789"
+
+    def opt_ignore(opt, arg):
+	sys.stderr.write("Warning:  ignoring %s option\n" % opt)
+
+    Option(func = opt_ignore,
+	short = 'bmSt', long = ['no-keep-going', 'stop', 'touch'],
+	help = "Ignored for compatibility.")
+
+    def opt_c(opt, arg):
+        global task_class, calc
+        task_class = CleanTask
+        class CleanCalculator:
+            def bsig(self, node):
+                return None
+            def csig(self, node):
+                return None
+            def current(self, node, sig):
+                return 0
+            def write(self):
+                pass
+        calc = CleanCalculator()
+
+    Option(func = opt_c,
+	short = 'c', long = ['clean', 'remove'],
+	help = "Remove specified targets and dependencies.")
+
+    Option(func = opt_not_yet, future = 1,
+	long = ['cache-disable', 'no-cache'],
+	help = "Do not retrieve built targets from Cache.")
+
+    Option(func = opt_not_yet, future = 1,
+	long = ['cache-force', 'cache-populate'],
+	help = "Copy already-built targets into the Cache.")
+
+    Option(func = opt_not_yet, future = 1,
+	long = ['cache-show'],
+	help = "Print what would have built Cached targets.")
+
+    def opt_C(opt, arg):
+	try:
+	    os.chdir(arg)
+            SCons.Node.FS.default_fs.set_toplevel_dir(os.getcwd())
+	except:
+	    sys.stderr.write("Could not change directory to 'arg'\n")
+
+    Option(func = opt_C,
+	short = 'C', long = ['directory'], arg = 'DIRECTORY',
+	help = "Change to DIRECTORY before doing anything.")
+
+    Option(func = opt_not_yet,
+	short = 'd',
+	help = "Print file dependency information.")
+
+    Option(func = opt_not_yet, future = 1,
+	long = ['debug'], arg = 'FLAGS',
+	help = "Print various types of debugging information.")
+
+    Option(func = opt_not_yet, future = 1,
+	short = 'e', long = ['environment-overrides'],
+	help = "Environment variables override makefiles.")
+
+    def opt_f(opt, arg):
+	global scripts
+        scripts.append(arg)
+
+    Option(func = opt_f,
+	short = 'f', long = ['file', 'makefile', 'sconstruct'], arg = 'FILE',
+	help = "Read FILE as the top-level SConstruct file.")
+
+    def opt_help(opt, arg):
+	global help_option
+        help_option = 'h'
+	SCons.Script.SConscript.print_help = 1
+
+    Option(func = opt_help,
+	short = 'h', long = ['help'],
+	help = "Print defined help message, or this one.")
+
+    def opt_help_options(opt, arg):
+	global help_option
+        help_option = 'H'
+
+    Option(func = opt_help_options,
+	short = 'H', long = ['help-options'],
+	help = "Print this message and exit.")
+
+    def opt_i(opt, arg):
+        global ignore_errors
+        ignore_errors = 1
+
+    Option(func = opt_i,
+	short = 'i', long = ['ignore-errors'],
+	help = "Ignore errors from build actions.")
+
+    def opt_I(opt, arg):
+	global include_dirs
+	include_dirs = include_dirs + [arg]
+
+    Option(func = opt_I,
+	short = 'I', long = ['include-dir'], arg = 'DIRECTORY',
+	help = "Search DIRECTORY for imported Python modules.")
+
+    def opt_j(opt, arg):
+	global num_jobs
+	try:
+            num_jobs = int(arg)
+	except:
+            print UsageString()
+            sys.exit(1)
+
+	if num_jobs <= 0:
+            print UsageString()
+            sys.exit(1)
+
+    Option(func = opt_j,
+	short = 'j', long = ['jobs'], arg = 'N',
+	help = "Allow N jobs at once.")
+
+    def opt_k(opt, arg):
+        global keep_going_on_error
+        keep_going_on_error = 1
+
+    Option(func = opt_k,
+	short = 'k', long = ['keep-going'],
+	help = "Keep going when a target can't be made.")
+
+    Option(func = opt_not_yet, future = 1,
+	short = 'l', long = ['load-average', 'max-load'], arg = 'N',
+	help = "Don't start multiple jobs unless load is below N.")
+
+    Option(func = opt_not_yet, future = 1,
+	long = ['list-derived'],
+	help = "Don't build; list files that would be built.")
+
+    Option(func = opt_not_yet, future = 1,
+	long = ['list-actions'],
+	help = "Don't build; list files and build actions.")
+
+    Option(func = opt_not_yet, future = 1,
+	long = ['list-where'],
+	help = "Don't build; list files and where defined.")
+
+    def opt_n(opt, arg):
+	SCons.Builder.execute_actions = None
+
+    Option(func = opt_n,
+	short = 'n', long = ['no-exec', 'just-print', 'dry-run', 'recon'],
+	help = "Don't build; just print commands.")
+
+    Option(func = opt_not_yet, future = 1,
+	short = 'o', long = ['old-file', 'assume-old'], arg = 'FILE',
+	help = "Consider FILE to be old; don't rebuild it.")
+
+    Option(func = opt_not_yet, future = 1,
+	long = ['override'], arg = 'FILE',
+	help = "Override variables as specified in FILE.")
+
+    Option(func = opt_not_yet, future = 1,
+	short = 'p',
+	help = "Print internal environments/objects.")
+
+    Option(func = opt_not_yet, future = 1,
+	short = 'q', long = ['question'],
+	help = "Don't build; exit status says if up to date.")
+
+    Option(func = opt_not_yet, future = 1,
+	short = 'rR', long = ['no-builtin-rules', 'no-builtin-variables'],
+	help = "Clear default environments and variables.")
+
+    Option(func = opt_not_yet, future = 1,
+	long = ['random'],
+	help = "Build dependencies in random order.")
+
+    def opt_s(opt, arg):
+	SCons.Builder.print_actions = None
+
+    Option(func = opt_s,
+	short = 's', long = ['silent', 'quiet'],
+	help = "Don't print commands.")
+
+    Option(func = opt_not_yet, future = 1,
+	short = 'u', long = ['up', 'search-up'],
+	help = "Search up directory tree for SConstruct.")
+
+    def option_v(opt, arg):
+        import SCons
+	print "SCons by Steven Knight et al.:"
+	print "\tscript version __VERSION__"
+	print "\tbuild engine version %s" % SCons.__version__
+	print "Copyright 2001 Steven Knight"
+	sys.exit(0)
+
+    Option(func = option_v,
+	short = 'v', long = ['version'],
+	help = "Print the SCons version number and exit.")
+
+    Option(func = opt_not_yet, future = 1,
+	short = 'w', long = ['print-directory'],
+	help = "Print the current directory.")
+
+    Option(func = opt_not_yet, future = 1,
+	long = ['no-print-directory'],
+	help = "Turn off -w, even if it was turned on implicitly.")
+
+    Option(func = opt_not_yet, future = 1,
+	long = ['write-filenames'], arg = 'FILE',
+	help = "Write all filenames examined into FILE.")
+
+    Option(func = opt_not_yet, future = 1,
+	short = 'W', long = ['what-if', 'new-file', 'assume-new'], arg = 'FILE',
+	help = "Consider FILE to be changed.")
+
+    Option(func = opt_not_yet, future = 1,
+	long = ['warn-undefined-variables'],
+	help = "Warn when an undefined variable is referenced.")
+
+    Option(func = opt_not_yet, future = 1,
+	short = 'Y', long = ['repository'], arg = 'REPOSITORY',
+	help = "Search REPOSITORY for source and target files.")
+
+    global short_opts
+    global long_opts
+    global opt_func
+    for o in option_list:
+	if o.short:
+	    if o.func:
+		for c in o.short:
+		    opt_func['-' + c] = o.func
+	    short_opts = short_opts + o.short
+	    if o.arg:
+		short_opts = short_opts + ":"
+	if o.long:
+	    if o.func:
+		for l in o.long:
+		    opt_func['--' + l] = o.func
+	    if o.arg:
+		long_opts = long_opts + map(lambda a: a + "=", o.long)
+	    else:
+		long_opts = long_opts + o.long
+
+options_init()
+
+
+
+def UsageString():
+    help_opts = filter(lambda x: x.helpline, option_list)
+    s = "Usage: scons [OPTION] [TARGET] ...\n" + "Options:\n" + \
+	string.join(map(lambda x: x.helpline, help_opts), "\n") + "\n"
+    return s
+
+
+
+def _main():
+    global scripts, num_jobs, task_class, calc
+
+    targets = []
+
+    # It looks like 2.0 changed the name of the exception class
+    # raised by getopt.
+    try:
+	getopt_err = getopt.GetoptError
+    except:
+	getopt_err = getopt.error
+
+    try:
+	cmd_opts, t = getopt.getopt(string.split(os.environ['SCONSFLAGS']),
+					  short_opts, long_opts)
+    except KeyError:
+	# It's all right if there's no SCONSFLAGS environment variable.
+	pass
+    except getopt_err, x:
+	_scons_user_warning("SCONSFLAGS " + str(x))
+    else:
+	for opt, arg in cmd_opts:
+	    opt_func[opt](opt, arg)
+
+    try:
+	cmd_opts, targets = getopt.getopt(sys.argv[1:], short_opts, long_opts)
+    except getopt_err, x:
+	_scons_user_error(x)
+    else:
+	for opt, arg in cmd_opts:
+	    opt_func[opt](opt, arg)
+
+    if not scripts:
+        for file in ['SConstruct', 'Sconstruct', 'sconstruct']:
+            if os.path.isfile(file):
+                scripts.append(file)
+                break
+
+    if help_option == 'H':
+	print UsageString()
+	sys.exit(0)
+
+    if not scripts:
+        if help_option == 'h':
+            # 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.
+	    print UsageString()
+	    sys.exit(0)
+	else:
+	    raise UserError, "No SConstruct file found."
+
+    sys.path = include_dirs + sys.path
+
+    for script in scripts:
+        SCons.Script.SConscript.SConscript(script)
+
+    SCons.Node.FS.default_fs.chdir(SCons.Node.FS.default_fs.Top)
+
+    if help_option == 'h':
+	# They specified -h, but there was no Help() inside the
+	# SConscript files.  Give them the options usage.
+	print UsageString()
+	sys.exit(0)
+
+    if not targets:
+        targets = SCons.Script.SConscript.default_targets
+	
+    def Entry(x):
+	if isinstance(x, SCons.Node.Node):
+	    return x
+	else:
+	    return SCons.Node.FS.default_fs.Entry(x)
+	
+    nodes = map(Entry, targets)
+
+    if not calc:
+        calc = SCons.Sig.Calculator(SCons.Sig.MD5)
+
+    taskmaster = SCons.Taskmaster.Taskmaster(nodes, task_class, calc)
+
+    jobs = SCons.Job.Jobs(num_jobs, taskmaster)
+    jobs.start()
+    jobs.wait()
+
+    SCons.Sig.write()
+
+def main():
+    try:
+	_main()
+    except SystemExit:
+        pass
+    except KeyboardInterrupt:
+        print "Build interrupted."
+    except SyntaxError, e:
+        _scons_syntax_error(e)
+    except UserError, e:
+        _scons_user_error(e)
+    except:
+        _scons_other_errors()
+
+

src/engine/setup.py

       packages = ["SCons",
 		  "SCons.Node",
 		  "SCons.Scanner",
-		  "SCons.Sig"])
+		  "SCons.Sig",
+		  "SCons.Script"])
     'packages'         : ["SCons",
                           "SCons.Node",
                           "SCons.Scanner",
-                          "SCons.Sig"],
+                          "SCons.Sig",
+                          "SCons.Script"],
     'package_dir'      : {'' : 'engine'},
     'scripts'          : ["script/scons"],
     'cmdclass'         : {'install_lib' : my_install_lib}

test/SConstruct.py

 test = TestSCons.TestSCons(match = TestCmd.match_re)
 
 test.run(stdout = "",
-	stderr = """
+	stderr = r"""
 SCons error: No SConstruct file found.
-File "\S+Script.py", line \d+, in _main
+File "\S+", line \d+, in \S+
 """)
 
 test.match_func = TestCmd.match_exact
 test.run(arguments='-f SConstruct3',
 	 stdout = "other errors\n",
 	 stderr = r"""Traceback \((most recent call|innermost) last\):
-  File ".*Script.py", line \d+, in main
-    _main\(\)
-  File ".*Script.py", line \d+, in _main
-    SCons.SConscript.SConscript\(script\)
-  File ".*SConscript.py", line \d+, in SConscript
-    exec file in stack\[-1\].globals
+  File ".+", line \d+, in .+
+    .+
+  File ".+", line \d+, in .+
+    .+
+  File ".+", line \d+, in .+
+    .+
   File "SConstruct3", line \d+, in \?
     raise InternalError, 'error inside'
 InternalError: error inside