# -*- mode:python -*-
+# Copyright (c) 2013 ARM Limited
+# All rights reserved.
+#
+# The license below extends only to copyright in the software and shall
+# not be construed as granting a license to any other intellectual
+# property including but not limited to intellectual property relating
+# to a hardware implementation of the functionality of the software
+# licensed hereunder. You may use the software subject to the license
+# terms below provided that you ensure that this notice is replicated
+# unmodified and in its entirety in all distributions of the software,
+# modified or unmodified, in source code or in binary form.
+#
# 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
"""
raise
-# We ensure the python version early because we have stuff that
-# requires python 2.4
+# We ensure the python version early because because python-config
+# requires python 2.5
try:
- EnsurePythonVersion(2, 4)
+ EnsurePythonVersion(2, 5)
except SystemExit, e:
print """
You can use a non-default installation of the Python interpreter by
-either (1) rearranging your PATH so that scons finds the non-default
-'python' first or (2) explicitly invoking an alternative interpreter
-on the scons script.
+rearranging your PATH so that scons finds the non-default 'python' and
+'python-config' first.
For more details, see:
http://gem5.org/wiki/index.php/Using_a_non-default_Python_installation
raise
# Global Python includes
+import itertools
import os
import re
import subprocess
Dir('src/python').srcnode().abspath, # gem5 includes
Dir('ext/ply').srcnode().abspath, # ply is used by several files
]
-
+
sys.path[1:1] = extra_python_paths
from m5.util import compareVersions, readCommand
+from m5.util.terminal import get_termcap
help_texts = {
"options" : "",
Export("help_texts")
-def AddM5Option(*args, **kwargs):
+
+# 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)
AddOption(*args, **kwargs)
-AddM5Option('--colors', dest='use_colors', action='store_true',
- help="Add color to abbreviated scons output")
-AddM5Option('--no-colors', dest='use_colors', action='store_false',
- help="Don't add color to abbreviated scons output")
-AddM5Option('--default', dest='default', type='string', action='store',
- help='Override which build_opts file to use for defaults')
-AddM5Option('--ignore-style', dest='ignore_style', action='store_true',
- help='Disable style checking hooks')
-AddM5Option('--update-ref', dest='update_ref', action='store_true',
- help='Update test reference outputs')
-AddM5Option('--verbose', dest='verbose', action='store_true',
- help='Print full tool command lines')
-
-use_colors = GetOption('use_colors')
-if use_colors:
- from m5.util.terminal import termcap
-elif use_colors is None:
- # option unspecified; default behavior is to use colors iff isatty
- from m5.util.terminal import tty_termcap as termcap
-else:
- from m5.util.terminal import no_termcap as termcap
+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('--no-lto', dest='no_lto', action='store_true',
+ help='Disable Link-Time Optimization for fast')
+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'))
########################################################################
#
# Set up the main build environment.
#
########################################################################
-use_vars = set([ 'AS', 'AR', 'CC', 'CXX', 'HOME', 'LD_LIBRARY_PATH', 'PATH',
- 'PYTHONPATH', 'RANLIB' ])
+
+# export TERM so that clang reports errors in color
+use_vars = set([ 'AS', 'AR', 'CC', 'CXX', 'HOME', 'LD_LIBRARY_PATH',
+ 'LIBRARY_PATH', 'PATH', 'PKG_CONFIG_PATH', 'PROTOC',
+ 'PYTHONPATH', 'RANLIB', 'SWIG', 'TERM' ])
+
+use_prefixes = [
+ "M5", # M5 configuration (e.g., path to kernels)
+ "DISTCC_", # distcc (distributed compiler wrapper) configuration
+ "CCACHE_", # ccache (caching compiler wrapper) configuration
+ "CCC_", # clang static analyzer configuration
+ ]
use_env = {}
for key,val in os.environ.iteritems():
- if key in use_vars or key.startswith("M5"):
+ if key in use_vars or \
+ any([key.startswith(prefix) for prefix in use_prefixes]):
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_dict_keys = main.Dictionary().keys()
+
+# Check that we have a C/C++ compiler
+if not ('CC' in main_dict_keys and 'CXX' in main_dict_keys):
+ print "No C++ compiler installed (package g++ on Ubuntu and RedHat)"
+ Exit(1)
+
+# Check that swig is present
+if not 'SWIG' in main_dict_keys:
+ print "swig is not installed (package swig on Ubuntu and RedHat)"
+ Exit(1)
+
# add useful python code PYTHONPATH so it can be used by subprocesses
# as well
main.AppendENVPath('PYTHONPATH', extra_python_paths)
global_vars.AddVariables(
('CC', 'C compiler', environ.get('CC', main['CC'])),
('CXX', 'C++ compiler', environ.get('CXX', main['CXX'])),
+ ('SWIG', 'SWIG tool', environ.get('SWIG', main['SWIG'])),
+ ('PROTOC', 'protoc tool', environ.get('PROTOC', 'protoc')),
('BATCH', 'Use batch pool for build and tests', False),
('BATCH_CMD', 'Batch pool submission command name', 'qdo'),
('M5_BUILD_CACHE', 'Cache built objects in this directory', False),
Export('Transform')
+# enable the regression script to use the termcap
+main['TERMCAP'] = termcap
if GetOption('verbose'):
def MakeAction(action, string, *args, **kwargs):
main['SHCXXCOMSTR'] = Transform("SHCXX")
Export('MakeAction')
+# Initialize the Link-Time Optimization (LTO) flags
+main['LTO_CCFLAGS'] = []
+main['LTO_LDFLAGS'] = []
+
+# According to the readme, tcmalloc works best if the compiler doesn't
+# assume that we're using the builtin malloc and friends. These flags
+# are compiler-specific, so we need to set them after we detect which
+# compiler we're using.
+main['TCMALLOC_CCFLAGS'] = []
+
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['CLANG'] = CXX_V and CXX_V.find('clang') >= 0
-if main['GCC'] + main['SUNCC'] + main['ICC'] + main['CLANG'] > 1:
+main['CLANG'] = CXX_version and CXX_version.find('clang') >= 0
+if main['GCC'] + 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']:
+if main['GCC'] or main['CLANG']:
+ # As gcc and clang share many flags, do the common parts here
main.Append(CCFLAGS=['-pipe'])
main.Append(CCFLAGS=['-fno-strict-aliasing'])
+ # Enable -Wall and then disable the few warnings that we
+ # consistently violate
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
+ # We always compile using C++11, but only gcc >= 4.7 and clang 3.1
+ # actually use that name, so we stick with c++0x
+ main.Append(CXXFLAGS=['-std=c++0x'])
+ # Add selected sanity checks from -Wextra
+ main.Append(CXXFLAGS=['-Wmissing-field-initializers',
+ '-Woverloaded-virtual'])
+else:
+ print termcap.Yellow + termcap.Bold + 'Error' + termcap.Normal,
+ print "Don't know what compiler options to use for your compiler."
+ print termcap.Yellow + ' compiler:' + termcap.Normal, main['CXX']
+ print termcap.Yellow + ' version:' + termcap.Normal,
+ if not CXX_version:
+ print termcap.Yellow + termcap.Bold + "COMMAND NOT FOUND!" +\
+ termcap.Normal
+ else:
+ print CXX_version.replace('\n', '<nl>')
+ print " If you're trying to use a compiler other than GCC"
+ print " or clang, there appears to be something wrong with your"
+ print " environment."
+ print " "
+ print " If you are trying to use a compiler other than those listed"
+ print " above you will need to ease fix SConstruct and "
+ print " src/SConscript to support that compiler."
+ Exit(1)
+
+if main['GCC']:
+ # Check for a supported version of gcc. >= 4.6 is chosen for its
+ # level of c++11 support. See
+ # http://gcc.gnu.org/projects/cxx0x.html for details. 4.6 is also
+ # the first version with proper LTO support.
gcc_version = readCommand([main['CXX'], '-dumpversion'], exception=False)
+ if compareVersions(gcc_version, "4.6") < 0:
+ print 'Error: gcc version 4.6 or newer required.'
+ print ' Installed version:', gcc_version
+ Exit(1)
+
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'])
-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'])
+
+ # 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 GetOption('no_lto'):
+ # Pass the LTO flag when compiling to produce GIMPLE
+ # output, we merely create the flags here and only append
+ # them later/
+ main['LTO_CCFLAGS'] = ['-flto=%d' % GetOption('num_jobs')]
+
+ # Use the same amount of jobs for LTO as we are running
+ # scons with, we hardcode the use of the linker plugin
+ # which requires either gold or GNU ld >= 2.21
+ main['LTO_LDFLAGS'] = ['-flto=%d' % GetOption('num_jobs'),
+ '-fuse-linker-plugin']
+
+ main.Append(TCMALLOC_CCFLAGS=['-fno-builtin-malloc', '-fno-builtin-calloc',
+ '-fno-builtin-realloc', '-fno-builtin-free'])
+
elif main['CLANG']:
+ # Check for a supported version of clang, >= 3.0 is needed to
+ # support similar features as gcc 4.6. See
+ # http://clang.llvm.org/cxx_status.html for details
clang_version_re = re.compile(".* version (\d+\.\d+)")
- clang_version_match = clang_version_re.match(CXX_version)
+ clang_version_match = clang_version_re.search(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.'
+ if compareVersions(clang_version, "3.0") < 0:
+ print 'Error: clang version 3.0 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'])
+ # clang has a few additional warnings that we disable,
+ # tautological comparisons are allowed due to unsigned integers
+ # being compared to constants that happen to be 0, and extraneous
+ # parantheses are allowed due to Ruby's printing of the AST,
+ # finally self assignments are allowed as the generated CPU code
+ # is relying on this
+ main.Append(CCFLAGS=['-Wno-tautological-compare',
+ '-Wno-parentheses',
+ '-Wno-self-assign'])
+
+ main.Append(TCMALLOC_CCFLAGS=['-fno-builtin'])
+
+ # On Mac OS X/Darwin we need to also use libc++ (part of XCode) as
+ # opposed to libstdc++, as the later is dated.
+ if sys.platform == "darwin":
+ main.Append(CXXFLAGS=['-stdlib=libc++'])
+ main.Append(LIBS=['c++'])
+
else:
- print 'Error: Don\'t know what compiler options to use for your compiler.'
- print ' Please fix SConstruct and src/SConscript and try again.'
+ print termcap.Yellow + termcap.Bold + 'Error' + termcap.Normal,
+ print "Don't know what compiler options to use for your compiler."
+ print termcap.Yellow + ' compiler:' + termcap.Normal, main['CXX']
+ print termcap.Yellow + ' version:' + termcap.Normal,
+ if not CXX_version:
+ print termcap.Yellow + termcap.Bold + "COMMAND NOT FOUND!" +\
+ termcap.Normal
+ else:
+ print CXX_version.replace('\n', '<nl>')
+ print " If you're trying to use a compiler other than GCC"
+ print " or clang, there appears to be something wrong with your"
+ print " environment."
+ print " "
+ print " If you are trying to use a compiler other than those listed"
+ print " above you will need to ease fix SConstruct and "
+ print " src/SConscript to support that compiler."
Exit(1)
# Set up common yacc/bison flags (needed for Ruby)
# cygwin has some header file issues...
main.Append(CCFLAGS=["-Wno-uninitialized"])
+# Check for the protobuf compiler
+protoc_version = readCommand([main['PROTOC'], '--version'],
+ exception='').split()
+
+# First two words should be "libprotoc x.y.z"
+if len(protoc_version) < 2 or protoc_version[0] != 'libprotoc':
+ print termcap.Yellow + termcap.Bold + \
+ 'Warning: Protocol buffer compiler (protoc) not found.\n' + \
+ ' Please install protobuf-compiler for tracing support.' + \
+ termcap.Normal
+ main['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:
+ print termcap.Yellow + termcap.Bold + \
+ 'Warning: protoc version', min_protoc_version, \
+ 'or newer required.\n' + \
+ ' Installed version:', protoc_version[1], \
+ termcap.Normal
+ main['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 readCommand(['pkg-config', '--version'], exception=''):
+ try:
+ # Attempt to establish what linking flags to add for protobuf
+ # using pkg-config
+ main.ParseConfig('pkg-config --cflags --libs-only-L protobuf')
+ except:
+ print termcap.Yellow + termcap.Bold + \
+ 'Warning: pkg-config could not get protobuf flags.' + \
+ termcap.Normal
+
# Check for SWIG
if not main.has_key('SWIG'):
print 'Error: SWIG utility not found.'
Exit(1)
# Check for appropriate SWIG version
-swig_version = readCommand(('swig', '-version'), exception='').split()
+swig_version = readCommand([main['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)
-min_swig_version = '1.3.28'
+min_swig_version = '2.0.4'
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]
context.Result(ret)
return ret
+# 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
+
# 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 = { 'CheckLeading' : CheckLeading })
+ custom_tests = {
+ 'CheckLeading' : CheckLeading,
+ 'CheckMember' : CheckMember,
+ })
# Check for leading underscores. Don't really need to worry either
# way so don't need to check the return code.
conf = NullConf(main)
-# Find Python include and library directories for embedding the
-# interpreter. For consistency, we will use the same Python
-# installation used to run scons (and thus this script). If you want
-# to link in an alternate version, see above for instructions on how
-# to invoke scons with a different copy of the Python interpreter.
-from distutils import sysconfig
-
-py_getvar = sysconfig.get_config_var
-
-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_includes = [ py_general_include ]
-if py_platform_include != py_general_include:
- py_includes.append(py_platform_include)
-
-py_lib_path = [ py_getvar('LIBDIR') ]
-# add the prefix/lib/pythonX.Y/config dir, but only if there is no
-# shared library in prefix/lib/.
-if not py_getvar('Py_ENABLE_SHARED'):
- py_lib_path.append(py_getvar('LIBPL'))
-
-py_libs = []
-for lib in py_getvar('LIBS').split() + py_getvar('SYSLIBS').split():
- 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)
-
# 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'])
+# Find Python include and library directories for embedding the
+# interpreter. We rely on python-config to resolve the appropriate
+# includes and linker flags. ParseConfig does not seem to understand
+# the more exotic linker flags such as -Xlinker and -export-dynamic so
+# we add them explicitly below. If you want to link in an alternate
+# version of python, see above for instructions on how to invoke
+# scons with the appropriate PATH set.
+#
+# First we check if python2-config exists, else we use python-config
+python_config = readCommand(['which', 'python2-config'], exception='').strip()
+if not os.path.exists(python_config):
+ python_config = readCommand(['which', 'python-config'],
+ exception='').strip()
+py_includes = readCommand([python_config, '--includes'],
+ exception='').split()
+# Strip the -I from the include folders before adding them to the
+# CPPPATH
+main.Append(CPPPATH=map(lambda inc: inc[2:], 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()
+py_libs = []
+for lib in py_ld_flags:
+ if not lib.startswith('-l'):
+ main.Append(LINKFLAGS=[lib])
+ else:
+ lib = lib[2:]
+ if lib not in py_libs:
+ py_libs.append(lib)
# verify that this stuff works
if not conf.CheckHeader('Python.h', '<>'):
print "Error: can't find Python.h header in", py_includes
+ print "Install Python headers (package python-dev on Ubuntu and RedHat)"
Exit(1)
for lib in py_libs:
print ' Please install zlib and try again.'
Exit(1)
+# If we have the protobuf compiler, also make sure we have the
+# development libraries. If the check passes, libprotobuf will be
+# automatically added to the LIBS environment variable. After
+# this, we can use the HAVE_PROTOBUF flag to determine if we have
+# got both protoc and libprotobuf available.
+main['HAVE_PROTOBUF'] = main['PROTOC'] and \
+ conf.CheckLibWithHeader('protobuf', 'google/protobuf/message.h',
+ 'C++', 'GOOGLE_PROTOBUF_VERIFY_VERSION;')
+
+# If we have the compiler but not the library, print another warning.
+if main['PROTOC'] and not main['HAVE_PROTOBUF']:
+ print termcap.Yellow + termcap.Bold + \
+ 'Warning: did not find protocol buffer library and/or headers.\n' + \
+ ' Please install libprotobuf-dev for tracing support.' + \
+ termcap.Normal
+
# Check for librt.
have_posix_clock = \
conf.CheckLibWithHeader(None, 'time.h', 'C',
conf.CheckLibWithHeader('rt', 'time.h', 'C',
'clock_nanosleep(0,0,NULL,NULL);')
+have_posix_timers = \
+ conf.CheckLibWithHeader([None, 'rt'], [ 'time.h', 'signal.h' ], 'C',
+ 'timer_create(CLOCK_MONOTONIC, NULL, NULL);')
+
+if conf.CheckLib('tcmalloc'):
+ main.Append(CCFLAGS=main['TCMALLOC_CCFLAGS'])
+elif conf.CheckLib('tcmalloc_minimal'):
+ main.Append(CCFLAGS=main['TCMALLOC_CCFLAGS'])
+else:
+ print termcap.Yellow + termcap.Bold + \
+ "You can get a 12% performance improvement by installing tcmalloc "\
+ "(libgoogle-perftools-dev package on Ubuntu or RedHat)." + \
+ termcap.Normal
+
if not have_posix_clock:
print "Can't find library for POSIX clocks."
print "Warning: Header file <fenv.h> not found."
print " This host has no IEEE FP rounding mode control."
+# Check if we should enable KVM-based hardware virtualization. The API
+# we rely on exists since version 2.6.36 of the kernel, but somehow
+# the KVM_API_VERSION does not reflect the change. We test for one of
+# the types as a fall back.
+have_kvm = conf.CheckHeader('linux/kvm.h', '<>') and \
+ conf.CheckTypeSize('struct kvm_xsave', '#include <linux/kvm.h>') != 0
+if not have_kvm:
+ print "Info: Compatible header file <linux/kvm.h> not found, " \
+ "disabling KVM support."
+
+# Check if the requested target ISA is compatible with the host
+def is_isa_kvm_compatible(isa):
+ isa_comp_table = {
+ "arm" : ( "armv7l" ),
+ "x86" : ( "x86_64" ),
+ }
+ try:
+ import platform
+ host_isa = platform.machine()
+ except:
+ print "Warning: Failed to determine host ISA."
+ return False
+
+ return host_isa in isa_comp_table.get(isa, [])
+
+
+# Check if the exclude_host attribute is available. We want this to
+# get accurate instruction counts in KVM.
+main['HAVE_PERF_ATTR_EXCLUDE_HOST'] = conf.CheckMember(
+ 'linux/perf_event.h', 'struct perf_event_attr', 'exclude_host')
+
+
######################################################################
#
# Finish the configuration
export_vars = []
Export('export_vars')
+# For Ruby
+all_protocols = []
+Export('all_protocols')
+protocol_dirs = []
+Export('protocol_dirs')
+slicc_includes = []
+Export('slicc_includes')
+
# Walk the tree and execute all SConsopts scripts that wil add to the
# above variables
-if not GetOption('verbose'):
+if GetOption('verbose'):
print "Reading SConsopts"
for bdir in [ base_dir ] + extras_dir_list:
if not isdir(bdir):
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('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',
False),
BoolVariable('SS_COMPATIBLE_FP',
False),
BoolVariable('USE_POSIX_CLOCK', 'Use POSIX Clocks', have_posix_clock),
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('USE_KVM', 'Enable hardware virtualized (KVM) CPU models', have_kvm),
+ EnumVariable('PROTOCOL', 'Coherence protocol for Ruby', 'None',
+ all_protocols),
)
# These variables get exported to #defines in config/*.hh (see src/SConscript).
-export_vars += ['USE_FENV', 'NO_FAST_ALLOC', 'FORCE_FAST_ALLOC',
- 'FAST_ALLOC_STATS', 'SS_COMPATIBLE_FP', 'USE_CHECKER',
- 'TARGET_ISA', 'CP_ANNOTATE', 'USE_POSIX_CLOCK' ]
+export_vars += ['USE_FENV', 'SS_COMPATIBLE_FP', 'TARGET_ISA', 'CP_ANNOTATE',
+ 'USE_POSIX_CLOCK', 'PROTOCOL', 'HAVE_PROTOBUF',
+ 'HAVE_PERF_ATTR_EXCLUDE_HOST']
###################################################
#
main.SConscript('ext/gzstream/SConscript',
variant_dir = joinpath(build_root, 'gzstream'))
+# libfdt build is shared across all configs in the build root.
+main.SConscript('ext/libfdt/SConscript',
+ variant_dir = joinpath(build_root, 'libfdt'))
+
+# fputils build is shared across all configs in the build root.
+main.SConscript('ext/fputils/SConscript',
+ variant_dir = joinpath(build_root, 'fputils'))
+
+# DRAMSim2 build is shared across all configs in the build root.
+main.SConscript('ext/dramsim2/SConscript',
+ variant_dir = joinpath(build_root, 'dramsim2'))
+
###################################################
#
# This function is used to set up a directory with switching headers
###################################################
main['ALL_ISA_LIST'] = all_isa_list
+all_isa_deps = {}
def make_switching_dir(dname, switch_headers, env):
# Generate the header. target[0] is the full path of the output
# header to generate. 'source' is a dummy variable, since we get the
# list of ISAs from env['ALL_ISA_LIST'].
def gen_switch_hdr(target, source, env):
fname = str(target[0])
- f = open(fname, 'w')
isa = env['TARGET_ISA'].lower()
- print >>f, '#include "%s/%s/%s"' % (dname, isa, basename(fname))
- f.close()
+ try:
+ f = open(fname, 'w')
+ print >>f, '#include "%s/%s/%s"' % (dname, isa, basename(fname))
+ f.close()
+ except IOError:
+ print "Failed to create %s" % fname
+ raise
# Build SCons Action object. 'varlist' specifies env vars that this
# action depends on; when env['ALL_ISA_LIST'] changes these actions
# Instantiate actions for each header
for hdr in switch_headers:
env.Command(hdr, [], switch_hdr_action)
+
+ isa_target = Dir('.').up().name.lower().replace('_', '-')
+ env['PHONY_BASE'] = '#'+isa_target
+ all_isa_deps[isa_target] = None
+
Export('make_switching_dir')
+# all-isas -> all-deps -> all-environs -> all_targets
+main.Alias('#all-isas', [])
+main.Alias('#all-deps', '#all-isas')
+
+# Dummy target to ensure all environments are created before telling
+# SCons what to actually make (the command line arguments). We attach
+# them to the dependence graph after the environments are complete.
+ORIG_BUILD_TARGETS = list(BUILD_TARGETS) # force a copy; gets closure to work.
+def environsComplete(target, source, env):
+ for t in ORIG_BUILD_TARGETS:
+ main.Depends('#all-targets', t)
+
+# Each build/* switching_dir attaches its *-environs target to #all-environs.
+main.Append(BUILDERS = {'CompleteEnvirons' :
+ Builder(action=MakeAction(environsComplete, None))})
+main.CompleteEnvirons('#all-environs', [])
+
+def doNothing(**ignored): pass
+main.Append(BUILDERS = {'Dummy': Builder(action=MakeAction(doNothing, None))})
+
+# The final target to which all the original targets ultimately get attached.
+main.Dummy('#all-targets', '#all-environs')
+BUILD_TARGETS[:] = ['#all-targets']
+
###################################################
#
# Define build environments for selected configurations.
###################################################
for variant_path in variant_paths:
- print "Building in", variant_path
+ if not GetOption('silent'):
+ print "Building in", variant_path
# Make a copy of the build-root environment to use for this config.
env = main.Clone()
current_vars_file = joinpath(build_root, 'variables', variant_dir)
if isfile(current_vars_file):
sticky_vars.files.append(current_vars_file)
- print "Using saved variables file %s" % current_vars_file
+ if not GetOption('silent'):
+ print "Using saved variables file %s" % current_vars_file
else:
# Build dir-specific variables file doesn't exist.
if env['EFENCE']:
env.Append(LIBS=['efence'])
+ if env['USE_KVM']:
+ if not have_kvm:
+ print "Warning: Can not enable KVM, host seems to lack KVM support"
+ env['USE_KVM'] = False
+ elif not have_posix_timers:
+ print "Warning: Can not enable KVM, host seems to lack support " \
+ "for POSIX timers"
+ 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"
+ env['USE_KVM'] = False
+
+ # Warn about missing optional functionality
+ if env['USE_KVM']:
+ if not main['HAVE_PERF_ATTR_EXCLUDE_HOST']:
+ print "Warning: perf_event headers lack support for the " \
+ "exclude_host attribute. KVM instruction counts will " \
+ "be inaccurate."
+
# Save sticky variable settings back to current variables file
sticky_vars.Save(current_vars_file, 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.)
- envList = SConscript('src/SConscript', variant_dir = variant_path,
- exports = 'env')
-
- # Set up the regression tests for each build.
- for e in envList:
- SConscript('tests/SConscript',
- variant_dir = joinpath(variant_path, 'tests', e.Label),
- exports = { 'env' : e }, duplicate = False)
+ SConscript('src/SConscript', variant_dir = variant_path, exports = 'env')
+
+def pairwise(iterable):
+ "s -> (s0,s1), (s1,s2), (s2, s3), ..."
+ a, b = itertools.tee(iterable)
+ b.next()
+ return itertools.izip(a, b)
+
+# Create false dependencies so SCons will parse ISAs, establish
+# dependencies, and setup the build Environments serially. Either
+# SCons (likely) and/or our SConscripts (possibly) cannot cope with -j
+# greater than 1. It appears to be standard race condition stuff; it
+# doesn't always fail, but usually, and the behaviors are different.
+# Every time I tried to remove this, builds would fail in some
+# creative new way. So, don't do that. You'll want to, though, because
+# tests/SConscript takes a long time to make its Environments.
+for t1, t2 in pairwise(sorted(all_isa_deps.iterkeys())):
+ main.Depends('#%s-deps' % t2, '#%s-deps' % t1)
+ main.Depends('#%s-environs' % t2, '#%s-environs' % t1)
# base help text
Help('''