X86: Move the GDT down to where it can be accessed in 32 bit mode.
[gem5.git] / SConstruct
old mode 100644 (file)
new mode 100755 (executable)
index 7a0bf27..415af6c
@@ -1,5 +1,6 @@
 # -*- mode:python -*-
 
 # -*- mode:python -*-
 
+# Copyright (c) 2011 Advanced Micro Devices, Inc.
 # Copyright (c) 2009 The Hewlett-Packard Development Company
 # Copyright (c) 2004-2005 The Regents of The University of Michigan
 # All rights reserved.
 # Copyright (c) 2009 The Hewlett-Packard Development Company
 # Copyright (c) 2004-2005 The Regents of The University of Michigan
 # All rights reserved.
 #
 # SCons top-level build description (SConstruct) file.
 #
 #
 # SCons top-level build description (SConstruct) file.
 #
-# While in this directory ('m5'), just type 'scons' to build the default
+# While in this directory ('gem5'), just type 'scons' to build the default
 # configuration (see below), or type 'scons build/<CONFIG>/<binary>'
 # configuration (see below), or type 'scons build/<CONFIG>/<binary>'
-# to build some other configuration (e.g., 'build/ALPHA_FS/m5.opt' for
+# to build some other configuration (e.g., 'build/ALPHA/gem5.opt' for
 # the optimized full-system version).
 #
 # the optimized full-system version).
 #
-# You can build M5 in a different directory as long as there is a
+# You can build gem5 in a different directory as long as there is a
 # 'build/<CONFIG>' somewhere along the target path.  The build system
 # expects that all configs under the same build directory are being
 # built for the same host system.
 # 'build/<CONFIG>' somewhere along the target path.  The build system
 # expects that all configs under the same build directory are being
 # built for the same host system.
 #
 #   The following two commands are equivalent.  The '-u' option tells
 #   scons to search up the directory tree for this SConstruct file.
 #
 #   The following two commands are equivalent.  The '-u' option tells
 #   scons to search up the directory tree for this SConstruct file.
-#   % cd <path-to-src>/m5 ; scons build/ALPHA_FS/m5.debug
-#   % cd <path-to-src>/m5/build/ALPHA_FS; scons -u m5.debug
+#   % cd <path-to-src>/gem5 ; scons build/ALPHA/gem5.debug
+#   % cd <path-to-src>/gem5/build/ALPHA; scons -u gem5.debug
 #
 #   The following two commands are equivalent and demonstrate building
 #   in a directory outside of the source tree.  The '-C' option tells
 #   scons to chdir to the specified directory to find this SConstruct
 #   file.
 #
 #   The following two commands are equivalent and demonstrate building
 #   in a directory outside of the source tree.  The '-C' option tells
 #   scons to chdir to the specified directory to find this SConstruct
 #   file.
-#   % cd <path-to-src>/m5 ; scons /local/foo/build/ALPHA_FS/m5.debug
-#   % cd /local/foo/build/ALPHA_FS; scons -C <path-to-src>/m5 m5.debug
+#   % cd <path-to-src>/gem5 ; scons /local/foo/build/ALPHA/gem5.debug
+#   % cd /local/foo/build/ALPHA; scons -C <path-to-src>/gem5 gem5.debug
 #
 # You can use 'scons -H' to print scons options.  If you're in this
 #
 # You can use 'scons -H' to print scons options.  If you're in this
-# 'm5' directory (or use -u or -C to tell scons where to find this
-# file), you can use 'scons -h' to print all the M5-specific build
+# 'gem5' directory (or use -u or -C to tell scons where to find this
+# file), you can use 'scons -h' to print all the gem5-specific build
 # options as well.
 #
 ###################################################
 # options as well.
 #
 ###################################################
@@ -76,7 +77,7 @@ try:
 except SystemExit, e:
     print """
 For more details, see:
 except SystemExit, e:
     print """
 For more details, see:
-    http://m5sim.org/wiki/index.php/Compiling_M5
+    http://gem5.org/Dependencies
 """
     raise
 
 """
     raise
 
@@ -92,10 +93,11 @@ either (1) rearranging your PATH so that scons finds the non-default
 on the scons script.
 
 For more details, see:
 on the scons script.
 
 For more details, see:
-    http://m5sim.org/wiki/index.php/Using_a_non-default_Python_installation
+    http://gem5.org/wiki/index.php/Using_a_non-default_Python_installation
 """
     raise
 
 """
     raise
 
+# Global Python includes
 import os
 import re
 import subprocess
 import os
 import re
 import subprocess
@@ -106,55 +108,69 @@ from os.path import abspath, basename, dirname, expanduser, normpath
 from os.path import exists,  isdir, isfile
 from os.path import join as joinpath, split as splitpath
 
 from os.path import exists,  isdir, isfile
 from os.path import join as joinpath, split as splitpath
 
+# SCons includes
 import SCons
 import SCons.Node
 
 import SCons
 import SCons.Node
 
-def read_command(cmd, **kwargs):
-    """run the command cmd, read the results and return them
-    this is sorta like `cmd` in shell"""
-    from subprocess import Popen, PIPE, STDOUT
-
-    if isinstance(cmd, str):
-        cmd = cmd.split()
-
-    no_exception = 'exception' in kwargs
-    exception = kwargs.pop('exception', None)
+extra_python_paths = [
+    Dir('src/python').srcnode().abspath, # gem5 includes
+    Dir('ext/ply').srcnode().abspath, # ply is used by several files
+    ]
     
     
-    kwargs.setdefault('shell', False)
-    kwargs.setdefault('stdout', PIPE)
-    kwargs.setdefault('stderr', STDOUT)
-    kwargs.setdefault('close_fds', True)
-    try:
-        subp = Popen(cmd, **kwargs)
-    except Exception, e:
-        if no_exception:
-            return exception
-        raise
-
-    return subp.communicate()[0]
-
-# helper function: compare arrays or strings of version numbers.
-# E.g., compare_version((1,3,25), (1,4,1)')
-# returns -1, 0, 1 if v1 is <, ==, > v2
-def compare_versions(v1, v2):
-    def make_version_list(v):
-        if isinstance(v, (list,tuple)):
-            return v
-        elif isinstance(v, str):
-            return map(lambda x: int(re.match('\d+', x).group()), v.split('.'))
+sys.path[1:1] = extra_python_paths
+
+from m5.util import compareVersions, readCommand
+from m5.util.terminal import get_termcap
+
+help_texts = {
+    "options" : "",
+    "global_vars" : "",
+    "local_vars" : ""
+}
+
+Export("help_texts")
+
+
+# There's a bug in scons in that (1) by default, the help texts from
+# AddOption() are supposed to be displayed when you type 'scons -h'
+# and (2) you can override the help displayed by 'scons -h' using the
+# Help() function, but these two features are incompatible: once
+# you've overridden the help text using Help(), there's no way to get
+# at the help texts from AddOptions.  See:
+#     http://scons.tigris.org/issues/show_bug.cgi?id=2356
+#     http://scons.tigris.org/issues/show_bug.cgi?id=2611
+# This hack lets us extract the help text from AddOptions and
+# re-inject it via Help().  Ideally someday this bug will be fixed and
+# we can just use AddOption directly.
+def AddLocalOption(*args, **kwargs):
+    col_width = 30
+
+    help = "  " + ", ".join(args)
+    if "help" in kwargs:
+        length = len(help)
+        if length >= col_width:
+            help += "\n" + " " * col_width
         else:
         else:
