tests: arch-power: Add 64-bit hello binaries
[gem5.git] / SConstruct
index 9a382102cc2c4d744504ebce966f6aa4a295365a..210f813646e6583435b2e1135a5f7e882f7ad8c9 100755 (executable)
@@ -1,6 +1,6 @@
 # -*- mode:python -*-
 
-# Copyright (c) 2013, 2015-2019 ARM Limited
+# Copyright (c) 2013, 2015-2020 ARM Limited
 # All rights reserved.
 #
 # The license below extends only to copyright in the software and shall
@@ -39,9 +39,6 @@
 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# Authors: Steve Reinhardt
-#          Nathan Binkert
 
 ###################################################
 #
@@ -49,7 +46,7 @@
 #
 # While in this directory ('gem5'), just type 'scons' to build the default
 # configuration (see below), or type 'scons build/<CONFIG>/<binary>'
-# to build some other configuration (e.g., 'build/ALPHA/gem5.opt' for
+# to build some other configuration (e.g., 'build/X86/gem5.opt' for
 # the optimized full-system version).
 #
 # You can build gem5 in a different directory as long as there is a
 #
 #   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>/gem5 ; scons build/ALPHA/gem5.debug
-#   % cd <path-to-src>/gem5/build/ALPHA; scons -u gem5.debug
+#   % cd <path-to-src>/gem5 ; scons build/X86/gem5.debug
+#   % cd <path-to-src>/gem5/build/X86; 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.
-#   % 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
+#   % cd <path-to-src>/gem5 ; scons /local/foo/build/X86/gem5.debug
+#   % cd /local/foo/build/X86; scons -C <path-to-src>/gem5 gem5.debug
 #
 # You can use 'scons -H' to print scons options.  If you're in this
 # 'gem5' directory (or use -u or -C to tell scons where to find this
@@ -78,9 +75,8 @@
 #
 ###################################################
 
-from __future__ import print_function
-
 # Global Python includes
+import atexit
 import itertools
 import os
 import re
@@ -99,80 +95,38 @@ import SCons
 import SCons.Node
 import SCons.Node.FS
 
-from m5.util import compareVersions, readCommand
-
-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:
-            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('--with-cxx-config', dest='with_cxx_config',
-               action='store_true',
-               help="Build with support for C++-based configuration")
-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('--gold-linker', dest='gold_linker', action='store_true',
-               help='Use the gold linker')
-AddLocalOption('--no-lto', dest='no_lto', action='store_true',
-               help='Disable Link-Time Optimization for fast')
-AddLocalOption('--force-lto', dest='force_lto', action='store_true',
-               help='Use Link-Time Optimization instead of partial linking' +
-                    ' when the compiler doesn\'t support using them together.')
-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')
-AddLocalOption('--without-python', dest='without_python',
-               action='store_true',
-               help='Build without Python configuration support')
-AddLocalOption('--without-tcmalloc', dest='without_tcmalloc',
-               action='store_true',
-               help='Disable linking against tcmalloc')
-AddLocalOption('--with-ubsan', dest='with_ubsan', action='store_true',
-               help='Build with Undefined Behavior Sanitizer if available')
-AddLocalOption('--with-asan', dest='with_asan', action='store_true',
-               help='Build with Address Sanitizer if available')
-
-from gem5_scons import Transform, error, warning
-
-if GetOption('no_lto') and GetOption('force_lto'):
-    error('--no-lto and --force-lto are mutually exclusive')
+from m5.util import compareVersions, readCommand, readCommandWithReturn
+
+AddOption('--colors', dest='use_colors', action='store_true',
+          help="Add color to abbreviated scons output")
+AddOption('--no-colors', dest='use_colors', action='store_false',
+          help="Don't add color to abbreviated scons output")
+AddOption('--with-cxx-config', action='store_true',
+          help="Build with support for C++-based configuration")
+AddOption('--default',
+          help='Override which build_opts file to use for defaults')
+AddOption('--ignore-style', action='store_true',
+          help='Disable style checking hooks')
+AddOption('--gold-linker', action='store_true', help='Use the gold linker')
+AddOption('--no-compress-debug', action='store_true',
+          help="Don't compress debug info in build files")
+AddOption('--no-lto', action='store_true',
+          help='Disable Link-Time Optimization for fast')
+AddOption('--verbose', action='store_true',
+          help='Print full tool command lines')
+AddOption('--without-python', action='store_true',
+          help='Build without Python configuration support')
+AddOption('--without-tcmalloc', action='store_true',
+          help='Disable linking against tcmalloc')
+AddOption('--with-ubsan', action='store_true',
+          help='Build with Undefined Behavior Sanitizer if available')
+AddOption('--with-asan', action='store_true',
+          help='Build with Address Sanitizer if available')
+AddOption('--with-systemc-tests', action='store_true',
+          help='Build systemc tests')
+
+from gem5_scons import Transform, error, warning, summarize_warnings
+import gem5_scons
 
 ########################################################################
 #
@@ -180,7 +134,7 @@ if GetOption('no_lto') and GetOption('force_lto'):
 #
 ########################################################################
 
-main = Environment()
+main = Environment(tools=['default', 'git'])
 
 from gem5_scons.util import get_termcap
 termcap = get_termcap()
@@ -199,14 +153,14 @@ if not ('CC' in main_dict_keys and 'CXX' in main_dict_keys):
 ###################################################
 
 # Find default configuration & binary.
-Default(environ.get('M5_DEFAULT_BINARY', 'build/ALPHA/gem5.debug'))
+Default(environ.get('M5_DEFAULT_BINARY', 'build/ARM/gem5.debug'))
 
 # helper function: find last occurrence of element in list
 def rfind(l, elt, offs = -1):
     for i in range(len(l)+offs, 0, -1):
         if l[i] == elt:
             return i