-            raise TypeError
-
-    v1 = make_version_list(v1)
-    v2 = make_version_list(v2)
-    # Compare corresponding elements of lists
-    for n1,n2 in zip(v1, v2):
-        if n1 < n2: return -1
-        if n1 > n2: return  1
-    # all corresponding values are equal... see if one has extra values
-    if len(v1) < len(v2): return -1
-    if len(v1) > len(v2): return  1
-    return 0
+            help += " " * (col_width - length)
+        help += kwargs["help"]
+    help_texts["options"] += help + "\n"
+
+    AddOption(*args, **kwargs)
+
+AddLocalOption('--colors', dest='use_colors', action='store_true',
+               help="Add color to abbreviated scons output")
+AddLocalOption('--no-colors', dest='use_colors', action='store_false',
+               help="Don't add color to abbreviated scons output")
+AddLocalOption('--default', dest='default', type='string', action='store',
+               help='Override which build_opts file to use for defaults')
+AddLocalOption('--ignore-style', dest='ignore_style', action='store_true',
+               help='Disable style checking hooks')
+AddLocalOption('--update-ref', dest='update_ref', action='store_true',
+               help='Update test reference outputs')
+AddLocalOption('--verbose', dest='verbose', action='store_true',
+               help='Print full tool command lines')
+
+termcap = get_termcap(GetOption('use_colors'))
 
 ########################################################################
 #
 
 ########################################################################
 #
@@ -162,7 +178,7 @@ def compare_versions(v1, v2):
 #
 ########################################################################
 use_vars = set([ 'AS', 'AR', 'CC', 'CXX', 'HOME', 'LD_LIBRARY_PATH', 'PATH',
 #
 ########################################################################
 use_vars = set([ 'AS', 'AR', 'CC', 'CXX', 'HOME', 'LD_LIBRARY_PATH', 'PATH',
-                 'RANLIB' ])
+                 'PYTHONPATH', 'RANLIB', 'SWIG' ])
 
 use_env = {}
 for key,val in os.environ.iteritems():
 
 use_env = {}
 for key,val in os.environ.iteritems():
@@ -170,14 +186,19 @@ for key,val in os.environ.iteritems():
         use_env[key] = val
 
 main = Environment(ENV=use_env)
         use_env[key] = val
 
 main = Environment(ENV=use_env)
+main.Decider('MD5-timestamp')
 main.root = Dir(".")         # The current directory (where this file lives).
 main.srcdir = Dir("src")     # The source directory
 
 main.root = Dir(".")         # The current directory (where this file lives).
 main.srcdir = Dir("src")     # The source directory
 
+# add useful python code PYTHONPATH so it can be used by subprocesses
+# as well
+main.AppendENVPath('PYTHONPATH', extra_python_paths)
+
 ########################################################################
 #
 # Mercurial Stuff.
 #
 ########################################################################
 #
 # Mercurial Stuff.
 #
-# If the M5 directory is a mercurial repository, we should do some
+# If the gem5 directory is a mercurial repository, we should do some
 # extra things.
 #
 ########################################################################
 # extra things.
 #
 ########################################################################
@@ -185,62 +206,62 @@ main.srcdir = Dir("src")     # The source directory
 hgdir = main.root.Dir(".hg")
 
 mercurial_style_message = """
 hgdir = main.root.Dir(".hg")
 
 mercurial_style_message = """
-You're missing the M5 style hook.
-Please install the hook so we can ensure that all code fits a common style.
-
-All you'd need to do is add the following lines to your repository .hg/hgrc
-or your personal .hgrc
-----------------
-
+You're missing the gem5 style hook, which automatically checks your code
+against the gem5 style rules on hg commit and qrefresh commands.  This
+script will now install the hook in your .hg/hgrc file.
+Press enter to continue, or ctrl-c to abort: """
+
+mercurial_style_hook = """
+# The following lines were automatically added by gem5/SConstruct
+# to provide the gem5 style-checking hooks
 [extensions]
 style = %s/util/style.py
 
 [hooks]
 [extensions]
 style = %s/util/style.py
 
 [hooks]
-pretxncommit.style = python:style.check_whitespace
-""" % (main.root)
-
-mercurial_bin_not_found = """
-Mercurial binary cannot be found, unfortunately this means that we
-cannot easily determine the version of M5 that you are running and
-this makes error messages more difficult to collect.  Please consider
-installing mercurial if you choose to post an error message
-"""
+pretxncommit.style = python:style.check_style
+pre-qrefresh.style = python:style.check_style
+# End of SConstruct additions
+
+""" % (main.root.abspath)
 
 mercurial_lib_not_found = """
 
 mercurial_lib_not_found = """
-Mercurial libraries cannot be found, ignoring style hook
-If you are actually a M5 developer, please fix this and
-run the style hook. It is important.
+Mercurial libraries cannot be found, ignoring style hook.  If
+you are a gem5 developer, please fix this and run the style
+hook. It is important.
 """
 
 """
 
-hg_info = "Unknown"
-if hgdir.exists():
-    # 1) Grab repository revision if we know it.
-    cmd = "hg id -n -i -t -b"
+# Check for style hook and prompt for installation if it's not there.
+# Skip this if --ignore-style was specified, there's no .hg dir to
+# install a hook in, or there's no interactive terminal to prompt.
+if not GetOption('ignore_style') and hgdir.exists() and sys.stdin.isatty():
+    style_hook = True
     try:
     try:
-        hg_info = read_command(cmd, cwd=main.root.abspath).strip()
-    except OSError:
-        print mercurial_bin_not_found
-
-    # 2) Ensure that the style hook is in place.
-    try:
-        ui = None
-        if ARGUMENTS.get('IGNORE_STYLE') != 'True':
-            from mercurial import ui
-            ui = ui.ui()
+        from mercurial import ui
+        ui = ui.ui()
+        ui.readconfig(hgdir.File('hgrc').abspath)
+        style_hook = ui.config('hooks', 'pretxncommit.style', None) and \
+                     ui.config('hooks', 'pre-qrefresh.style', None)
     except ImportError:
         print mercurial_lib_not_found
 
     except ImportError:
         print mercurial_lib_not_found
 
-    if ui is not None:
-        ui.readconfig(hgdir.File('hgrc').abspath)
-        style_hook = ui.config('hooks', 'pretxncommit.style', None)
-
-        if not style_hook:
-            print mercurial_style_message
+    if not style_hook:
+        print mercurial_style_message,
+        # continue unless user does ctrl-c/ctrl-d etc.
+        try:
+            raw_input()
+        except:
+            print "Input exception, exiting scons.\n"
+            sys.exit(1)
+        hgrc_path = '%s/.hg/hgrc' % main.root.abspath
+        print "Adding style hook to", hgrc_path, "\n"
+        try:
+            hgrc = open(hgrc_path, 'a')
+            hgrc.write(mercurial_style_hook)
+            hgrc.close()
+        except:
+            print "Error updating", hgrc_path
             sys.exit(1)
             sys.exit(1)
-else:
-    print ".hg directory not found"
 
 
-main['HG_INFO'] = hg_info
 
 ###################################################
 #
 
 ###################################################
 #
@@ -250,7 +271,7 @@ main['HG_INFO'] = hg_info
 ###################################################
 
 # Find default configuration & binary.
 ###################################################
 
 # Find default configuration & binary.
-Default(environ.get('M5_DEFAULT_BINARY', 'build/ALPHA_SE/m5.debug'))
+Default(environ.get('M5_DEFAULT_BINARY', 'build/ALPHA/gem5.debug'))
 
 # helper function: find last occurrence of element in list
 def rfind(l, elt, offs = -1):
 
 # helper function: find last occurrence of element in list
 def rfind(l, elt, offs = -1):
@@ -259,30 +280,29 @@ def rfind(l, elt, offs = -1):
             return i
     raise ValueError, "element not found"
 
             return i
     raise ValueError, "element not found"
 
+# Take a list of paths (or SCons Nodes) and return a list with all
+# paths made absolute and ~-expanded.  Paths will be interpreted
+# relative to the launch directory unless a different root is provided
+def makePathListAbsolute(path_list, root=GetLaunchDir()):
+    return [abspath(joinpath(root, expanduser(str(p))))
+            for p in path_list]
+
 # Each target must have 'build' in the interior of the path; the
 # directory below this will determine the build parameters.  For
 # example, for target 'foo/bar/build/ALPHA_SE/arch/alpha/blah.do' we
 # recognize that ALPHA_SE specifies the configuration because it
 # Each target must have 'build' in the interior of the path; the
 # directory below this will determine the build parameters.  For
 # example, for target 'foo/bar/build/ALPHA_SE/arch/alpha/blah.do' we
 # recognize that ALPHA_SE specifies the configuration because it
-# follow 'build' in the bulid path.
-
-# Generate absolute paths to targets so we can see where the build dir is
-if COMMAND_LINE_TARGETS:
-    # Ask SCons which directory it was invoked from
-    launch_dir = GetLaunchDir()
-    # Make targets relative to invocation directory
-    abs_targets = [ normpath(joinpath(launch_dir, str(x))) for x in \
-                    COMMAND_LINE_TARGETS]
-else:
-    # Default targets are relative to root of tree
-    abs_targets = [ normpath(joinpath(main.root.abspath, str(x))) for x in \
-                    DEFAULT_TARGETS]
+# follow 'build' in the build path.
 
 
+# The funky assignment to "[:]" is needed to replace the list contents
+# in place rather than reassign the symbol to a new list, which
+# doesn't work (obviously!).
+BUILD_TARGETS[:] = makePathListAbsolute(BUILD_TARGETS)
 
 # Generate a list of the unique build roots and configs that the
 # collected targets reference.
 variant_paths = []
 build_root = None
 
 # Generate a list of the unique build roots and configs that the
 # collected targets reference.
 variant_paths = []
 build_root = None
-for t in abs_targets:
+for t in BUILD_TARGETS:
     path_dirs = t.split('/')
     try:
         build_top = rfind(path_dirs, 'build', -2)
     path_dirs = t.split('/')
     try:
         build_top = rfind(path_dirs, 'build', -2)
@@ -304,6 +324,7 @@ for t in abs_targets:
 # Make sure build_root exists (might not if this is the first build there)
 if not isdir(build_root):
     mkdir(build_root)
 # Make sure build_root exists (might not if this is the first build there)
 if not isdir(build_root):
     mkdir(build_root)
+main['BUILDROOT'] = build_root
 
 Export('main')
 
 
 Export('main')
 
@@ -320,54 +341,32 @@ main.SetOption('duplicate', 'soft-copy')
 # tree (not specific to a particular build like ALPHA_SE)
 #
 
 # tree (not specific to a particular build like ALPHA_SE)
 #
 
-# Variable validators & converters for global sticky variables
-def PathListMakeAbsolute(val):
-    if not val:
-        return val
-    f = lambda p: abspath(expanduser(p))
-    return ':'.join(map(f, val.split(':')))
-
-def PathListAllExist(key, val, env):
-    if not val:
-        return
-    paths = val.split(':')
-    for path in paths:
-        if not isdir(path):
-            raise SCons.Errors.UserError("Path does not exist: '%s'" % path)
+global_vars_file = joinpath(build_root, 'variables.global')
 
 
-global_sticky_vars_file = joinpath(build_root, 'variables.global')
+global_vars = Variables(global_vars_file, args=ARGUMENTS)
 
 
-global_sticky_vars = Variables(global_sticky_vars_file, args=ARGUMENTS)
-
-global_sticky_vars.AddVariables(
+global_vars.AddVariables(
     ('CC', 'C compiler', environ.get('CC', main['CC'])),
     ('CXX', 'C++ compiler', environ.get('CXX', main['CXX'])),
     ('CC', 'C compiler', environ.get('CC', main['CC'])),
     ('CXX', 'C++ compiler', environ.get('CXX', main['CXX'])),
+    ('SWIG', 'SWIG tool', environ.get('SWIG', main['SWIG'])),
     ('BATCH', 'Use batch pool for build and tests', False),
     ('BATCH_CMD', 'Batch pool submission command name', 'qdo'),
     ('BATCH', 'Use batch pool for build and tests', False),
     ('BATCH_CMD', 'Batch pool submission command name', 'qdo'),
-    ('EXTRAS', 'Add Extra directories to the compilation', '',
-     PathListAllExist, PathListMakeAbsolute)
-    )    
-
-# base help text
-help_text = '''
-Usage: scons [scons options] [build options] [target(s)]
-
-Global sticky options:
-'''
-
-help_text += global_sticky_vars.GenerateHelpText(main)
+    ('M5_BUILD_CACHE', 'Cache built objects in this directory', False),
+    ('EXTRAS', 'Add extra directories to the compilation', '')
+    )
 
 
-# Update main environment with values from ARGUMENTS & global_sticky_vars_file
-global_sticky_vars.Update(main)
+# Update main environment with values from ARGUMENTS & global_vars_file
+global_vars.Update(main)
+help_texts["global_vars"] += global_vars.GenerateHelpText(main)
 
 # Save sticky variable settings back to current variables file
 
 # Save sticky variable settings back to current variables file
-global_sticky_vars.Save(global_sticky_vars_file, main)
+global_vars.Save(global_vars_file, main)
 
 # Parse EXTRAS variable to build list of all directories where we're
 
 # Parse EXTRAS variable to build list of all directories where we're
-# look for sources etc.  This list is exported as base_dir_list.
+# look for sources etc.  This list is exported as extras_dir_list.
 base_dir = main.srcdir.abspath
 if main['EXTRAS']:
 base_dir = main.srcdir.abspath
 if main['EXTRAS']:
-    extras_dir_list = main['EXTRAS'].split(':')
+    extras_dir_list = makePathListAbsolute(main['EXTRAS'].split(':'))
 else:
     extras_dir_list = []
 
 else:
     extras_dir_list = []
 
@@ -377,39 +376,176 @@ Export('extras_dir_list')
 # the ext directory should be on the #includes path
 main.Append(CPPPATH=[Dir('ext')])
 
 # the ext directory should be on the #includes path
 main.Append(CPPPATH=[Dir('ext')])
 
-# M5_PLY is used by isa_parser.py to find the PLY package.
-main.Append(ENV = { 'M5_PLY' : Dir('ext/ply').abspath })
-
-CXX_version = read_command([main['CXX'],'--version'], exception=False)
-CXX_V = read_command([main['CXX'],'-V'], exception=False)
+def strip_build_path(path, env):
+    path = str(path)
+    variant_base = env['BUILDROOT'] + os.path.sep
+    if path.startswith(variant_base):
+        path = path[len(variant_base):]
+    elif path.startswith('build/'):
+        path = path[6:]
+    return path
+
+# Generate a string of the form:
+#   common/path/prefix/src1, src2 -> tgt1, tgt2
+# to print while building.
+class Transform(object):
+    # all specific color settings should be here and nowhere else
+    tool_color = termcap.Normal
+    pfx_color = termcap.Yellow
+    srcs_color = termcap.Yellow + termcap.Bold
+    arrow_color = termcap.Blue + termcap.Bold
+    tgts_color = termcap.Yellow + termcap.Bold
+
+    def __init__(self, tool, max_sources=99):
+        self.format = self.tool_color + (" [%8s] " % tool) \
+                      + self.pfx_color + "%s" \
+                      + self.srcs_color + "%s" \
+                      + self.arrow_color + " -> " \
+                      + self.tgts_color + "%s" \
+                      + termcap.Normal
+        self.max_sources = max_sources
+
+    def __call__(self, target, source, env, for_signature=None):
+        # truncate source list according to max_sources param
+        source = source[0:self.max_sources]
+        def strip(f):
+            return strip_build_path(str(f), env)
+        if len(source) > 0:
+            srcs = map(strip, source)
+        else:
+            srcs = ['']
+        tgts = map(strip, target)
+        # surprisingly, os.path.commonprefix is a dumb char-by-char string
+        # operation that has nothing to do with paths.
+        com_pfx = os.path.commonprefix(srcs + tgts)
+        com_pfx_len = len(com_pfx)
+        if com_pfx:
+            # do some cleanup and sanity checking on common prefix
+            if com_pfx[-1] == ".":
+                # prefix matches all but file extension: ok
+                # back up one to change 'foo.cc -> o' to 'foo.cc -> .o'
+                com_pfx = com_pfx[0:-1]
+            elif com_pfx[-1] == "/":
+                # common prefix is directory path: OK
+                pass
+            else:
+                src0_len = len(srcs[0])
+                tgt0_len = len(tgts[0])
+                if src0_len == com_pfx_len:
+                    # source is a substring of target, OK
+                    pass
+                elif tgt0_len == com_pfx_len:
+                    # target is a substring of source, need to back up to
+                    # avoid empty string on RHS of arrow
+                    sep_idx = com_pfx.rfind(".")
+                    if sep_idx != -1:
+                        com_pfx = com_pfx[0:sep_idx]
+                    else:
+                        com_pfx = ''
+                elif src0_len > com_pfx_len and srcs[0][com_pfx_len] == ".":
+                    # still splitting at file extension: ok
+                    pass
+                else:
+                    # probably a fluke; ignore it
+                    com_pfx = ''
+        # recalculate length in case com_pfx was modified
+        com_pfx_len = len(com_pfx)
+        def fmt(files):
+            f = map(lambda s: s[com_pfx_len:], files)
+            return ', '.join(f)
+        return self.format % (com_pfx, fmt(srcs), fmt(tgts))
+
+Export('Transform')
+
+# enable the regression script to use the termcap
+main['TERMCAP'] = termcap
+
+if GetOption('verbose'):
+    def MakeAction(action, string, *args, **kwargs):
+        return Action(action, *args, **kwargs)
+else:
+    MakeAction = Action
+    main['CCCOMSTR']        = Transform("CC")
+    main['CXXCOMSTR']       = Transform("CXX")
+    main['ASCOMSTR']        = Transform("AS")
+    main['SWIGCOMSTR']      = Transform("SWIG")
+    main['ARCOMSTR']        = Transform("AR", 0)
+    main['LINKCOMSTR']      = Transform("LINK", 0)
+    main['RANLIBCOMSTR']    = Transform("RANLIB", 0)
+    main['M4COMSTR']        = Transform("M4")
+    main['SHCCCOMSTR']      = Transform("SHCC")
+    main['SHCXXCOMSTR']     = Transform("SHCXX")
+Export('MakeAction')
+
+CXX_version = readCommand([main['CXX'],'--version'], exception=False)
+CXX_V = readCommand([main['CXX'],'-V'], exception=False)
 
 main['GCC'] = CXX_version and CXX_version.find('g++') >= 0
 main['SUNCC'] = CXX_V and CXX_V.find('Sun C++') >= 0
 main['ICC'] = CXX_V and CXX_V.find('Intel') >= 0
 
 main['GCC'] = CXX_version and CXX_version.find('g++') >= 0
 main['SUNCC'] = CXX_V and CXX_V.find('Sun C++') >= 0
 main['ICC'] = CXX_V and CXX_V.find('Intel') >= 0