-    raise ValueError, "element not found"
+    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
@@ -215,23 +169,10 @@ def makePathListAbsolute(path_list, root=GetLaunchDir()):
     return [abspath(joinpath(root, expanduser(str(p))))
             for p in path_list]
 
-def find_first_prog(prog_names):
-    """Find the absolute path to the first existing binary in prog_names"""
-
-    if not isinstance(prog_names, (list, tuple)):
-        prog_names = [ prog_names ]
-
-    for p in prog_names:
-        p = main.WhereIs(p)
-        if p is not None:
-            return p
-
-    return None
-
 # 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
+# example, for target 'foo/bar/build/X86/arch/x86/blah.do' we
+# recognize that X86 specifies the configuration because it
 # follow 'build' in the build path.
 
 # The funky assignment to "[:]" is needed to replace the list contents
@@ -277,7 +218,7 @@ main.SetOption('duplicate', 'soft-copy')
 
 #
 # Set up global sticky variables... these are common to an entire build
-# tree (not specific to a particular build like ALPHA_SE)
+# tree (not specific to a particular build like X86)
 #
 
 global_vars_file = joinpath(build_root, 'variables.global')
@@ -289,8 +230,11 @@ global_vars.AddVariables(
     ('CXX', 'C++ compiler', environ.get('CXX', main['CXX'])),
     ('CCFLAGS_EXTRA', 'Extra C and C++ compiler flags', ''),
     ('LDFLAGS_EXTRA', 'Extra linker flags', ''),
+    ('MARSHAL_CCFLAGS_EXTRA', 'Extra C and C++ marshal compiler flags', ''),
+    ('MARSHAL_LDFLAGS_EXTRA', 'Extra marshal linker flags', ''),
     ('PYTHON_CONFIG', 'Python config binary to use',
-     [ 'python2.7-config', 'python-config' ]),
+     [ 'python3-config', 'python-config']
+    ),
     ('PROTOC', 'protoc tool', environ.get('PROTOC', 'protoc')),
     ('BATCH', 'Use batch pool for build and tests', False),
     ('BATCH_CMD', 'Batch pool submission command name', 'qdo'),
@@ -300,14 +244,17 @@ global_vars.AddVariables(
 
 # Update main environment with values from ARGUMENTS & global_vars_file
 global_vars.Update(main)
-help_texts["global_vars"] += global_vars.GenerateHelpText(main)
+Help('''
+Global build variables:
+{help}
+'''.format(help=global_vars.GenerateHelpText(main)), append=True)
 
 # Save sticky variable settings back to current variables file
 global_vars.Save(global_vars_file, main)
 
 # Parse EXTRAS variable to build list of all directories where we're
 # look for sources etc.  This list is exported as extras_dir_list.
-base_dir = main.srcdir.abspath
+base_dir = Dir('#src').abspath
 if main['EXTRAS']:
     extras_dir_list = makePathListAbsolute(main['EXTRAS'].split(':'))
 else:
@@ -349,6 +296,10 @@ main['LTO_LDFLAGS'] = []
 # compiler we're using.
 main['TCMALLOC_CCFLAGS'] = []
 
+# Platform-specific configuration.  Note again that we assume that all
+# builds under a given build root run on the same host platform.
+conf = gem5_scons.Configure(main)
+
 CXX_version = readCommand([main['CXX'],'--version'], exception=False)
 CXX_V = readCommand([main['CXX'],'-V'], exception=False)
 
@@ -366,20 +317,15 @@ if main['GCC'] or main['CLANG']:
     # we consistently violate
     main.Append(CCFLAGS=['-Wall', '-Wundef', '-Wextra',
                          '-Wno-sign-compare', '-Wno-unused-parameter'])
-    # We always compile using C++11
-    main.Append(CXXFLAGS=['-std=c++11'])
+    # We always compile using C++14
+    main.Append(CXXFLAGS=['-std=c++14'])
     if sys.platform.startswith('freebsd'):
         main.Append(CCFLAGS=['-I/usr/local/include'])
         main.Append(CXXFLAGS=['-I/usr/local/include'])
 
-    main['FILTER_PSHLINKFLAGS'] = lambda x: str(x).replace(' -shared', '')
-    main['PSHLINKFLAGS'] = main.subst('${FILTER_PSHLINKFLAGS(SHLINKFLAGS)}')
+    conf.CheckLinkFlag('-Wl,--as-needed')
     if GetOption('gold_linker'):
         main.Append(LINKFLAGS='-fuse-ld=gold')
-    main['PLINKFLAGS'] = main.subst('${LINKFLAGS}')
-    shared_partial_flags = ['-r', '-nostdlib']
-    main.Append(PSHLINKFLAGS=shared_partial_flags)
-    main.Append(PLINKFLAGS=shared_partial_flags)
 
     # Treat warnings as errors but white list some warnings that we
     # want to allow (e.g., deprecation warnings).
@@ -388,7 +334,7 @@ if main['GCC'] or main['CLANG']:
                          '-Wno-error=deprecated',
                         ])
 else:
-    error('\n'.join(
+    error('\n'.join((
           "Don't know what compiler options to use for your compiler.",
           "compiler: " + main['CXX'],
           "version: " + CXX_version.replace('\n', '<nl>') if
@@ -399,61 +345,21 @@ else:
           "",
           "If you are trying to use a compiler other than those listed",
           "above you will need to ease fix SConstruct and ",
-          "src/SConscript to support that compiler."))
+          "src/SConscript to support that compiler.")))
 
 if main['GCC']:
-    # Check for a supported version of gcc. >= 4.8 is chosen for its
-    # level of c++11 support. See
-    # http://gcc.gnu.org/projects/cxx0x.html for details.
     gcc_version = readCommand([main['CXX'], '-dumpversion'], exception=False)
-    if compareVersions(gcc_version, "4.8") < 0:
-        error('gcc version 4.8 or newer required.\n'
+    if compareVersions(gcc_version, "5") < 0:
+        error('gcc version 5 or newer required.\n'
               'Installed version:', gcc_version)
         Exit(1)
 
     main['GCC_VERSION'] = gcc_version
 
-    if compareVersions(gcc_version, '4.9') >= 0:
-        # Incremental linking with LTO is currently broken in gcc versions
-        # 4.9 and above. A version where everything works completely hasn't
-        # yet been identified.
-        #
-        # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67548
-        main['BROKEN_INCREMENTAL_LTO'] = True
-    if compareVersions(gcc_version, '6.0') >= 0:
-        # gcc versions 6.0 and greater accept an -flinker-output flag which
-        # selects what type of output the linker should generate. This is
-        # necessary for incremental lto to work, but is also broken in
-        # current versions of gcc. It may not be necessary in future
-        # versions. We add it here since it might be, and as a reminder that
-        # it exists. It's excluded if lto is being forced.
-        #
-        # https://gcc.gnu.org/gcc-6/changes.html
-        # https://gcc.gnu.org/ml/gcc-patches/2015-11/msg03161.html
-        # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69866
-        if not GetOption('force_lto'):
-            main.Append(PSHLINKFLAGS='-flinker-output=rel')
-            main.Append(PLINKFLAGS='-flinker-output=rel')
-
-    # Make sure we warn if the user has requested to compile with the
-    # Undefined Benahvior Sanitizer and this version of gcc does not
-    # support it.
-    if GetOption('with_ubsan') and compareVersions(gcc_version, '4.9') < 0:
-        warning('UBSan is only supported using gcc 4.9 and later.')
-
-    disable_lto = GetOption('no_lto')
-    if not disable_lto and main.get('BROKEN_INCREMENTAL_LTO', False) and \
-            not GetOption('force_lto'):
-        warning('Warning: Your compiler doesn\'t support incremental linking '
-                'and lto at the same time, so lto is being disabled. To force '
-                'lto on anyway, use the --force-lto option. That will disable '
-                'partial linking.')
-        disable_lto = True
-
     # Add the appropriate Link-Time Optimization (LTO) flags
     # unless LTO is explicitly turned off. Note that these flags
     # are only used by the fast target.
-    if not disable_lto:
+    if not GetOption('no_lto'):
         # Pass the LTO flag when compiling to produce GIMPLE
         # output, we merely create the flags here and only append
         # them later
@@ -466,35 +372,13 @@ if main['GCC']:
     main.Append(TCMALLOC_CCFLAGS=['-fno-builtin-malloc', '-fno-builtin-calloc',
                                   '-fno-builtin-realloc', '-fno-builtin-free'])
 
-    # The address sanitizer is available for gcc >= 4.8
-    if GetOption('with_asan'):
-        if GetOption('with_ubsan') and \
-                compareVersions(main['GCC_VERSION'], '4.9') >= 0:
-            main.Append(CCFLAGS=['-fsanitize=address,undefined',
-                                 '-fno-omit-frame-pointer'],
-                        LINKFLAGS='-fsanitize=address,undefined')
-        else:
-            main.Append(CCFLAGS=['-fsanitize=address',
-                                 '-fno-omit-frame-pointer'],
-                        LINKFLAGS='-fsanitize=address')
-    # Only gcc >= 4.9 supports UBSan, so check both the version
-    # and the command-line option before adding the compiler and
-    # linker flags.
-    elif GetOption('with_ubsan') and \
-            compareVersions(main['GCC_VERSION'], '4.9') >= 0:
-        main.Append(CCFLAGS='-fsanitize=undefined')
-        main.Append(LINKFLAGS='-fsanitize=undefined')
-
 elif main['CLANG']:
-    # Check for a supported version of clang, >= 3.1 is needed to
-    # support similar features as gcc 4.8. See
-    # http://clang.llvm.org/cxx_status.html for details
     clang_version_re = re.compile(".* version (\d+\.\d+)")
     clang_version_match = clang_version_re.search(CXX_version)
     if (clang_version_match):
         clang_version = clang_version_match.groups()[0]
-        if compareVersions(clang_version, "3.1") < 0:
-            error('clang version 3.1 or newer required.\n'
+        if compareVersions(clang_version, "3.9") < 0:
+            error('clang version 3.9 or newer required.\n'
                   'Installed version:', clang_version)
     else:
         error('Unable to determine clang version.')
@@ -510,6 +394,8 @@ elif main['CLANG']:
                          # interchangeably.
                          '-Wno-mismatched-tags',
                          ])
+    conf.CheckCxxFlag('-Wno-c99-designator')
+    conf.CheckCxxFlag('-Wno-defaulted-function-deleted')
 
     main.Append(TCMALLOC_CCFLAGS=['-fno-builtin'])
 
@@ -523,21 +409,33 @@ elif main['CLANG']:
     if sys.platform.startswith('freebsd'):
         main.Append(LIBS=['thr'])
 