-if main['GCC'] + main['SUNCC'] + main['ICC'] > 1:
+main['CLANG'] = CXX_version and CXX_version.find('clang') >= 0
+if main['GCC'] + main['SUNCC'] + main['ICC'] + main['CLANG'] > 1:
     print 'Error: How can we have two at the same time?'
     Exit(1)
 
 # Set up default C++ compiler flags
 if main['GCC']:
     print 'Error: How can we have two at the same time?'
     Exit(1)
 
 # Set up default C++ compiler flags
 if main['GCC']:
-    main.Append(CCFLAGS='-pipe')
-    main.Append(CCFLAGS='-fno-strict-aliasing')
+    main.Append(CCFLAGS=['-pipe'])
+    main.Append(CCFLAGS=['-fno-strict-aliasing'])
     main.Append(CCFLAGS=['-Wall', '-Wno-sign-compare', '-Wundef'])
     main.Append(CCFLAGS=['-Wall', '-Wno-sign-compare', '-Wundef'])
-    main.Append(CXXFLAGS='-Wno-deprecated')
+    # Read the GCC version to check for versions with bugs
+    # Note CCVERSION doesn't work here because it is run with the CC
+    # before we override it from the command line
+    gcc_version = readCommand([main['CXX'], '-dumpversion'], exception=False)
+    main['GCC_VERSION'] = gcc_version
+    if not compareVersions(gcc_version, '4.4.1') or \
+       not compareVersions(gcc_version, '4.4.2'):
+        print 'Info: Tree vectorizer in GCC 4.4.1 & 4.4.2 is buggy, disabling.'
+        main.Append(CCFLAGS=['-fno-tree-vectorize'])
+    if compareVersions(gcc_version, '4.6') >= 0:
+        main.Append(CXXFLAGS=['-std=c++0x'])
 elif main['ICC']:
     pass #Fix me... add warning flags once we clean up icc warnings
 elif main['SUNCC']:
 elif main['ICC']:
     pass #Fix me... add warning flags once we clean up icc warnings
 elif main['SUNCC']:
-    main.Append(CCFLAGS='-Qoption ccfe')
-    main.Append(CCFLAGS='-features=gcc')
-    main.Append(CCFLAGS='-features=extensions')
-    main.Append(CCFLAGS='-library=stlport4')
-    main.Append(CCFLAGS='-xar')
-    #main.Append(CCFLAGS='-instances=semiexplicit')
+    main.Append(CCFLAGS=['-Qoption ccfe'])
+    main.Append(CCFLAGS=['-features=gcc'])
+    main.Append(CCFLAGS=['-features=extensions'])
+    main.Append(CCFLAGS=['-library=stlport4'])
+    main.Append(CCFLAGS=['-xar'])
+    #main.Append(CCFLAGS=['-instances=semiexplicit'])
+elif main['CLANG']:
+    clang_version_re = re.compile(".* version (\d+\.\d+)")
+    clang_version_match = clang_version_re.match(CXX_version)
+    if (clang_version_match):
+        clang_version = clang_version_match.groups()[0]
+        if compareVersions(clang_version, "2.9") < 0:
+            print 'Error: clang version 2.9 or newer required.'
+            print '       Installed version:', clang_version
+            Exit(1)
+    else:
+        print 'Error: Unable to determine clang version.'
+        Exit(1)
+
+    main.Append(CCFLAGS=['-pipe'])
+    main.Append(CCFLAGS=['-fno-strict-aliasing'])
+    main.Append(CCFLAGS=['-Wall', '-Wno-sign-compare', '-Wundef'])
+    main.Append(CCFLAGS=['-Wno-tautological-compare'])
+    main.Append(CCFLAGS=['-Wno-self-assign'])
+    # Ruby makes frequent use of extraneous parantheses in the printing
+    # of if-statements
+    main.Append(CCFLAGS=['-Wno-parentheses'])
+
+    if compareVersions(clang_version, "3") >= 0:
+        main.Append(CXXFLAGS=['-std=c++0x'])
 else:
     print 'Error: Don\'t know what compiler options to use for your compiler.'
     print '       Please fix SConstruct and src/SConscript and try again.'
     Exit(1)
 
 else:
     print 'Error: Don\'t know what compiler options to use for your compiler.'
     print '       Please fix SConstruct and src/SConscript and try again.'
     Exit(1)
 
+# Set up common yacc/bison flags (needed for Ruby)
+main['YACCFLAGS'] = '-d'
+main['YACCHXXFILESUFFIX'] = '.hh'
+
 # Do this after we save setting back, or else we'll tack on an
 # extra 'qdo' every time we run scons.
 if main['BATCH']:
 # Do this after we save setting back, or else we'll tack on an
 # extra 'qdo' every time we run scons.
 if main['BATCH']:
@@ -421,7 +557,7 @@ if main['BATCH']:
 
 if sys.platform == 'cygwin':
     # cygwin has some header file issues...
 
 if sys.platform == 'cygwin':
     # cygwin has some header file issues...
-    main.Append(CCFLAGS=Split("-Wno-uninitialized"))
+    main.Append(CCFLAGS=["-Wno-uninitialized"])
 
 # Check for SWIG
 if not main.has_key('SWIG'):
 
 # Check for SWIG
 if not main.has_key('SWIG'):
@@ -430,15 +566,15 @@ if not main.has_key('SWIG'):
     Exit(1)
 
 # Check for appropriate SWIG version
     Exit(1)
 
 # Check for appropriate SWIG version
-swig_version = read_command(('swig', '-version'), exception='').split()
+swig_version = readCommand(('swig', '-version'), exception='').split()
 # First 3 words should be "SWIG Version x.y.z"
 if len(swig_version) < 3 or \
         swig_version[0] != 'SWIG' or swig_version[1] != 'Version':
     print 'Error determining SWIG version.'
     Exit(1)
 
 # First 3 words should be "SWIG Version x.y.z"
 if len(swig_version) < 3 or \
         swig_version[0] != 'SWIG' or swig_version[1] != 'Version':
     print 'Error determining SWIG version.'
     Exit(1)
 