-    # We require clang >= 3.1, so there is no need to check any
-    # versions here.
-    if GetOption('with_ubsan'):
-        if GetOption('with_asan'):
-            main.Append(CCFLAGS=['-fsanitize=address,undefined',
-                                 '-fno-omit-frame-pointer'],
-                       LINKFLAGS='-fsanitize=address,undefined')
-        else:
-            main.Append(CCFLAGS='-fsanitize=undefined',
-                        LINKFLAGS='-fsanitize=undefined')
-
-    elif GetOption('with_asan'):
-        main.Append(CCFLAGS=['-fsanitize=address',
+# Add sanitizers flags
+sanitizers=[]
+if GetOption('with_ubsan'):
+    sanitizers.append('undefined')
+if GetOption('with_asan'):
+    # Available for gcc >= 5 or llvm >= 3.1 both a requirement
+    # by the build system
+    sanitizers.append('address')
+    suppressions_file = Dir('util').File('lsan-suppressions').get_abspath()
+    suppressions_opt = 'suppressions=%s' % suppressions_file
+    main['ENV']['LSAN_OPTIONS'] = ':'.join([suppressions_opt,
+                                            'print_suppressions=0'])
+    print()
+    warning('To suppress false positive leaks, set the LSAN_OPTIONS '
+            'environment variable to "%s" when running gem5' %
+            suppressions_opt)
+    warning('LSAN_OPTIONS=suppressions=%s' % suppressions_opt)
+    print()
+if sanitizers:
+    sanitizers = ','.join(sanitizers)
+    if main['GCC'] or main['CLANG']:
+        main.Append(CCFLAGS=['-fsanitize=%s' % sanitizers,
                              '-fno-omit-frame-pointer'],
-                   LINKFLAGS='-fsanitize=address')
+                    LINKFLAGS='-fsanitize=%s' % sanitizers)
+    else:
+        warning("Don't know how to enable %s sanitizer(s) for your "
+                "compiler." % sanitizers)
 
 # Set up common yacc/bison flags (needed for Ruby)
 main['YACCFLAGS'] = '-d'
@@ -557,127 +455,50 @@ if sys.platform == 'cygwin':
     main.Append(CCFLAGS=["-Wno-uninitialized"])
 
 
-have_pkg_config = readCommand(['pkg-config', '--version'], exception='')
+have_pkg_config = main.Detect('pkg-config')
 
 # Check for the protobuf compiler
+main['HAVE_PROTOC'] = False
+protoc_version = []
 try:
-    main['HAVE_PROTOC'] = True
     protoc_version = readCommand([main['PROTOC'], '--version']).split()
-
-    # First two words should be "libprotoc x.y.z"
-    if len(protoc_version) < 2 or protoc_version[0] != 'libprotoc':
-        warning('Protocol buffer compiler (protoc) not found.\n'
-                'Please install protobuf-compiler for tracing support.')
-        main['HAVE_PROTOC'] = False
-    else:
-        # Based on the availability of the compress stream wrappers,
-        # require 2.1.0
-        min_protoc_version = '2.1.0'
-        if compareVersions(protoc_version[1], min_protoc_version) < 0:
-            warning('protoc version', min_protoc_version,
-                    'or newer required.\n'
-                    'Installed version:', protoc_version[1])
-            main['HAVE_PROTOC'] = False
-        else:
-            # Attempt to determine the appropriate include path and
-            # library path using pkg-config, that means we also need to
-            # check for pkg-config. Note that it is possible to use
-            # protobuf without the involvement of pkg-config. Later on we
-            # check go a library config check and at that point the test
-            # will fail if libprotobuf cannot be found.
-            if have_pkg_config:
-                try:
-                    # Attempt to establish what linking flags to add for
-                    # protobuf
-                    # using pkg-config
-                    main.ParseConfig(
-                            'pkg-config --cflags --libs-only-L protobuf')
-                except:
-                    warning('pkg-config could not get protobuf flags.')
 except Exception as e:
     warning('While checking protoc version:', str(e))
-    main['HAVE_PROTOC'] = False
-
-# Check for 'timeout' from GNU coreutils. If present, regressions will
-# be run with a time limit. We require version 8.13 since we rely on
-# support for the '--foreground' option.
-if sys.platform.startswith('freebsd'):
-    timeout_lines = readCommand(['gtimeout', '--version'],
-                                exception='').splitlines()
+
+# Based on the availability of the compress stream wrappers, require 2.1.0.
+min_protoc_version = '2.1.0'
+
+# First two words should be "libprotoc x.y.z"
+if len(protoc_version) < 2 or protoc_version[0] != 'libprotoc':
+    warning('Protocol buffer compiler (protoc) not found.\n'
+            'Please install protobuf-compiler for tracing support.')
+elif compareVersions(protoc_version[1], min_protoc_version) < 0:
+    warning('protoc version', min_protoc_version, 'or newer required.\n'
+            'Installed version:', protoc_version[1])
 else:
-    timeout_lines = readCommand(['timeout', '--version'],
-                                exception='').splitlines()
-# Get the first line and tokenize it
-timeout_version = timeout_lines[0].split() if timeout_lines else []
-main['TIMEOUT'] =  timeout_version and \
-    compareVersions(timeout_version[-1], '8.13') >= 0
-
-# Add a custom Check function to test for structure members.
-def CheckMember(context, include, decl, member, include_quotes="<>"):
-    context.Message("Checking for member %s in %s..." %
-                    (member, decl))
-    text = """
-#include %(header)s
-int main(){
-  %(decl)s test;
-  (void)test.%(member)s;
-  return 0;
-};
-""" % { "header" : include_quotes[0] + include + include_quotes[1],
-        "decl" : decl,
-        "member" : member,
-        }
-
-    ret = context.TryCompile(text, extension=".cc")
-    context.Result(ret)
-    return ret
+    # Attempt to determine the appropriate include path and
+    # library path using pkg-config, that means we also need to
+    # check for pkg-config. Note that it is possible to use
+    # protobuf without the involvement of pkg-config. Later on we
+    # check go a library config check and at that point the test
+    # will fail if libprotobuf cannot be found.
+    if have_pkg_config:
+        conf.CheckPkgConfig('protobuf', '--cflags', '--libs-only-L')
+    main['HAVE_PROTOC'] = True
 
-# Platform-specific configuration.  Note again that we assume that all
-# builds under a given build root run on the same host platform.
-conf = Configure(main,
-                 conf_dir = joinpath(build_root, '.scons_config'),
-                 log_file = joinpath(build_root, 'scons_config.log'),
-                 custom_tests = {
-        'CheckMember' : CheckMember,
-        })
-
-# Check if we should compile a 64 bit binary on Mac OS X/Darwin
-try:
-    import platform
-    uname = platform.uname()
-    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
 
-# Recent versions of scons substitute a "Null" object for Configure()
-# when configuration isn't necessary, e.g., if the "--help" option is
-# present.  Unfortuantely this Null object always returns false,
-# breaking all our configuration checks.  We replace it with our own
-# more optimistic null object that returns True instead.
-if not conf:
-    def NullCheck(*args, **kwargs):
-        return True
-
-    class NullConf:
-        def __init__(self, env):
-            self.env = env
-        def Finish(self):
-            return self.env
-        def __getattr__(self, mname):
-            return NullCheck
-
-    conf = NullConf(main)
 
 # 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'])
 
+if not GetOption('no_compress_debug'):
+    if not conf.CheckCxxFlag('-gz'):
+        warning("Can't enable object file debug section compression")
+    if not conf.CheckLinkFlag('-gz'):
+        warning("Can't enable executable debug section compression")
+
 main['USE_PYTHON'] = not GetOption('without_python')
 if main['USE_PYTHON']:
     # Find Python include and library directories for embedding the
@@ -688,24 +509,40 @@ if main['USE_PYTHON']:
     # version of python, see above for instructions on how to invoke
     # scons with the appropriate PATH set.
 
-    python_config = find_first_prog(main['PYTHON_CONFIG'])
+    python_config = main.Detect(main['PYTHON_CONFIG'])
     if python_config is None:
         error("Can't find a suitable python-config, tried %s" % \
               main['PYTHON_CONFIG'])
 
     print("Info: Using Python config: %s" % (python_config, ))
+
     py_includes = readCommand([python_config, '--includes'],
                               exception='').split()
-    py_includes = filter(lambda s: match(r'.*\/include\/.*',s), py_includes)
+    py_includes = list(filter(
+        lambda s: match(r'.*\/include\/.*',s), py_includes))
     # Strip the -I from the include folders before adding them to the
     # CPPPATH
-    py_includes = map(lambda s: s[2:] if s.startswith('-I') else s, py_includes)
+    py_includes = list(map(
+        lambda s: s[2:] if s.startswith('-I') else s, py_includes))
     main.Append(CPPPATH=py_includes)
 
     # Read the linker flags and split them into libraries and other link
     # flags. The libraries are added later through the call the CheckLib.
-    py_ld_flags = readCommand([python_config, '--ldflags'],
-        exception='').split()
+    # Note: starting in Python 3.8 the --embed flag is required to get the
+    # -lpython3.8 linker flag
+    retcode, cmd_stdout = readCommandWithReturn(
+        [python_config, '--ldflags', '--embed'], exception='')
+    if retcode != 0:
+        # If --embed isn't detected then we're running python <3.8
+        retcode, cmd_stdout = readCommandWithReturn(
+            [python_config, '--ldflags'], exception='')
+
+    # Checking retcode again
+    if retcode != 0:
+        error("Failing on python-config --ldflags command")
+
+    py_ld_flags = cmd_stdout.split()
+
     py_libs = []
     for lib in py_ld_flags:
          if not lib.startswith('-l'):
@@ -717,7 +554,8 @@ if main['USE_PYTHON']:
 
     # verify that this stuff works
     if not conf.CheckHeader('Python.h', '<>'):
-        error("Check failed for Python.h header in", py_includes, "\n"
+        error("Check failed for Python.h header in",
+                ' '.join(py_includes), "\n"
               "Two possible reasons:\n"
               "1. Python headers are not installed (You can install the "
               "package python-dev on Ubuntu and RedHat)\n"
@@ -729,11 +567,30 @@ if main['USE_PYTHON']:
         if not conf.CheckLib(lib):
             error("Can't find library %s required by python." % lib)
 
+    main.Prepend(CPPPATH=Dir('ext/pybind11/include/'))
+
+    marshal_env = main.Clone()
+
+    # Bare minimum environment that only includes python
+    marshal_env.Append(CCFLAGS='$MARSHAL_CCFLAGS_EXTRA')
+    marshal_env.Append(LINKFLAGS='$MARSHAL_LDFLAGS_EXTRA')
+
+    py_version = conf.CheckPythonLib()
+    if not py_version:
+        error("Can't find a working Python installation")
+
+    # Found a working Python installation. Check if it meets minimum
+    # requirements.
+    if py_version[0] < 3 or \
+    (py_version[0] == 3 and py_version[1] < 6):
+        error('Python version too old. Version 3.6 or newer is required.')
+    elif py_version[0] > 3:
+        warning('Python version too new. Python 3 expected.')
+
 # On Solaris you need to use libsocket for socket ops
-if not conf.CheckLibWithHeader(None, 'sys/socket.h', 'C++', 'accept(0,0,0);'):
-   if not conf.CheckLibWithHeader('socket', 'sys/socket.h',
-                                  'C++', 'accept(0,0,0);'):
-       error("Can't find library with socket calls (e.g. accept()).")
+if not conf.CheckLibWithHeader(
+        [None, 'socket'], 'sys/socket.h', 'C++', 'accept(0,0,0);'):
+   error("Can't find library with socket calls (e.g. accept()).")
 
 # Check for zlib.  If the check passes, libz will be automatically
 # added to the LIBS environment variable.
@@ -762,10 +619,10 @@ if main['HAVE_PROTOC'] and not main['HAVE_PROTOBUF']:
 
 # 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',
+    conf.CheckLibWithHeader([None, 'rt'], 'time.h', 'C',
                             'clock_nanosleep(0,0,NULL,NULL);')
+if not have_posix_clock:
+    warning("Can't find library for POSIX clocks.")
 
 have_posix_timers = \
     conf.CheckLibWithHeader([None, 'rt'], [ 'time.h', 'signal.h' ], 'C',
@@ -782,27 +639,13 @@ if not GetOption('without_tcmalloc'):
                 "on Ubuntu or RedHat).")
 
 
-# Detect back trace implementations. The last implementation in the
-# list will be used by default.
-backtrace_impls = [ "none" ]
-
-backtrace_checker = 'char temp;' + \
-    ' backtrace_symbols_fd((void*)&temp, 0, 0);'
-if conf.CheckLibWithHeader(None, 'execinfo.h', 'C', backtrace_checker):
-    backtrace_impls.append("glibc")
-elif conf.CheckLibWithHeader('execinfo', 'execinfo.h', 'C',
-                             backtrace_checker):
-    # NetBSD and FreeBSD need libexecinfo.
-    backtrace_impls.append("glibc")
-    main.Append(LIBS=['execinfo'])
-
-if backtrace_impls[-1] == "none":
-    default_backtrace_impl = "none"
+if conf.CheckLibWithHeader([None, 'execinfo'], 'execinfo.h', 'C',
+        'char temp; backtrace_symbols_fd((void *)&temp, 0, 0);'):
+    main['BACKTRACE_IMPL'] = 'glibc'
+else:
+    main['BACKTRACE_IMPL'] = 'none'
     warning("No suitable back trace implementation found.")
 
-if not have_posix_clock:
-    warning("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:
@@ -831,39 +674,26 @@ have_tuntap = conf.CheckHeader('linux/if_tun.h', '<>')
 if not have_tuntap:
     print("Info: Compatible header file <linux/if_tun.h> not found.")
 
-# x86 needs support for xsave. We test for the structure here since we
-# won't be able to run new tests by the time we know which ISA we're
-# targeting.
-have_kvm_xsave = conf.CheckTypeSize('struct kvm_xsave',
-                                    '#include <linux/kvm.h>') != 0
-
-# Check if the requested target ISA is compatible with the host
-def is_isa_kvm_compatible(isa):
-    try:
-        import platform
-        host_isa = platform.machine()
-    except:
-        warning("Failed to determine host ISA.")
-        return False
-
-    if not have_posix_timers:
-        warning("Can not enable KVM, host seems to lack support "
-                "for POSIX timers")
-        return False
-
-    if isa == "arm":
-        return host_isa in ( "armv7l", "aarch64" )
-    elif isa == "x86":
-        if host_isa != "x86_64":
-            return False
-
-        if not have_kvm_xsave:
-            warning("KVM on x86 requires xsave support in kernel headers.")
-            return False
+# Determine what ISA KVM can support on this host.
+kvm_isa = None
+host_isa = None
+try:
+    import platform
+    host_isa = platform.machine()
+except:
+    pass
 
-        return True
+if not host_isa:
+    warning("Failed to determine host ISA.")
+elif not have_posix_timers:
+    warning("Cannot enable KVM, host seems to lack support for POSIX timers")
+elif host_isa in ('armv7l', 'aarch64'):
+    kvm_isa = 'arm'
+elif host_isa == 'x86_64':
+    if conf.CheckTypeSize('struct kvm_xsave', '#include <linux/kvm.h>') != 0:
+        kvm_isa = 'x86'
     else:
-        return False
+        warning("KVM on x86 requires xsave support in kernel headers.")
 
 
 # Check if the exclude_host attribute is available. We want this to
@@ -871,42 +701,25 @@ def is_isa_kvm_compatible(isa):
 main['HAVE_PERF_ATTR_EXCLUDE_HOST'] = conf.CheckMember(
     'linux/perf_event.h', 'struct perf_event_attr', 'exclude_host')
 
-def check_hdf5():
-    return \
-        conf.CheckLibWithHeader('hdf5', 'hdf5.h', 'C',
-                                'H5Fcreate("", 0, 0, 0);') and \
-        conf.CheckLibWithHeader('hdf5_cpp', 'H5Cpp.h', 'C++',
-                                'H5::H5File("", 0);')
-
-def check_hdf5_pkg(name):
-    print("Checking for %s using pkg-config..." % name, end="")
-    if not have_pkg_config:
-        print(" pkg-config not found")
-        return False
-
-    try:
-        main.ParseConfig('pkg-config --cflags-only-I --libs-only-L %s' % name)
-        print(" yes")
-        return True
-    except:
-        print(" no")
-        return False
-
 # Check if there is a pkg-config configuration for hdf5. If we find
 # it, setup the environment to enable linking and header inclusion. We
 # don't actually try to include any headers or link with hdf5 at this
 # stage.
-if not check_hdf5_pkg('hdf5-serial'):
-    check_hdf5_pkg('hdf5')
+if have_pkg_config:
+    conf.CheckPkgConfig(['hdf5-serial', 'hdf5'],
+            '--cflags-only-I', '--libs-only-L')
 
 # Check if the HDF5 libraries can be found. This check respects the
 # include path and library path provided by pkg-config. We perform
 # this check even if there isn't a pkg-config configuration for hdf5
 # since some installations don't use pkg-config.
-have_hdf5 = check_hdf5()
+have_hdf5 = \
+        conf.CheckLibWithHeader('hdf5', 'hdf5.h', 'C',
+                                'H5Fcreate("", 0, 0, 0);') and \
+        conf.CheckLibWithHeader('hdf5_cpp', 'H5Cpp.h', 'C++',
+                                'H5::H5File("", 0);')
 if not have_hdf5:
-    print("Warning: Couldn't find any HDF5 C++ libraries. Disabling")
-    print("         HDF5 support.")
+    warning("Couldn't find any HDF5 C++ libraries. Disabling HDF5 support.")
 
 ######################################################################
 #
@@ -941,7 +754,7 @@ class CpuModel(object):
 
         # Add self to dict
         if name in CpuModel.dict:
-            raise AttributeError, "CpuModel '%s' already registered" % name
+            raise AttributeError("CpuModel '%s' already registered" % name)
         CpuModel.dict[name] = self
 
 Export('CpuModel')
@@ -981,24 +794,19 @@ all_isa_list.sort()
 all_gpu_isa_list.sort()
 
 sticky_vars.AddVariables(
-    EnumVariable('TARGET_ISA', 'Target ISA', 'alpha', all_isa_list),
-    EnumVariable('TARGET_GPU_ISA', 'Target GPU ISA', 'hsail', all_gpu_isa_list),
+    EnumVariable('TARGET_ISA', 'Target ISA', 'null', all_isa_list),
+    EnumVariable('TARGET_GPU_ISA', 'Target GPU ISA', 'gcn3', all_gpu_isa_list),
     ListVariable('CPU_MODELS', 'CPU models',
-                 sorted(n for n,m in CpuModel.dict.iteritems() if m.default),
+                 sorted(n for n,m in CpuModel.dict.items() if m.default),
                  sorted(CpuModel.dict.keys())),
     BoolVariable('EFENCE', 'Link with Electric Fence malloc debugger',
                  False),
-    BoolVariable('SS_COMPATIBLE_FP',
-                 'Make floating-point results compatible with SimpleScalar',
-                 False),
     BoolVariable('USE_SSE2',
                  'Compile for SSE2 (-msse2) to get IEEE FP on x86 hosts',
                  False),
     BoolVariable('USE_POSIX_CLOCK', 'Use POSIX Clocks', have_posix_clock),
     BoolVariable('USE_FENV', 'Use <fenv.h> IEEE mode control', have_fenv),
     BoolVariable('USE_PNG',  'Enable support for PNG images', have_png),
-    BoolVariable('CP_ANNOTATE', 'Enable critical path annotation capability',
-                 False),
     BoolVariable('USE_KVM', 'Enable hardware virtualized (KVM) CPU models',
                  have_kvm),
     BoolVariable('USE_TUNTAP',
@@ -1007,17 +815,15 @@ sticky_vars.AddVariables(
     BoolVariable('BUILD_GPU', 'Build the compute-GPU model', False),
     EnumVariable('PROTOCOL', 'Coherence protocol for Ruby', 'None',
                   all_protocols),
-    EnumVariable('BACKTRACE_IMPL', 'Post-mortem dump implementation',
-                 backtrace_impls[-1], backtrace_impls),
     ('NUMBER_BITS_PER_SET', 'Max elements in set (default 64)',
                  64),
     BoolVariable('USE_HDF5', 'Enable the HDF5 support', have_hdf5),
     )
 
 # These variables get exported to #defines in config/*.hh (see src/SConscript).
-export_vars += ['USE_FENV', 'SS_COMPATIBLE_FP', 'TARGET_ISA', 'TARGET_GPU_ISA',
-                'CP_ANNOTATE', 'USE_POSIX_CLOCK', 'USE_KVM', 'USE_TUNTAP',
-                'PROTOCOL', 'HAVE_PROTOBUF', 'HAVE_VALGRIND',
+export_vars += ['USE_FENV', 'TARGET_ISA', 'TARGET_GPU_ISA',
+                'USE_POSIX_CLOCK', 'USE_KVM', 'USE_TUNTAP', 'PROTOCOL',
+                'HAVE_PROTOBUF', 'HAVE_VALGRIND',
                 'HAVE_PERF_ATTR_EXCLUDE_HOST', 'USE_PNG',
                 'NUMBER_BITS_PER_SET', 'USE_HDF5']
 
@@ -1032,10 +838,9 @@ export_vars += ['USE_FENV', 'SS_COMPATIBLE_FP', 'TARGET_ISA', 'TARGET_GPU_ISA',
 # operands are the name of the variable and a Value node containing the
 # value of the variable.
 def build_config_file(target, source, env):
-    (variable, value) = [s.get_contents() for s in source]
-    f = file(str(target[0]), 'w')
-    print('#define', variable, value, file=f)
-    f.close()
+    (variable, value) = [s.get_contents().decode('utf-8') for s in source]
+    with open(str(target[0].abspath), 'w') as f:
+        print('#define', variable, value, file=f)
     return None
 
 # Combine the two functions into a scons Action object.
@@ -1047,7 +852,7 @@ def config_emitter(target, source, env):
     # extract variable name from Builder arg
     variable = str(target[0])
     # True target is config header file
-    target = joinpath('config', variable.lower() + '.hh')
+    target = Dir('config').File(variable.lower() + '.hh')
     val = env[variable]
     if isinstance(val, bool):
         # Force value to 0/1
@@ -1056,38 +861,12 @@ def config_emitter(target, source, env):
         val = '"' + val + '"'
 
     # Sources are variable name & value (packaged in SCons Value nodes)
-    return ([target], [Value(variable), Value(val)])
+    return [target], [Value(variable), Value(val)]
 
-config_builder = Builder(emitter = config_emitter, action = config_action)
+config_builder = Builder(emitter=config_emitter, action=config_action)
 
 main.Append(BUILDERS = { 'ConfigFile' : config_builder })
 
-###################################################
-#
-# Builders for static and shared partially linked object files.
-#
-###################################################
-
-partial_static_builder = Builder(action=SCons.Defaults.LinkAction,
-                                 src_suffix='$OBJSUFFIX',
-                                 src_builder=['StaticObject', 'Object'],
-                                 LINKFLAGS='$PLINKFLAGS',
-                                 LIBS='')
-
-def partial_shared_emitter(target, source, env):
-    for tgt in target:
-        tgt.attributes.shared = 1
-    return (target, source)
-partial_shared_builder = Builder(action=SCons.Defaults.ShLinkAction,
-                                 emitter=partial_shared_emitter,
-                                 src_suffix='$SHOBJSUFFIX',
-                                 src_builder='SharedObject',
-                                 SHLINKFLAGS='$PSHLINKFLAGS',
-                                 LIBS='')
-
-main.Append(BUILDERS = { 'PartialShared' : partial_shared_builder,
-                         'PartialStatic' : partial_static_builder })
-
 def add_local_rpath(env, *targets):
     '''Set up an RPATH for a library which lives in the build directory.
 
@@ -1112,7 +891,7 @@ if sys.platform != "darwin":
 main.AddMethod(add_local_rpath, 'AddLocalRPATH')
 
 # builds in ext are shared across all configs in the build root.
-ext_dir = abspath(joinpath(str(main.root), 'ext'))
+ext_dir = Dir('#ext').abspath
 ext_build_dirs = []
 for root, dirs, files in os.walk(ext_dir):
     if 'SConscript' in files:
@@ -1124,8 +903,6 @@ for root, dirs, files in os.walk(ext_dir):
 gdb_xml_dir = joinpath(ext_dir, 'gdb-xml')
 Export('gdb_xml_dir')
 
-main.Prepend(CPPPATH=Dir('ext/pybind11/include/'))
-
 ###################################################
 #
 # This builder and wrapper method are used to set up a directory with
@@ -1174,7 +951,7 @@ for variant_path in variant_paths:
     env['BUILDDIR'] = variant_path
 
     # variant_dir is the tail component of build path, and is used to
-    # determine the build parameters (e.g., 'ALPHA_SE')
+    # determine the build parameters (e.g., 'X86')
     (build_root, variant_dir) = splitpath(variant_path)
 
     # Set env variables according to the build directory config.
@@ -1202,13 +979,13 @@ for variant_path in variant_paths:
         # normally determined by name of $VARIANT_DIR, but can be
         # overridden by '--default=' arg on command line.
         default = GetOption('default')
-        opts_dir = joinpath(main.root.abspath, 'build_opts')
+        opts_dir = Dir('#build_opts').abspath
         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)
+        existing_files = list(filter(isfile, default_vars_files))
         if existing_files:
             default_vars_file = existing_files[0]
             sticky_vars.files.append(default_vars_file)
@@ -1222,9 +999,11 @@ for variant_path in variant_paths:
     # Apply current variable settings to env
     sticky_vars.Update(env)
 
-    help_texts["local_vars"] += \
-        "Build variables for %s:\n" % variant_dir \
-                 + sticky_vars.GenerateHelpText(env)
+    Help('''
+Build variables for {dir}:
+{help}
+'''.format(dir=variant_dir, help=sticky_vars.GenerateHelpText(env)),
+         append=True)
 
     # Process variable settings.
 
@@ -1252,9 +1031,9 @@ for variant_path in variant_paths:
         if not have_kvm:
             warning("Can not enable KVM, host seems to lack KVM support")
             env['USE_KVM'] = False
-        elif not is_isa_kvm_compatible(env['TARGET_ISA']):
-            print("Info: KVM support disabled due to unsupported host and "
-                  "target ISA combination")
+        elif kvm_isa != env['TARGET_ISA']:
+            print("Info: KVM for %s not supported on %s host." %
+                  (env['TARGET_ISA'], kvm_isa))
             env['USE_KVM'] = False
 
     if env['USE_TUNTAP']:
@@ -1280,20 +1059,13 @@ for variant_path in variant_paths:
     env.Append(CCFLAGS='$CCFLAGS_EXTRA')
     env.Append(LINKFLAGS='$LDFLAGS_EXTRA')
 
+    exports=['env']
+    if main['USE_PYTHON']:
+        exports.append('marshal_env')
+
     # The src/SConscript file sets up the build rules in 'env' according
     # to the configured variables.  It returns a list of environments,
     # one for each variant build (debug, opt, etc.)
-    SConscript('src/SConscript', variant_dir = variant_path, exports = 'env')
-
-# base help text
-Help('''
-Usage: scons [scons options] [build variables] [target(s)]
-
-Extra scons options:
-%(options)s
-
-Global build variables:
-%(global_vars)s
+    SConscript('src/SConscript', variant_dir=variant_path, exports=exports)
 
-%(local_vars)s
-''' % help_texts)
+atexit.register(summarize_warnings)