-min_swig_version = '1.3.28'
-if compare_versions(swig_version[2], min_swig_version) < 0:
+min_swig_version = '1.3.34'
+if compareVersions(swig_version[2], min_swig_version) < 0:
     print 'Error: SWIG version', min_swig_version, 'or newer required.'
     print '       Installed version:', swig_version[2]
     Exit(1)
     print 'Error: SWIG version', min_swig_version, 'or newer required.'
     print '       Installed version:', swig_version[2]
     Exit(1)
@@ -509,12 +645,12 @@ conf.CheckLeading()
 try:
     import platform
     uname = platform.uname()
 try:
     import platform
     uname = platform.uname()
-    if uname[0] == 'Darwin' and compare_versions(uname[2], '9.0.0') >= 0:
-        if int(read_command('sysctl -n hw.cpu64bit_capable')[0]):
-            main.Append(CCFLAGS='-arch x86_64')
-            main.Append(CFLAGS='-arch x86_64')
-            main.Append(LINKFLAGS='-arch x86_64')
-            main.Append(ASFLAGS='-arch x86_64')
+    if uname[0] == 'Darwin' and compareVersions(uname[2], '9.0.0') >= 0:
+        if int(readCommand('sysctl -n hw.cpu64bit_capable')[0]):
+            main.Append(CCFLAGS=['-arch', 'x86_64'])
+            main.Append(CFLAGS=['-arch', 'x86_64'])
+            main.Append(LINKFLAGS=['-arch', 'x86_64'])
+            main.Append(ASFLAGS=['-arch', 'x86_64'])
 except:
     pass
 
 except:
     pass
 
@@ -546,7 +682,8 @@ from distutils import sysconfig
 
 py_getvar = sysconfig.get_config_var
 
 
 py_getvar = sysconfig.get_config_var
 
-py_version = 'python' + py_getvar('VERSION')
+py_debug = getattr(sys, 'pydebug', False)
+py_version = 'python' + py_getvar('VERSION') + (py_debug and "_d" or "")
 
 py_general_include = sysconfig.get_python_inc()
 py_platform_include = sysconfig.get_python_inc(plat_specific=True)
 
 py_general_include = sysconfig.get_python_inc()
 py_platform_include = sysconfig.get_python_inc(plat_specific=True)
@@ -562,15 +699,25 @@ if not py_getvar('Py_ENABLE_SHARED'):
 
 py_libs = []
 for lib in py_getvar('LIBS').split() + py_getvar('SYSLIBS').split():
 
 py_libs = []
 for lib in py_getvar('LIBS').split() + py_getvar('SYSLIBS').split():
-    assert lib.startswith('-l')
-    lib = lib[2:]   
-    if lib not in py_libs:
-        py_libs.append(lib)
+    if not lib.startswith('-l'):
+        # Python requires some special flags to link (e.g. -framework
+        # common on OS X systems), assume appending preserves order
+        main.Append(LINKFLAGS=[lib])
+    else:
+        lib = lib[2:]
+        if lib not in py_libs:
+            py_libs.append(lib)
 py_libs.append(py_version)
 
 main.Append(CPPPATH=py_includes)
 main.Append(LIBPATH=py_lib_path)
 
 py_libs.append(py_version)
 
 main.Append(CPPPATH=py_includes)
 main.Append(LIBPATH=py_lib_path)
 
+# Cache build files in the supplied directory.
+if main['M5_BUILD_CACHE']:
+    print 'Using build cache located at', main['M5_BUILD_CACHE']
+    CacheDir(main['M5_BUILD_CACHE'])
+
+
 # verify that this stuff works
 if not conf.CheckHeader('Python.h', '<>'):
     print "Error: can't find Python.h header in", py_includes
 # verify that this stuff works
 if not conf.CheckHeader('Python.h', '<>'):
     print "Error: can't find Python.h header in", py_includes
@@ -595,38 +742,22 @@ if not conf.CheckLibWithHeader('z', 'zlib.h', 'C++','zlibVersion();'):
     print '       Please install zlib and try again.'
     Exit(1)
 
     print '       Please install zlib and try again.'
     Exit(1)
 
+# Check for librt.
+have_posix_clock = \
+    conf.CheckLibWithHeader(None, 'time.h', 'C',
+                            'clock_nanosleep(0,0,NULL,NULL);') or \
+    conf.CheckLibWithHeader('rt', 'time.h', 'C',
+                            'clock_nanosleep(0,0,NULL,NULL);')
+
+if not have_posix_clock:
+    print "Can't find library for POSIX clocks."
+
 # Check for <fenv.h> (C99 FP environment control)
 have_fenv = conf.CheckHeader('fenv.h', '<>')
 if not have_fenv:
     print "Warning: Header file <fenv.h> not found."
     print "         This host has no IEEE FP rounding mode control."
 
 # Check for <fenv.h> (C99 FP environment control)
 have_fenv = conf.CheckHeader('fenv.h', '<>')
 if not have_fenv:
     print "Warning: Header file <fenv.h> not found."
     print "         This host has no IEEE FP rounding mode control."
 
-######################################################################
-#
-# Check for mysql.
-#
-mysql_config = WhereIs('mysql_config')
-have_mysql = bool(mysql_config)
-
-# Check MySQL version.
-if have_mysql:
-    mysql_version = read_command(mysql_config + ' --version')
-    min_mysql_version = '4.1'
-    if compare_versions(mysql_version, min_mysql_version) < 0:
-        print 'Warning: MySQL', min_mysql_version, 'or newer required.'
-        print '         Version', mysql_version, 'detected.'
-        have_mysql = False
-
-# Set up mysql_config commands.
-if have_mysql:
-    mysql_config_include = mysql_config + ' --include'
-    if os.system(mysql_config_include + ' > /dev/null') != 0:
-        # older mysql_config versions don't support --include, use
-        # --cflags instead
-        mysql_config_include = mysql_config + ' --cflags | sed s/\\\'//g'
-    # This seems to work in all versions
-    mysql_config_libs = mysql_config + ' --libs'
-
 ######################################################################
 #
 # Finish the configuration
 ######################################################################
 #
 # Finish the configuration
@@ -642,10 +773,34 @@ main = conf.Finish()
 all_isa_list = [ ]
 Export('all_isa_list')
 
 all_isa_list = [ ]
 Export('all_isa_list')
 
-# Define the universe of supported CPU models
-all_cpu_list = [ ]
-default_cpus = [ ]
-Export('all_cpu_list', 'default_cpus')
+class CpuModel(object):
+    '''The CpuModel class encapsulates everything the ISA parser needs to
+    know about a particular CPU model.'''
+
+    # Dict of available CPU model objects.  Accessible as CpuModel.dict.
+    dict = {}
+    list = []
+    defaults = []
+
+    # Constructor.  Automatically adds models to CpuModel.dict.
+    def __init__(self, name, filename, includes, strings, default=False):
+        self.name = name           # name of model
+        self.filename = filename   # filename for output exec code
+        self.includes = includes   # include files needed in exec file
+        # The 'strings' dict holds all the per-CPU symbols we can
+        # substitute into templates etc.
+        self.strings = strings
+
+        # This cpu is enabled by default
+        self.default = default
+
+        # Add self to dict
+        if name in CpuModel.dict:
+            raise AttributeError, "CpuModel '%s' already registered" % name
+        CpuModel.dict[name] = self
+        CpuModel.list.append(name)
+
+Export('CpuModel')
 
 # Sticky variables get saved in the variables file so they persist from
 # one invocation to the next (unless overridden, in which case the new
 
 # Sticky variables get saved in the variables file so they persist from
 # one invocation to the next (unless overridden, in which case the new
@@ -657,29 +812,30 @@ Export('sticky_vars')
 export_vars = []
 Export('export_vars')
 
 export_vars = []
 Export('export_vars')
 
-# Non-sticky variables only apply to the current build.
-nonsticky_vars = Variables(args=ARGUMENTS)
-Export('nonsticky_vars')
-
 # Walk the tree and execute all SConsopts scripts that wil add to the
 # above variables
 # Walk the tree and execute all SConsopts scripts that wil add to the
 # above variables
+if not GetOption('verbose'):
+    print "Reading SConsopts"
 for bdir in [ base_dir ] + extras_dir_list:
 for bdir in [ base_dir ] + extras_dir_list:
+    if not isdir(bdir):
+        print "Error: directory '%s' does not exist" % bdir
+        Exit(1)
     for root, dirs, files in os.walk(bdir):
         if 'SConsopts' in files:
     for root, dirs, files in os.walk(bdir):
         if 'SConsopts' in files:
-            print "Reading", joinpath(root, 'SConsopts')
+            if GetOption('verbose'):
+                print "Reading", joinpath(root, 'SConsopts')
             SConscript(joinpath(root, 'SConsopts'))
 
 all_isa_list.sort()
             SConscript(joinpath(root, 'SConsopts'))
 
 all_isa_list.sort()
-all_cpu_list.sort()
-default_cpus.sort()
 
 sticky_vars.AddVariables(
     EnumVariable('TARGET_ISA', 'Target ISA', 'alpha', all_isa_list),
 
 sticky_vars.AddVariables(
     EnumVariable('TARGET_ISA', 'Target ISA', 'alpha', all_isa_list),
-    BoolVariable('FULL_SYSTEM', 'Full-system support', False),
-    ListVariable('CPU_MODELS', 'CPU models', default_cpus, all_cpu_list),
+    ListVariable('CPU_MODELS', 'CPU models',
+                 sorted(n for n,m in CpuModel.dict.iteritems() if m.default),
+                 sorted(CpuModel.list)),
     BoolVariable('NO_FAST_ALLOC', 'Disable fast object allocator', False),
     BoolVariable('NO_FAST_ALLOC', 'Disable fast object allocator', False),
-    BoolVariable('FAST_ALLOC_DEBUG', 'Enable fast object allocator debugging',
-                 False),
+    BoolVariable('FORCE_FAST_ALLOC',
+                 'Enable fast object allocator, even for gem5.debug', False),
     BoolVariable('FAST_ALLOC_STATS', 'Enable fast object allocator statistics',
                  False),
     BoolVariable('EFENCE', 'Link with Electric Fence malloc debugger',
     BoolVariable('FAST_ALLOC_STATS', 'Enable fast object allocator statistics',
                  False),
     BoolVariable('EFENCE', 'Link with Electric Fence malloc debugger',
@@ -690,20 +846,15 @@ sticky_vars.AddVariables(
     BoolVariable('USE_SSE2',
                  'Compile for SSE2 (-msse2) to get IEEE FP on x86 hosts',
                  False),
     BoolVariable('USE_SSE2',
                  'Compile for SSE2 (-msse2) to get IEEE FP on x86 hosts',
                  False),
-    BoolVariable('USE_MYSQL', 'Use MySQL for stats output', have_mysql),
+    BoolVariable('USE_POSIX_CLOCK', 'Use POSIX Clocks', have_posix_clock),
     BoolVariable('USE_FENV', 'Use <fenv.h> IEEE mode control', have_fenv),
     BoolVariable('USE_FENV', 'Use <fenv.h> IEEE mode control', have_fenv),
-    BoolVariable('USE_CHECKER', 'Use checker for detailed CPU models', False),
     BoolVariable('CP_ANNOTATE', 'Enable critical path annotation capability', False),
     )
 
     BoolVariable('CP_ANNOTATE', 'Enable critical path annotation capability', False),
     )
 
-nonsticky_vars.AddVariables(
-    BoolVariable('update_ref', 'Update test reference outputs', False)
-    )
-
 # These variables get exported to #defines in config/*.hh (see src/SConscript).
 # These variables get exported to #defines in config/*.hh (see src/SConscript).
-export_vars += ['FULL_SYSTEM', 'USE_FENV', 'USE_MYSQL',
-                'NO_FAST_ALLOC', 'FAST_ALLOC_DEBUG', 'FAST_ALLOC_STATS',
-                'SS_COMPATIBLE_FP', 'USE_CHECKER', 'TARGET_ISA', 'CP_ANNOTATE']
+export_vars += ['USE_FENV', 'NO_FAST_ALLOC', 'FORCE_FAST_ALLOC',
+                'FAST_ALLOC_STATS', 'SS_COMPATIBLE_FP',
+                'TARGET_ISA', 'CP_ANNOTATE', 'USE_POSIX_CLOCK' ]
 
 ###################################################
 #
 
 ###################################################
 #
@@ -722,13 +873,8 @@ def build_config_file(target, source, env):
     f.close()
     return None
 
     f.close()
     return None
 
-# Generate the message to be printed when building the config file.
-def build_config_file_string(target, source, env):
-    (variable, value) = [s.get_contents() for s in source]
-    return "Defining %s as %s in %s." % (variable, value, target[0])
-
 # Combine the two functions into a scons Action object.
 # Combine the two functions into a scons Action object.
-config_action = Action(build_config_file, build_config_file_string)
+config_action = MakeAction(build_config_file, Transform("CONFIG H", 2))
 
 # The emitter munges the source & target node lists to reflect what
 # we're really doing.
 
 # The emitter munges the source & target node lists to reflect what
 # we're really doing.
@@ -772,27 +918,16 @@ def make_switching_dir(dname, switch_headers, env):
     # list of ISAs from env['ALL_ISA_LIST'].
     def gen_switch_hdr(target, source, env):
         fname = str(target[0])
     # list of ISAs from env['ALL_ISA_LIST'].
     def gen_switch_hdr(target, source, env):
         fname = str(target[0])
-        bname = basename(fname)
         f = open(fname, 'w')
         f = open(fname, 'w')
-        f.write('#include "arch/isa_specific.hh"\n')
-        cond = '#if'
-        for isa in all_isa_list:
-            f.write('%s THE_ISA == %s_ISA\n#include "%s/%s/%s"\n'
-                    % (cond, isa.upper(), dname, isa, bname))
-            cond = '#elif'
-        f.write('#else\n#error "THE_ISA not set"\n#endif\n')
+        isa = env['TARGET_ISA'].lower()
+        print >>f, '#include "%s/%s/%s"' % (dname, isa, basename(fname))
         f.close()
         f.close()
-        return 0
-
-    # String to print when generating header
-    def gen_switch_hdr_string(target, source, env):
-        return "Generating switch header " + str(target[0])
 
     # Build SCons Action object. 'varlist' specifies env vars that this
     # action depends on; when env['ALL_ISA_LIST'] changes these actions
     # should get re-executed.
 
     # Build SCons Action object. 'varlist' specifies env vars that this
     # action depends on; when env['ALL_ISA_LIST'] changes these actions
     # should get re-executed.
-    switch_hdr_action = Action(gen_switch_hdr, gen_switch_hdr_string,
-                               varlist=['ALL_ISA_LIST'])
+    switch_hdr_action = MakeAction(gen_switch_hdr,
+                          Transform("GENERATE"), varlist=['ALL_ISA_LIST'])
 
     # Instantiate actions for each header
     for hdr in switch_headers:
 
     # Instantiate actions for each header
     for hdr in switch_headers:
@@ -835,26 +970,32 @@ for variant_path in variant_paths:
 
         # Get default build variables from source tree.  Variables are
         # normally determined by name of $VARIANT_DIR, but can be
 
         # Get default build variables from source tree.  Variables are
         # normally determined by name of $VARIANT_DIR, but can be
-        # overriden by 'default=' arg on command line.
-        default_vars_file = joinpath('build_opts',
-                                     ARGUMENTS.get('default', variant_dir))
-        if isfile(default_vars_file):
+        # overridden by '--default=' arg on command line.
+        default = GetOption('default')
+        opts_dir = joinpath(main.root.abspath, 'build_opts')
+        if default:
+            default_vars_files = [joinpath(build_root, 'variables', default),
+                                  joinpath(opts_dir, default)]
+        else:
+            default_vars_files = [joinpath(opts_dir, variant_dir)]
+        existing_files = filter(isfile, default_vars_files)
+        if existing_files:
+            default_vars_file = existing_files[0]
             sticky_vars.files.append(default_vars_file)
             print "Variables file %s not found,\n  using defaults in %s" \
                   % (current_vars_file, default_vars_file)
         else:
             sticky_vars.files.append(default_vars_file)
             print "Variables file %s not found,\n  using defaults in %s" \
                   % (current_vars_file, default_vars_file)
         else:
-            print "Error: cannot find variables file %s or %s" \
-                  % (current_vars_file, default_vars_file)
+            print "Error: cannot find variables file %s or " \
+                  "default file(s) %s" \
+                  % (current_vars_file, ' or '.join(default_vars_files))
             Exit(1)
 
     # Apply current variable settings to env
     sticky_vars.Update(env)
             Exit(1)
 
     # Apply current variable settings to env
     sticky_vars.Update(env)
-    nonsticky_vars.Update(env)
 
 
-    help_text += "\nSticky variables for %s:\n" % variant_dir \
-                 + sticky_vars.GenerateHelpText(env) \
-                 + "\nNon-sticky variables for %s:\n" % variant_dir \
-                 + nonsticky_vars.GenerateHelpText(env)
+    help_texts["local_vars"] += \
+        "Build variables for %s:\n" % variant_dir \
+                 + sticky_vars.GenerateHelpText(env)
 
     # Process variable settings.
 
 
     # Process variable settings.
 
@@ -870,21 +1011,11 @@ for variant_path in variant_paths:
     if env['EFENCE']:
         env.Append(LIBS=['efence'])
 
     if env['EFENCE']:
         env.Append(LIBS=['efence'])
 
-    if env['USE_MYSQL']:
-        if not have_mysql:
-            print "Warning: MySQL not available; " \
-                  "forcing USE_MYSQL to False in", variant_dir + "."
-            env['USE_MYSQL'] = False
-        else:
-            print "Compiling in", variant_dir, "with MySQL support."
-            env.ParseConfig(mysql_config_libs)
-            env.ParseConfig(mysql_config_include)
-
     # Save sticky variable settings back to current variables file
     sticky_vars.Save(current_vars_file, env)
 
     if env['USE_SSE2']:
     # Save sticky variable settings back to current variables file
     sticky_vars.Save(current_vars_file, env)
 
     if env['USE_SSE2']:
-        env.Append(CCFLAGS='-msse2')
+        env.Append(CCFLAGS=['-msse2'])
 
     # The src/SConscript file sets up the build rules in 'env' according
     # to the configured variables.  It returns a list of environments,
 
     # The src/SConscript file sets up the build rules in 'env' according
     # to the configured variables.  It returns a list of environments,
@@ -898,4 +1029,15 @@ for variant_path in variant_paths:
                    variant_dir = joinpath(variant_path, 'tests', e.Label),
                    exports = { 'env' : e }, duplicate = False)
 
                    variant_dir = joinpath(variant_path, 'tests', e.Label),
                    exports = { 'env' : e }, duplicate = False)
 
-Help(help_text)
+# base help text
+Help('''
+Usage: scons [scons options] [build variables] [target(s)]
+
+Extra scons options:
+%(options)s
+
+Global build variables:
+%(global_vars)s
+
+%(local_vars)s
+''' % help_texts)