SConstruct revision 11308
17094Sgblack@eecs.umich.edu# -*- mode:python -*-
212497Sgiacomo.travaglini@arm.com
39913Ssteve.reinhardt@amd.com# Copyright (c) 2013, 2015 ARM Limited
47094Sgblack@eecs.umich.edu# All rights reserved.
57094Sgblack@eecs.umich.edu#
67094Sgblack@eecs.umich.edu# The license below extends only to copyright in the software and shall
77094Sgblack@eecs.umich.edu# not be construed as granting a license to any other intellectual
87094Sgblack@eecs.umich.edu# property including but not limited to intellectual property relating
97094Sgblack@eecs.umich.edu# to a hardware implementation of the functionality of the software
107094Sgblack@eecs.umich.edu# licensed hereunder.  You may use the software subject to the license
117094Sgblack@eecs.umich.edu# terms below provided that you ensure that this notice is replicated
127094Sgblack@eecs.umich.edu# unmodified and in its entirety in all distributions of the software,
137094Sgblack@eecs.umich.edu# modified or unmodified, in source code or in binary form.
147094Sgblack@eecs.umich.edu#
157094Sgblack@eecs.umich.edu# Copyright (c) 2011 Advanced Micro Devices, Inc.
166253Sgblack@eecs.umich.edu# Copyright (c) 2009 The Hewlett-Packard Development Company
176253Sgblack@eecs.umich.edu# Copyright (c) 2004-2005 The Regents of The University of Michigan
186253Sgblack@eecs.umich.edu# All rights reserved.
196253Sgblack@eecs.umich.edu#
206253Sgblack@eecs.umich.edu# Redistribution and use in source and binary forms, with or without
216253Sgblack@eecs.umich.edu# modification, are permitted provided that the following conditions are
226253Sgblack@eecs.umich.edu# met: redistributions of source code must retain the above copyright
236253Sgblack@eecs.umich.edu# notice, this list of conditions and the following disclaimer;
246253Sgblack@eecs.umich.edu# redistributions in binary form must reproduce the above copyright
256253Sgblack@eecs.umich.edu# notice, this list of conditions and the following disclaimer in the
266253Sgblack@eecs.umich.edu# documentation and/or other materials provided with the distribution;
276253Sgblack@eecs.umich.edu# neither the name of the copyright holders nor the names of its
286253Sgblack@eecs.umich.edu# contributors may be used to endorse or promote products derived from
296253Sgblack@eecs.umich.edu# this software without specific prior written permission.
306253Sgblack@eecs.umich.edu#
316253Sgblack@eecs.umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
326253Sgblack@eecs.umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
336253Sgblack@eecs.umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
346253Sgblack@eecs.umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
356253Sgblack@eecs.umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
366253Sgblack@eecs.umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
376253Sgblack@eecs.umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
386253Sgblack@eecs.umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
396253Sgblack@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
406253Sgblack@eecs.umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
416253Sgblack@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
426253Sgblack@eecs.umich.edu#
436253Sgblack@eecs.umich.edu# Authors: Steve Reinhardt
448229Snate@binkert.org#          Nathan Binkert
4511793Sbrandon.potter@amd.com
466759SAli.Saidi@ARM.com###################################################
476255Sgblack@eecs.umich.edu#
486712Snate@binkert.org# SCons top-level build description (SConstruct) file.
4911793Sbrandon.potter@amd.com#
509913Ssteve.reinhardt@amd.com# While in this directory ('gem5'), just type 'scons' to build the default
516253Sgblack@eecs.umich.edu# configuration (see below), or type 'scons build/<CONFIG>/<binary>'
526253Sgblack@eecs.umich.edu# to build some other configuration (e.g., 'build/ALPHA/gem5.opt' for
536253Sgblack@eecs.umich.edu# the optimized full-system version).
546254Sgblack@eecs.umich.edu#
556254Sgblack@eecs.umich.edu# You can build gem5 in a different directory as long as there is a
567148Sgblack@eecs.umich.edu# 'build/<CONFIG>' somewhere along the target path.  The build system
577094Sgblack@eecs.umich.edu# expects that all configs under the same build directory are being
586254Sgblack@eecs.umich.edu# built for the same host system.
596255Sgblack@eecs.umich.edu#
606255Sgblack@eecs.umich.edu# Examples:
616255Sgblack@eecs.umich.edu#
626254Sgblack@eecs.umich.edu#   The following two commands are equivalent.  The '-u' option tells
636254Sgblack@eecs.umich.edu#   scons to search up the directory tree for this SConstruct file.
646254Sgblack@eecs.umich.edu#   % cd <path-to-src>/gem5 ; scons build/ALPHA/gem5.debug
656255Sgblack@eecs.umich.edu#   % cd <path-to-src>/gem5/build/ALPHA; scons -u gem5.debug
666255Sgblack@eecs.umich.edu#
676255Sgblack@eecs.umich.edu#   The following two commands are equivalent and demonstrate building
686255Sgblack@eecs.umich.edu#   in a directory outside of the source tree.  The '-C' option tells
696255Sgblack@eecs.umich.edu#   scons to chdir to the specified directory to find this SConstruct
706255Sgblack@eecs.umich.edu#   file.
716255Sgblack@eecs.umich.edu#   % cd <path-to-src>/gem5 ; scons /local/foo/build/ALPHA/gem5.debug
726255Sgblack@eecs.umich.edu#   % cd /local/foo/build/ALPHA; scons -C <path-to-src>/gem5 gem5.debug
736255Sgblack@eecs.umich.edu#
747182Sgblack@eecs.umich.edu# You can use 'scons -H' to print scons options.  If you're in this
756255Sgblack@eecs.umich.edu# 'gem5' directory (or use -u or -C to tell scons where to find this
767182Sgblack@eecs.umich.edu# file), you can use 'scons -h' to print all the gem5-specific build
776255Sgblack@eecs.umich.edu# options as well.
786255Sgblack@eecs.umich.edu#
796255Sgblack@eecs.umich.edu###################################################
806255Sgblack@eecs.umich.edu
816255Sgblack@eecs.umich.edu# Check for recent-enough Python and SCons versions.
826255Sgblack@eecs.umich.edutry:
836712Snate@binkert.org    # Really old versions of scons only take two options for the
846255Sgblack@eecs.umich.edu    # function, so check once without the revision and once with the
856255Sgblack@eecs.umich.edu    # revision, the first instance will fail for stuff other than
866254Sgblack@eecs.umich.edu    # 0.98, and the second will fail for 0.98.0
876254Sgblack@eecs.umich.edu    EnsureSConsVersion(0, 98)
886254Sgblack@eecs.umich.edu    EnsureSConsVersion(0, 98, 1)
896254Sgblack@eecs.umich.eduexcept SystemExit, e:
9010037SARM gem5 Developers    print """
9110037SARM gem5 DevelopersFor more details, see:
9210037SARM gem5 Developers    http://gem5.org/Dependencies
9310037SARM gem5 Developers"""
9410037SARM gem5 Developers    raise
9510037SARM gem5 Developers
9610037SARM gem5 Developers# We ensure the python version early because because python-config
9710037SARM gem5 Developers# requires python 2.5
9810037SARM gem5 Developerstry:
9910037SARM gem5 Developers    EnsurePythonVersion(2, 5)
10010037SARM gem5 Developersexcept SystemExit, e:
10110037SARM gem5 Developers    print """
10210037SARM gem5 DevelopersYou can use a non-default installation of the Python interpreter by
10310037SARM gem5 Developersrearranging your PATH so that scons finds the non-default 'python' and
10410037SARM gem5 Developers'python-config' first.
10510037SARM gem5 Developers
10610037SARM gem5 DevelopersFor more details, see:
10710037SARM gem5 Developers    http://gem5.org/wiki/index.php/Using_a_non-default_Python_installation
10810037SARM gem5 Developers"""
10910037SARM gem5 Developers    raise
11010037SARM gem5 Developers
11110037SARM gem5 Developers# Global Python includes
11210037SARM gem5 Developersimport itertools
11310037SARM gem5 Developersimport os
11410037SARM gem5 Developersimport re
11510037SARM gem5 Developersimport subprocess
11610037SARM gem5 Developersimport sys
11710037SARM gem5 Developers
11810037SARM gem5 Developersfrom os import mkdir, environ
11910037SARM gem5 Developersfrom os.path import abspath, basename, dirname, expanduser, normpath
12010037SARM gem5 Developersfrom os.path import exists,  isdir, isfile
12110037SARM gem5 Developersfrom os.path import join as joinpath, split as splitpath
12210037SARM gem5 Developers
12310037SARM gem5 Developers# SCons includes
12410037SARM gem5 Developersimport SCons
12510037SARM gem5 Developersimport SCons.Node
12610037SARM gem5 Developers
12710037SARM gem5 Developersextra_python_paths = [
12810037SARM gem5 Developers    Dir('src/python').srcnode().abspath, # gem5 includes
12910037SARM gem5 Developers    Dir('ext/ply').srcnode().abspath, # ply is used by several files
13010037SARM gem5 Developers    ]
13110037SARM gem5 Developers
13210037SARM gem5 Developerssys.path[1:1] = extra_python_paths
13310037SARM gem5 Developers
13410037SARM gem5 Developersfrom m5.util import compareVersions, readCommand
13510037SARM gem5 Developersfrom m5.util.terminal import get_termcap
13610037SARM gem5 Developers
13710037SARM gem5 Developershelp_texts = {
13810037SARM gem5 Developers    "options" : "",
13910037SARM gem5 Developers    "global_vars" : "",
14010037SARM gem5 Developers    "local_vars" : ""
14110037SARM gem5 Developers}
14210037SARM gem5 Developers
14310037SARM gem5 DevelopersExport("help_texts")
14410037SARM gem5 Developers
14510037SARM gem5 Developers
14610037SARM gem5 Developers# There's a bug in scons in that (1) by default, the help texts from
14710037SARM gem5 Developers# AddOption() are supposed to be displayed when you type 'scons -h'
14810037SARM gem5 Developers# and (2) you can override the help displayed by 'scons -h' using the
14910037SARM gem5 Developers# Help() function, but these two features are incompatible: once
15010037SARM gem5 Developers# you've overridden the help text using Help(), there's no way to get
15110037SARM gem5 Developers# at the help texts from AddOptions.  See:
15210037SARM gem5 Developers#     http://scons.tigris.org/issues/show_bug.cgi?id=2356
15310037SARM gem5 Developers#     http://scons.tigris.org/issues/show_bug.cgi?id=2611
15410037SARM gem5 Developers# This hack lets us extract the help text from AddOptions and
15510037SARM gem5 Developers# re-inject it via Help().  Ideally someday this bug will be fixed and
15610037SARM gem5 Developers# we can just use AddOption directly.
15710037SARM gem5 Developersdef AddLocalOption(*args, **kwargs):
15810037SARM gem5 Developers    col_width = 30
15910037SARM gem5 Developers
16010037SARM gem5 Developers    help = "  " + ", ".join(args)
16110037SARM gem5 Developers    if "help" in kwargs:
16210037SARM gem5 Developers        length = len(help)
16310037SARM gem5 Developers        if length >= col_width:
16410037SARM gem5 Developers            help += "\n" + " " * col_width
16510037SARM gem5 Developers        else:
16610037SARM gem5 Developers            help += " " * (col_width - length)
16710037SARM gem5 Developers        help += kwargs["help"]
16810037SARM gem5 Developers    help_texts["options"] += help + "\n"
16910037SARM gem5 Developers
17010037SARM gem5 Developers    AddOption(*args, **kwargs)
17110037SARM gem5 Developers
17210037SARM gem5 DevelopersAddLocalOption('--colors', dest='use_colors', action='store_true',
17310037SARM gem5 Developers               help="Add color to abbreviated scons output")
1746254Sgblack@eecs.umich.eduAddLocalOption('--no-colors', dest='use_colors', action='store_false',
1756254Sgblack@eecs.umich.edu               help="Don't add color to abbreviated scons output")
1767148Sgblack@eecs.umich.eduAddLocalOption('--with-cxx-config', dest='with_cxx_config',
1777094Sgblack@eecs.umich.edu               action='store_true',
1786254Sgblack@eecs.umich.edu               help="Build with support for C++-based configuration")
1796254Sgblack@eecs.umich.eduAddLocalOption('--default', dest='default', type='string', action='store',
1806254Sgblack@eecs.umich.edu               help='Override which build_opts file to use for defaults')
1816254Sgblack@eecs.umich.eduAddLocalOption('--ignore-style', dest='ignore_style', action='store_true',
1826254Sgblack@eecs.umich.edu               help='Disable style checking hooks')
1836254Sgblack@eecs.umich.eduAddLocalOption('--no-lto', dest='no_lto', action='store_true',
1846255Sgblack@eecs.umich.edu               help='Disable Link-Time Optimization for fast')
1856255Sgblack@eecs.umich.eduAddLocalOption('--update-ref', dest='update_ref', action='store_true',
1866255Sgblack@eecs.umich.edu               help='Update test reference outputs')
1876255Sgblack@eecs.umich.eduAddLocalOption('--verbose', dest='verbose', action='store_true',
1886255Sgblack@eecs.umich.edu               help='Print full tool command lines')
1896255Sgblack@eecs.umich.eduAddLocalOption('--without-python', dest='without_python',
1906255Sgblack@eecs.umich.edu               action='store_true',
1916255Sgblack@eecs.umich.edu               help='Build without Python configuration support')
1926255Sgblack@eecs.umich.eduAddLocalOption('--without-tcmalloc', dest='without_tcmalloc',
1936255Sgblack@eecs.umich.edu               action='store_true',
1946255Sgblack@eecs.umich.edu               help='Disable linking against tcmalloc')
1956255Sgblack@eecs.umich.eduAddLocalOption('--with-ubsan', dest='with_ubsan', action='store_true',
1967182Sgblack@eecs.umich.edu               help='Build with Undefined Behavior Sanitizer if available')
1976255Sgblack@eecs.umich.edu
1987182Sgblack@eecs.umich.edutermcap = get_termcap(GetOption('use_colors'))
1996255Sgblack@eecs.umich.edu
2006255Sgblack@eecs.umich.edu########################################################################
2016255Sgblack@eecs.umich.edu#
2026255Sgblack@eecs.umich.edu# Set up the main build environment.
2036255Sgblack@eecs.umich.edu#
2046255Sgblack@eecs.umich.edu########################################################################
2056255Sgblack@eecs.umich.edu
2066712Snate@binkert.org# export TERM so that clang reports errors in color
2076255Sgblack@eecs.umich.eduuse_vars = set([ 'AS', 'AR', 'CC', 'CXX', 'HOME', 'LD_LIBRARY_PATH',
2086255Sgblack@eecs.umich.edu                 'LIBRARY_PATH', 'PATH', 'PKG_CONFIG_PATH', 'PROTOC',
2096254Sgblack@eecs.umich.edu                 'PYTHONPATH', 'RANLIB', 'SWIG', 'TERM' ])
2106254Sgblack@eecs.umich.edu
2116254Sgblack@eecs.umich.eduuse_prefixes = [
2126254Sgblack@eecs.umich.edu    "CCACHE_",         # ccache (caching compiler wrapper) configuration
2136254Sgblack@eecs.umich.edu    "CCC_",            # clang static analyzer configuration
2146254Sgblack@eecs.umich.edu    "DISTCC_",         # distcc (distributed compiler wrapper) configuration
2156255Sgblack@eecs.umich.edu    "INCLUDE_SERVER_", # distcc pump server settings
2167148Sgblack@eecs.umich.edu    "M5",              # M5 configuration (e.g., path to kernels)
2177094Sgblack@eecs.umich.edu    ]
2186254Sgblack@eecs.umich.edu
2196254Sgblack@eecs.umich.eduuse_env = {}
2206254Sgblack@eecs.umich.edufor key,val in sorted(os.environ.iteritems()):
2216254Sgblack@eecs.umich.edu    if key in use_vars or \
2226254Sgblack@eecs.umich.edu            any([key.startswith(prefix) for prefix in use_prefixes]):
2236254Sgblack@eecs.umich.edu        use_env[key] = val
2246255Sgblack@eecs.umich.edu
2256255Sgblack@eecs.umich.edu# Tell scons to avoid implicit command dependencies to avoid issues
2266255Sgblack@eecs.umich.edu# with the param wrappes being compiled twice (see
2276255Sgblack@eecs.umich.edu# http://scons.tigris.org/issues/show_bug.cgi?id=2811)
2286254Sgblack@eecs.umich.edumain = Environment(ENV=use_env, IMPLICIT_COMMAND_DEPENDENCIES=0)
2296255Sgblack@eecs.umich.edumain.Decider('MD5-timestamp')
2306255Sgblack@eecs.umich.edumain.root = Dir(".")         # The current directory (where this file lives).
2316255Sgblack@eecs.umich.edumain.srcdir = Dir("src")     # The source directory
2326255Sgblack@eecs.umich.edu
2336255Sgblack@eecs.umich.edumain_dict_keys = main.Dictionary().keys()
2346255Sgblack@eecs.umich.edu
2356255Sgblack@eecs.umich.edu# Check that we have a C/C++ compiler
2366255Sgblack@eecs.umich.eduif not ('CC' in main_dict_keys and 'CXX' in main_dict_keys):
2376255Sgblack@eecs.umich.edu    print "No C++ compiler installed (package g++ on Ubuntu and RedHat)"
2386255Sgblack@eecs.umich.edu    Exit(1)
2396255Sgblack@eecs.umich.edu
2406255Sgblack@eecs.umich.edu# Check that swig is present
2416255Sgblack@eecs.umich.eduif not 'SWIG' in main_dict_keys:
2426255Sgblack@eecs.umich.edu    print "swig is not installed (package swig on Ubuntu and RedHat)"
2436255Sgblack@eecs.umich.edu    Exit(1)
2446255Sgblack@eecs.umich.edu
2456255Sgblack@eecs.umich.edu# add useful python code PYTHONPATH so it can be used by subprocesses
2466712Snate@binkert.org# as well
2476255Sgblack@eecs.umich.edumain.AppendENVPath('PYTHONPATH', extra_python_paths)
2486255Sgblack@eecs.umich.edu
2496254Sgblack@eecs.umich.edu########################################################################
2506254Sgblack@eecs.umich.edu#
2516254Sgblack@eecs.umich.edu# Mercurial Stuff.
2526254Sgblack@eecs.umich.edu#
2536254Sgblack@eecs.umich.edu# If the gem5 directory is a mercurial repository, we should do some
2546254Sgblack@eecs.umich.edu# extra things.
2556255Sgblack@eecs.umich.edu#
2567148Sgblack@eecs.umich.edu########################################################################
2577094Sgblack@eecs.umich.edu
2586254Sgblack@eecs.umich.eduhgdir = main.root.Dir(".hg")
2596254Sgblack@eecs.umich.edu
2606254Sgblack@eecs.umich.edumercurial_style_message = """
2616254Sgblack@eecs.umich.eduYou're missing the gem5 style hook, which automatically checks your code
2626255Sgblack@eecs.umich.eduagainst the gem5 style rules on hg commit and qrefresh commands.  This
2636255Sgblack@eecs.umich.eduscript will now install the hook in your .hg/hgrc file.
2646255Sgblack@eecs.umich.eduPress enter to continue, or ctrl-c to abort: """
2656254Sgblack@eecs.umich.edu
2666254Sgblack@eecs.umich.edumercurial_style_hook = """
2676255Sgblack@eecs.umich.edu# The following lines were automatically added by gem5/SConstruct
2686255Sgblack@eecs.umich.edu# to provide the gem5 style-checking hooks
2696255Sgblack@eecs.umich.edu[extensions]
2706255Sgblack@eecs.umich.edustyle = %s/util/style.py
2716255Sgblack@eecs.umich.edu
2726255Sgblack@eecs.umich.edu[hooks]
2736255Sgblack@eecs.umich.edupretxncommit.style = python:style.check_style
2746255Sgblack@eecs.umich.edupre-qrefresh.style = python:style.check_style
2756255Sgblack@eecs.umich.edu# End of SConstruct additions
2766255Sgblack@eecs.umich.edu
2776255Sgblack@eecs.umich.edu""" % (main.root.abspath)
2786255Sgblack@eecs.umich.edu
2796255Sgblack@eecs.umich.edumercurial_lib_not_found = """
2806255Sgblack@eecs.umich.eduMercurial libraries cannot be found, ignoring style hook.  If
2816255Sgblack@eecs.umich.eduyou are a gem5 developer, please fix this and run the style
2826255Sgblack@eecs.umich.eduhook. It is important.
2836255Sgblack@eecs.umich.edu"""
2846255Sgblack@eecs.umich.edu
2856255Sgblack@eecs.umich.edu# Check for style hook and prompt for installation if it's not there.
2866255Sgblack@eecs.umich.edu# Skip this if --ignore-style was specified, there's no .hg dir to
2876712Snate@binkert.org# install a hook in, or there's no interactive terminal to prompt.
2886255Sgblack@eecs.umich.eduif not GetOption('ignore_style') and hgdir.exists() and sys.stdin.isatty():
2896255Sgblack@eecs.umich.edu    style_hook = True
2906254Sgblack@eecs.umich.edu    try:
2916254Sgblack@eecs.umich.edu        from mercurial import ui
2926254Sgblack@eecs.umich.edu        ui = ui.ui()
2936254Sgblack@eecs.umich.edu        ui.readconfig(hgdir.File('hgrc').abspath)
29412104Snathanael.premillieu@arm.com        style_hook = ui.config('hooks', 'pretxncommit.style', None) and \
29512104Snathanael.premillieu@arm.com                     ui.config('hooks', 'pre-qrefresh.style', None)
29612104Snathanael.premillieu@arm.com    except ImportError:
29712104Snathanael.premillieu@arm.com        print mercurial_lib_not_found
29812104Snathanael.premillieu@arm.com
29912104Snathanael.premillieu@arm.com    if not style_hook:
30012104Snathanael.premillieu@arm.com        print mercurial_style_message,
30112104Snathanael.premillieu@arm.com        # continue unless user does ctrl-c/ctrl-d etc.
30212104Snathanael.premillieu@arm.com        try:
30312104Snathanael.premillieu@arm.com            raw_input()
30412104Snathanael.premillieu@arm.com        except:
30512104Snathanael.premillieu@arm.com            print "Input exception, exiting scons.\n"
30612104Snathanael.premillieu@arm.com            sys.exit(1)
30712104Snathanael.premillieu@arm.com        hgrc_path = '%s/.hg/hgrc' % main.root.abspath
30812104Snathanael.premillieu@arm.com        print "Adding style hook to", hgrc_path, "\n"
30912104Snathanael.premillieu@arm.com        try:
31012104Snathanael.premillieu@arm.com            hgrc = open(hgrc_path, 'a')
31112104Snathanael.premillieu@arm.com            hgrc.write(mercurial_style_hook)
31212104Snathanael.premillieu@arm.com            hgrc.close()
31312104Snathanael.premillieu@arm.com        except:
31412104Snathanael.premillieu@arm.com            print "Error updating", hgrc_path
31512104Snathanael.premillieu@arm.com            sys.exit(1)
31612104Snathanael.premillieu@arm.com
31712104Snathanael.premillieu@arm.com
31812104Snathanael.premillieu@arm.com###################################################
31912104Snathanael.premillieu@arm.com#
32012104Snathanael.premillieu@arm.com# Figure out which configurations to set up based on the path(s) of
32112104Snathanael.premillieu@arm.com# the target(s).
32212104Snathanael.premillieu@arm.com#
32312104Snathanael.premillieu@arm.com###################################################
32412104Snathanael.premillieu@arm.com
32512104Snathanael.premillieu@arm.com# Find default configuration & binary.
3266254Sgblack@eecs.umich.eduDefault(environ.get('M5_DEFAULT_BINARY', 'build/ALPHA/gem5.debug'))
3276254Sgblack@eecs.umich.edu
32812104Snathanael.premillieu@arm.com# helper function: find last occurrence of element in list
3296253Sgblack@eecs.umich.edudef rfind(l, elt, offs = -1):
33012104Snathanael.premillieu@arm.com    for i in range(len(l)+offs, 0, -1):
33112104Snathanael.premillieu@arm.com        if l[i] == elt:
3329913Ssteve.reinhardt@amd.com            return i
33312104Snathanael.premillieu@arm.com    raise ValueError, "element not found"
33412109SRekai.GonzalezAlberquilla@arm.com
33512109SRekai.GonzalezAlberquilla@arm.com# Take a list of paths (or SCons Nodes) and return a list with all
33612109SRekai.GonzalezAlberquilla@arm.com# paths made absolute and ~-expanded.  Paths will be interpreted
33712109SRekai.GonzalezAlberquilla@arm.com# relative to the launch directory unless a different root is provided
33812109SRekai.GonzalezAlberquilla@arm.comdef makePathListAbsolute(path_list, root=GetLaunchDir()):
33912109SRekai.GonzalezAlberquilla@arm.com    return [abspath(joinpath(root, expanduser(str(p))))
34012104Snathanael.premillieu@arm.com            for p in path_list]
34112104Snathanael.premillieu@arm.com
34212104Snathanael.premillieu@arm.com# Each target must have 'build' in the interior of the path; the
34312104Snathanael.premillieu@arm.com# directory below this will determine the build parameters.  For
34412104Snathanael.premillieu@arm.com# example, for target 'foo/bar/build/ALPHA_SE/arch/alpha/blah.do' we
34512104Snathanael.premillieu@arm.com# recognize that ALPHA_SE specifies the configuration because it
34612104Snathanael.premillieu@arm.com# follow 'build' in the build path.
34712104Snathanael.premillieu@arm.com
34812104Snathanael.premillieu@arm.com# The funky assignment to "[:]" is needed to replace the list contents
34912104Snathanael.premillieu@arm.com# in place rather than reassign the symbol to a new list, which
3506253Sgblack@eecs.umich.edu# doesn't work (obviously!).
3516253Sgblack@eecs.umich.eduBUILD_TARGETS[:] = makePathListAbsolute(BUILD_TARGETS)
3526262Sgblack@eecs.umich.edu
3537148Sgblack@eecs.umich.edu# Generate a list of the unique build roots and configs that the
3546262Sgblack@eecs.umich.edu# collected targets reference.
35510037SARM gem5 Developersvariant_paths = []
35610037SARM gem5 Developersbuild_root = None
35710037SARM gem5 Developersfor t in BUILD_TARGETS:
3586262Sgblack@eecs.umich.edu    path_dirs = t.split('/')
3596262Sgblack@eecs.umich.edu    try:
36010037SARM gem5 Developers        build_top = rfind(path_dirs, 'build', -2)
36110037SARM gem5 Developers    except:
3627122Sgblack@eecs.umich.edu        print "Error: no non-leaf 'build' dir found on target path", t
36310037SARM gem5 Developers        Exit(1)
36410037SARM gem5 Developers    this_build_root = joinpath('/',*path_dirs[:build_top+1])
36510037SARM gem5 Developers    if not build_root:
36610037SARM gem5 Developers        build_root = this_build_root
36710037SARM gem5 Developers    else:
36810037SARM gem5 Developers        if this_build_root != build_root:
36910037SARM gem5 Developers            print "Error: build targets not under same build root\n"\
37010037SARM gem5 Developers                  "  %s\n  %s" % (build_root, this_build_root)
37110037SARM gem5 Developers            Exit(1)
37210037SARM gem5 Developers    variant_path = joinpath('/',*path_dirs[:build_top+2])
37310037SARM gem5 Developers    if variant_path not in variant_paths:
37410037SARM gem5 Developers        variant_paths.append(variant_path)
37510037SARM gem5 Developers
37610037SARM gem5 Developers# Make sure build_root exists (might not if this is the first build there)
37710037SARM gem5 Developersif not isdir(build_root):
37810037SARM gem5 Developers    mkdir(build_root)
37910037SARM gem5 Developersmain['BUILDROOT'] = build_root
38010037SARM gem5 Developers
38110037SARM gem5 DevelopersExport('main')
38210037SARM gem5 Developers
38310037SARM gem5 Developersmain.SConsignFile(joinpath(build_root, "sconsign"))
38410037SARM gem5 Developers
38510037SARM gem5 Developers# Default duplicate option is to use hard links, but this messes up
38610037SARM gem5 Developers# when you use emacs to edit a file in the target dir, as emacs moves
38710037SARM gem5 Developers# file to file~ then copies to file, breaking the link.  Symbolic
38810037SARM gem5 Developers# (soft) links work better.
38910037SARM gem5 Developersmain.SetOption('duplicate', 'soft-copy')
39010037SARM gem5 Developers
39110037SARM gem5 Developers#
39210037SARM gem5 Developers# Set up global sticky variables... these are common to an entire build
39310037SARM gem5 Developers# tree (not specific to a particular build like ALPHA_SE)
39410037SARM gem5 Developers#
39510037SARM gem5 Developers
39610037SARM gem5 Developersglobal_vars_file = joinpath(build_root, 'variables.global')
39710037SARM gem5 Developers
39810037SARM gem5 Developersglobal_vars = Variables(global_vars_file, args=ARGUMENTS)
39910037SARM gem5 Developers
40010037SARM gem5 Developersglobal_vars.AddVariables(
40110037SARM gem5 Developers    ('CC', 'C compiler', environ.get('CC', main['CC'])),
40210037SARM gem5 Developers    ('CXX', 'C++ compiler', environ.get('CXX', main['CXX'])),
40310037SARM gem5 Developers    ('SWIG', 'SWIG tool', environ.get('SWIG', main['SWIG'])),
40410037SARM gem5 Developers    ('PROTOC', 'protoc tool', environ.get('PROTOC', 'protoc')),
40510037SARM gem5 Developers    ('BATCH', 'Use batch pool for build and tests', False),
40610037SARM gem5 Developers    ('BATCH_CMD', 'Batch pool submission command name', 'qdo'),
40710037SARM gem5 Developers    ('M5_BUILD_CACHE', 'Cache built objects in this directory', False),
40810037SARM gem5 Developers    ('EXTRAS', 'Add extra directories to the compilation', '')
40910037SARM gem5 Developers    )
41010037SARM gem5 Developers
41110037SARM gem5 Developers# Update main environment with values from ARGUMENTS & global_vars_file
41210037SARM gem5 Developersglobal_vars.Update(main)
41310037SARM gem5 Developershelp_texts["global_vars"] += global_vars.GenerateHelpText(main)
41410037SARM gem5 Developers
41510037SARM gem5 Developers# Save sticky variable settings back to current variables file
41610037SARM gem5 Developersglobal_vars.Save(global_vars_file, main)
41710037SARM gem5 Developers
41810037SARM gem5 Developers# Parse EXTRAS variable to build list of all directories where we're
41910037SARM gem5 Developers# look for sources etc.  This list is exported as extras_dir_list.
42010037SARM gem5 Developersbase_dir = main.srcdir.abspath
42110037SARM gem5 Developersif main['EXTRAS']:
42210037SARM gem5 Developers    extras_dir_list = makePathListAbsolute(main['EXTRAS'].split(':'))
42310037SARM gem5 Developerselse:
42410037SARM gem5 Developers    extras_dir_list = []
42510037SARM gem5 Developers
42610037SARM gem5 DevelopersExport('base_dir')
42710037SARM gem5 DevelopersExport('extras_dir_list')
42810037SARM gem5 Developers
42910037SARM gem5 Developers# the ext directory should be on the #includes path
43010037SARM gem5 Developersmain.Append(CPPPATH=[Dir('ext')])
43110037SARM gem5 Developers
43210037SARM gem5 Developersdef strip_build_path(path, env):
43310037SARM gem5 Developers    path = str(path)
43410037SARM gem5 Developers    variant_base = env['BUILDROOT'] + os.path.sep
43510037SARM gem5 Developers    if path.startswith(variant_base):
43610037SARM gem5 Developers        path = path[len(variant_base):]
43710037SARM gem5 Developers    elif path.startswith('build/'):
43810037SARM gem5 Developers        path = path[6:]
43910037SARM gem5 Developers    return path
44010037SARM gem5 Developers
44110037SARM gem5 Developers# Generate a string of the form:
44210037SARM gem5 Developers#   common/path/prefix/src1, src2 -> tgt1, tgt2
44310037SARM gem5 Developers# to print while building.
44410037SARM gem5 Developersclass Transform(object):
44510037SARM gem5 Developers    # all specific color settings should be here and nowhere else
44610037SARM gem5 Developers    tool_color = termcap.Normal
44710037SARM gem5 Developers    pfx_color = termcap.Yellow
44810037SARM gem5 Developers    srcs_color = termcap.Yellow + termcap.Bold
44910037SARM gem5 Developers    arrow_color = termcap.Blue + termcap.Bold
45010037SARM gem5 Developers    tgts_color = termcap.Yellow + termcap.Bold
4516262Sgblack@eecs.umich.edu
4526262Sgblack@eecs.umich.edu    def __init__(self, tool, max_sources=99):
4536262Sgblack@eecs.umich.edu        self.format = self.tool_color + (" [%8s] " % tool) \
4546263Sgblack@eecs.umich.edu                      + self.pfx_color + "%s" \
4557148Sgblack@eecs.umich.edu                      + self.srcs_color + "%s" \
4566263Sgblack@eecs.umich.edu                      + self.arrow_color + " -> " \
4576263Sgblack@eecs.umich.edu                      + self.tgts_color + "%s" \
4586263Sgblack@eecs.umich.edu                      + termcap.Normal
4596263Sgblack@eecs.umich.edu        self.max_sources = max_sources
4606263Sgblack@eecs.umich.edu
4616263Sgblack@eecs.umich.edu    def __call__(self, target, source, env, for_signature=None):
4626263Sgblack@eecs.umich.edu        # truncate source list according to max_sources param
4636263Sgblack@eecs.umich.edu        source = source[0:self.max_sources]
4646263Sgblack@eecs.umich.edu        def strip(f):
4656263Sgblack@eecs.umich.edu            return strip_build_path(str(f), env)
4666263Sgblack@eecs.umich.edu        if len(source) > 0:
4676263Sgblack@eecs.umich.edu            srcs = map(strip, source)
4686263Sgblack@eecs.umich.edu        else:
4696263Sgblack@eecs.umich.edu            srcs = ['']
4706263Sgblack@eecs.umich.edu        tgts = map(strip, target)
4716264Sgblack@eecs.umich.edu        # surprisingly, os.path.commonprefix is a dumb char-by-char string
4727148Sgblack@eecs.umich.edu        # operation that has nothing to do with paths.
4737142Sgblack@eecs.umich.edu        com_pfx = os.path.commonprefix(srcs + tgts)
4747142Sgblack@eecs.umich.edu        com_pfx_len = len(com_pfx)
4757142Sgblack@eecs.umich.edu        if com_pfx:
4767142Sgblack@eecs.umich.edu            # do some cleanup and sanity checking on common prefix
4777142Sgblack@eecs.umich.edu            if com_pfx[-1] == ".":
4786264Sgblack@eecs.umich.edu                # prefix matches all but file extension: ok
4797142Sgblack@eecs.umich.edu                # back up one to change 'foo.cc -> o' to 'foo.cc -> .o'
4806264Sgblack@eecs.umich.edu                com_pfx = com_pfx[0:-1]
4817142Sgblack@eecs.umich.edu            elif com_pfx[-1] == "/":
48212104Snathanael.premillieu@arm.com                # common prefix is directory path: OK
4837142Sgblack@eecs.umich.edu                pass
4847142Sgblack@eecs.umich.edu            else:
4856306Sgblack@eecs.umich.edu                src0_len = len(srcs[0])
4866264Sgblack@eecs.umich.edu                tgt0_len = len(tgts[0])
4876306Sgblack@eecs.umich.edu                if src0_len == com_pfx_len:
4886306Sgblack@eecs.umich.edu                    # source is a substring of target, OK
4896264Sgblack@eecs.umich.edu                    pass
4906306Sgblack@eecs.umich.edu                elif tgt0_len == com_pfx_len:
4916306Sgblack@eecs.umich.edu                    # target is a substring of source, need to back up to
4926306Sgblack@eecs.umich.edu                    # avoid empty string on RHS of arrow
4936306Sgblack@eecs.umich.edu                    sep_idx = com_pfx.rfind(".")
4946264Sgblack@eecs.umich.edu                    if sep_idx != -1:
4956306Sgblack@eecs.umich.edu                        com_pfx = com_pfx[0:sep_idx]
4967142Sgblack@eecs.umich.edu                    else:
4977142Sgblack@eecs.umich.edu                        com_pfx = ''
4987142Sgblack@eecs.umich.edu                elif src0_len > com_pfx_len and srcs[0][com_pfx_len] == ".":
4996306Sgblack@eecs.umich.edu                    # still splitting at file extension: ok
5006306Sgblack@eecs.umich.edu                    pass
5017142Sgblack@eecs.umich.edu                else:
5027142Sgblack@eecs.umich.edu                    # probably a fluke; ignore it
5037142Sgblack@eecs.umich.edu                    com_pfx = ''
5046306Sgblack@eecs.umich.edu        # recalculate length in case com_pfx was modified
5056306Sgblack@eecs.umich.edu        com_pfx_len = len(com_pfx)
5067142Sgblack@eecs.umich.edu        def fmt(files):
5077142Sgblack@eecs.umich.edu            f = map(lambda s: s[com_pfx_len:], files)
5087142Sgblack@eecs.umich.edu            return ', '.join(f)
5096306Sgblack@eecs.umich.edu        return self.format % (com_pfx, fmt(srcs), fmt(tgts))
5106306Sgblack@eecs.umich.edu
5116306Sgblack@eecs.umich.eduExport('Transform')
5127142Sgblack@eecs.umich.edu
5137142Sgblack@eecs.umich.edu# enable the regression script to use the termcap
5147142Sgblack@eecs.umich.edumain['TERMCAP'] = termcap
5156306Sgblack@eecs.umich.edu
5166264Sgblack@eecs.umich.eduif GetOption('verbose'):
5176264Sgblack@eecs.umich.edu    def MakeAction(action, string, *args, **kwargs):
5187142Sgblack@eecs.umich.edu        return Action(action, *args, **kwargs)
5197142Sgblack@eecs.umich.eduelse:
5207142Sgblack@eecs.umich.edu    MakeAction = Action
5216306Sgblack@eecs.umich.edu    main['CCCOMSTR']        = Transform("CC")
5226306Sgblack@eecs.umich.edu    main['CXXCOMSTR']       = Transform("CXX")
5236306Sgblack@eecs.umich.edu    main['ASCOMSTR']        = Transform("AS")
5246306Sgblack@eecs.umich.edu    main['SWIGCOMSTR']      = Transform("SWIG")
5256306Sgblack@eecs.umich.edu    main['ARCOMSTR']        = Transform("AR", 0)
5267142Sgblack@eecs.umich.edu    main['LINKCOMSTR']      = Transform("LINK", 0)
5277142Sgblack@eecs.umich.edu    main['RANLIBCOMSTR']    = Transform("RANLIB", 0)
5286306Sgblack@eecs.umich.edu    main['M4COMSTR']        = Transform("M4")
5296306Sgblack@eecs.umich.edu    main['SHCCCOMSTR']      = Transform("SHCC")
5306306Sgblack@eecs.umich.edu    main['SHCXXCOMSTR']     = Transform("SHCXX")
53112104Snathanael.premillieu@arm.comExport('MakeAction')
5326264Sgblack@eecs.umich.edu
5336264Sgblack@eecs.umich.edu# Initialize the Link-Time Optimization (LTO) flags
5346264Sgblack@eecs.umich.edumain['LTO_CCFLAGS'] = []
5356264Sgblack@eecs.umich.edumain['LTO_LDFLAGS'] = []
53610037SARM gem5 Developers
53710037SARM gem5 Developers# According to the readme, tcmalloc works best if the compiler doesn't
53810037SARM gem5 Developers# assume that we're using the builtin malloc and friends. These flags
53910037SARM gem5 Developers# are compiler-specific, so we need to set them after we detect which
54010037SARM gem5 Developers# compiler we're using.
54110037SARM gem5 Developersmain['TCMALLOC_CCFLAGS'] = []
54212104Snathanael.premillieu@arm.com
54310037SARM gem5 DevelopersCXX_version = readCommand([main['CXX'],'--version'], exception=False)
54410037SARM gem5 DevelopersCXX_V = readCommand([main['CXX'],'-V'], exception=False)
54510037SARM gem5 Developers
54610037SARM gem5 Developersmain['GCC'] = CXX_version and CXX_version.find('g++') >= 0
54710037SARM gem5 Developersmain['CLANG'] = CXX_version and CXX_version.find('clang') >= 0
54810037SARM gem5 Developersif main['GCC'] + main['CLANG'] > 1:
54910037SARM gem5 Developers    print 'Error: How can we have two at the same time?'
55010037SARM gem5 Developers    Exit(1)
55110037SARM gem5 Developers
55210037SARM gem5 Developers# Set up default C++ compiler flags
55310037SARM gem5 Developersif main['GCC'] or main['CLANG']:
55410037SARM gem5 Developers    # As gcc and clang share many flags, do the common parts here
55510037SARM gem5 Developers    main.Append(CCFLAGS=['-pipe'])
55610037SARM gem5 Developers    main.Append(CCFLAGS=['-fno-strict-aliasing'])
55710037SARM gem5 Developers    # Enable -Wall and -Wextra and then disable the few warnings that
55810037SARM gem5 Developers    # we consistently violate
55910037SARM gem5 Developers    main.Append(CCFLAGS=['-Wall', '-Wundef', '-Wextra',
56010037SARM gem5 Developers                         '-Wno-sign-compare', '-Wno-unused-parameter'])
56110037SARM gem5 Developers    # We always compile using C++11
56210037SARM gem5 Developers    main.Append(CXXFLAGS=['-std=c++11'])
56310037SARM gem5 Developerselse:
56410037SARM gem5 Developers    print termcap.Yellow + termcap.Bold + 'Error' + termcap.Normal,
56510037SARM gem5 Developers    print "Don't know what compiler options to use for your compiler."
56610037SARM gem5 Developers    print termcap.Yellow + '       compiler:' + termcap.Normal, main['CXX']
56710037SARM gem5 Developers    print termcap.Yellow + '       version:' + termcap.Normal,
5687148Sgblack@eecs.umich.edu    if not CXX_version:
5697142Sgblack@eecs.umich.edu        print termcap.Yellow + termcap.Bold + "COMMAND NOT FOUND!" +\
5707142Sgblack@eecs.umich.edu               termcap.Normal
57111371Snathanael.premillieu@arm.com    else:
5726264Sgblack@eecs.umich.edu        print CXX_version.replace('\n', '<nl>')
5737142Sgblack@eecs.umich.edu    print "       If you're trying to use a compiler other than GCC"
5746264Sgblack@eecs.umich.edu    print "       or clang, there appears to be something wrong with your"
5756264Sgblack@eecs.umich.edu    print "       environment."
5766264Sgblack@eecs.umich.edu    print "       "
5777142Sgblack@eecs.umich.edu    print "       If you are trying to use a compiler other than those listed"
5786264Sgblack@eecs.umich.edu    print "       above you will need to ease fix SConstruct and "
57912104Snathanael.premillieu@arm.com    print "       src/SConscript to support that compiler."
5806264Sgblack@eecs.umich.edu    Exit(1)
5816264Sgblack@eecs.umich.edu
5826264Sgblack@eecs.umich.eduif main['GCC']:
5837142Sgblack@eecs.umich.edu    # Check for a supported version of gcc. >= 4.7 is chosen for its
5846264Sgblack@eecs.umich.edu    # level of c++11 support. See
5856264Sgblack@eecs.umich.edu    # http://gcc.gnu.org/projects/cxx0x.html for details.
5866264Sgblack@eecs.umich.edu    gcc_version = readCommand([main['CXX'], '-dumpversion'], exception=False)
58712104Snathanael.premillieu@arm.com    if compareVersions(gcc_version, "4.7") < 0:
5886264Sgblack@eecs.umich.edu        print 'Error: gcc version 4.7 or newer required.'
5896264Sgblack@eecs.umich.edu        print '       Installed version:', gcc_version
5906264Sgblack@eecs.umich.edu        Exit(1)
5916264Sgblack@eecs.umich.edu
5926306Sgblack@eecs.umich.edu    main['GCC_VERSION'] = gcc_version
59311371Snathanael.premillieu@arm.com
5946306Sgblack@eecs.umich.edu    # gcc from version 4.8 and above generates "rep; ret" instructions
5957142Sgblack@eecs.umich.edu    # to avoid performance penalties on certain AMD chips. Older
5966306Sgblack@eecs.umich.edu    # assemblers detect this as an error, "Error: expecting string
5976264Sgblack@eecs.umich.edu    # instruction after `rep'"
5986264Sgblack@eecs.umich.edu    if compareVersions(gcc_version, "4.8") > 0:
5996254Sgblack@eecs.umich.edu        as_version_raw = readCommand([main['AS'], '-v', '/dev/null'],
6007148Sgblack@eecs.umich.edu                                     exception=False).split()
6016254Sgblack@eecs.umich.edu
6026253Sgblack@eecs.umich.edu        # version strings may contain extra distro-specific
6036253Sgblack@eecs.umich.edu        # qualifiers, so play it safe and keep only what comes before
6046262Sgblack@eecs.umich.edu        # the first hyphen
6056253Sgblack@eecs.umich.edu        as_version = as_version_raw[-1].split('-')[0] if as_version_raw \
6066253Sgblack@eecs.umich.edu            else None
60711513Sandreas.sandberg@arm.com
60811513Sandreas.sandberg@arm.com        if not as_version or compareVersions(as_version, "2.23") < 0:
60911513Sandreas.sandberg@arm.com            print termcap.Yellow + termcap.Bold + \
61011513Sandreas.sandberg@arm.com                'Warning: This combination of gcc and binutils have' + \
61111513Sandreas.sandberg@arm.com                ' known incompatibilities.\n' + \
61211513Sandreas.sandberg@arm.com                '         If you encounter build problems, please update ' + \
61311513Sandreas.sandberg@arm.com                'binutils to 2.23.' + \
61411513Sandreas.sandberg@arm.com                termcap.Normal
61511513Sandreas.sandberg@arm.com
61611513Sandreas.sandberg@arm.com    # Make sure we warn if the user has requested to compile with the
61711513Sandreas.sandberg@arm.com    # Undefined Benahvior Sanitizer and this version of gcc does not
61811513Sandreas.sandberg@arm.com    # support it.
61911513Sandreas.sandberg@arm.com    if GetOption('with_ubsan') and \
62011513Sandreas.sandberg@arm.com            compareVersions(gcc_version, '4.9') < 0:
62111513Sandreas.sandberg@arm.com        print termcap.Yellow + termcap.Bold + \
62211513Sandreas.sandberg@arm.com            'Warning: UBSan is only supported using gcc 4.9 and later.' + \
62311513Sandreas.sandberg@arm.com            termcap.Normal
62411513Sandreas.sandberg@arm.com
62511513Sandreas.sandberg@arm.com    # Add the appropriate Link-Time Optimization (LTO) flags
6266253Sgblack@eecs.umich.edu    # unless LTO is explicitly turned off. Note that these flags
62711513Sandreas.sandberg@arm.com    # are only used by the fast target.
62811513Sandreas.sandberg@arm.com    if not GetOption('no_lto'):
62911513Sandreas.sandberg@arm.com        # Pass the LTO flag when compiling to produce GIMPLE
63011513Sandreas.sandberg@arm.com        # output, we merely create the flags here and only append
63111513Sandreas.sandberg@arm.com        # them later
63211513Sandreas.sandberg@arm.com        main['LTO_CCFLAGS'] = ['-flto=%d' % GetOption('num_jobs')]
63311513Sandreas.sandberg@arm.com
63411513Sandreas.sandberg@arm.com        # Use the same amount of jobs for LTO as we are running
63511513Sandreas.sandberg@arm.com        # scons with
63611513Sandreas.sandberg@arm.com        main['LTO_LDFLAGS'] = ['-flto=%d' % GetOption('num_jobs')]
63711513Sandreas.sandberg@arm.com
63811513Sandreas.sandberg@arm.com    main.Append(TCMALLOC_CCFLAGS=['-fno-builtin-malloc', '-fno-builtin-calloc',
63911513Sandreas.sandberg@arm.com                                  '-fno-builtin-realloc', '-fno-builtin-free'])
64011513Sandreas.sandberg@arm.com
64111513Sandreas.sandberg@arm.comelif main['CLANG']:
64211513Sandreas.sandberg@arm.com    # Check for a supported version of clang, >= 3.1 is needed to
64311513Sandreas.sandberg@arm.com    # support similar features as gcc 4.7. See
64411513Sandreas.sandberg@arm.com    # http://clang.llvm.org/cxx_status.html for details
64511513Sandreas.sandberg@arm.com    clang_version_re = re.compile(".* version (\d+\.\d+)")
64611513Sandreas.sandberg@arm.com    clang_version_match = clang_version_re.search(CXX_version)
64711513Sandreas.sandberg@arm.com    if (clang_version_match):
64811513Sandreas.sandberg@arm.com        clang_version = clang_version_match.groups()[0]
64911513Sandreas.sandberg@arm.com        if compareVersions(clang_version, "3.1") < 0:
65011513Sandreas.sandberg@arm.com            print 'Error: clang version 3.1 or newer required.'
65111513Sandreas.sandberg@arm.com            print '       Installed version:', clang_version
65211513Sandreas.sandberg@arm.com            Exit(1)
65311513Sandreas.sandberg@arm.com    else:
65411513Sandreas.sandberg@arm.com        print 'Error: Unable to determine clang version.'
65511513Sandreas.sandberg@arm.com        Exit(1)
65611513Sandreas.sandberg@arm.com
65711513Sandreas.sandberg@arm.com    # clang has a few additional warnings that we disable, extraneous
65811513Sandreas.sandberg@arm.com    # parantheses are allowed due to Ruby's printing of the AST,
65911513Sandreas.sandberg@arm.com    # finally self assignments are allowed as the generated CPU code
66011513Sandreas.sandberg@arm.com    # is relying on this
66111513Sandreas.sandberg@arm.com    main.Append(CCFLAGS=['-Wno-parentheses',
66211513Sandreas.sandberg@arm.com                         '-Wno-self-assign',
66311513Sandreas.sandberg@arm.com                         # Some versions of libstdc++ (4.8?) seem to
66411513Sandreas.sandberg@arm.com                         # use struct hash and class hash
66511513Sandreas.sandberg@arm.com                         # interchangeably.
66611513Sandreas.sandberg@arm.com                         '-Wno-mismatched-tags',
66711513Sandreas.sandberg@arm.com                         ])
66811513Sandreas.sandberg@arm.com
66911513Sandreas.sandberg@arm.com    main.Append(TCMALLOC_CCFLAGS=['-fno-builtin'])
67011513Sandreas.sandberg@arm.com
67111513Sandreas.sandberg@arm.com    # On Mac OS X/Darwin we need to also use libc++ (part of XCode) as
67211513Sandreas.sandberg@arm.com    # opposed to libstdc++, as the later is dated.
67311513Sandreas.sandberg@arm.com    if sys.platform == "darwin":
67411513Sandreas.sandberg@arm.com        main.Append(CXXFLAGS=['-stdlib=libc++'])
67511513Sandreas.sandberg@arm.com        main.Append(LIBS=['c++'])
67611513Sandreas.sandberg@arm.com
67711513Sandreas.sandberg@arm.comelse:
67811513Sandreas.sandberg@arm.com    print termcap.Yellow + termcap.Bold + 'Error' + termcap.Normal,
67911513Sandreas.sandberg@arm.com    print "Don't know what compiler options to use for your compiler."
68011513Sandreas.sandberg@arm.com    print termcap.Yellow + '       compiler:' + termcap.Normal, main['CXX']
68111513Sandreas.sandberg@arm.com    print termcap.Yellow + '       version:' + termcap.Normal,
68211513Sandreas.sandberg@arm.com    if not CXX_version:
68311513Sandreas.sandberg@arm.com        print termcap.Yellow + termcap.Bold + "COMMAND NOT FOUND!" +\
68411513Sandreas.sandberg@arm.com               termcap.Normal
68511513Sandreas.sandberg@arm.com    else:
68611513Sandreas.sandberg@arm.com        print CXX_version.replace('\n', '<nl>')
68711513Sandreas.sandberg@arm.com    print "       If you're trying to use a compiler other than GCC"
68811513Sandreas.sandberg@arm.com    print "       or clang, there appears to be something wrong with your"
68911513Sandreas.sandberg@arm.com    print "       environment."
69011513Sandreas.sandberg@arm.com    print "       "
69111513Sandreas.sandberg@arm.com    print "       If you are trying to use a compiler other than those listed"
69211513Sandreas.sandberg@arm.com    print "       above you will need to ease fix SConstruct and "
69311513Sandreas.sandberg@arm.com    print "       src/SConscript to support that compiler."
69411513Sandreas.sandberg@arm.com    Exit(1)
69511513Sandreas.sandberg@arm.com
69611513Sandreas.sandberg@arm.com# Set up common yacc/bison flags (needed for Ruby)
69711513Sandreas.sandberg@arm.commain['YACCFLAGS'] = '-d'
69811513Sandreas.sandberg@arm.commain['YACCHXXFILESUFFIX'] = '.hh'
69911513Sandreas.sandberg@arm.com
70011513Sandreas.sandberg@arm.com# Do this after we save setting back, or else we'll tack on an
70111513Sandreas.sandberg@arm.com# extra 'qdo' every time we run scons.
70211513Sandreas.sandberg@arm.comif main['BATCH']:
70311513Sandreas.sandberg@arm.com    main['CC']     = main['BATCH_CMD'] + ' ' + main['CC']
70411513Sandreas.sandberg@arm.com    main['CXX']    = main['BATCH_CMD'] + ' ' + main['CXX']
70511513Sandreas.sandberg@arm.com    main['AS']     = main['BATCH_CMD'] + ' ' + main['AS']
70611513Sandreas.sandberg@arm.com    main['AR']     = main['BATCH_CMD'] + ' ' + main['AR']
70711513Sandreas.sandberg@arm.com    main['RANLIB'] = main['BATCH_CMD'] + ' ' + main['RANLIB']
70811513Sandreas.sandberg@arm.com
70911513Sandreas.sandberg@arm.comif sys.platform == 'cygwin':
71011513Sandreas.sandberg@arm.com    # cygwin has some header file issues...
71111513Sandreas.sandberg@arm.com    main.Append(CCFLAGS=["-Wno-uninitialized"])
71211513Sandreas.sandberg@arm.com
71311513Sandreas.sandberg@arm.com# Check for the protobuf compiler
71411513Sandreas.sandberg@arm.comprotoc_version = readCommand([main['PROTOC'], '--version'],
71511513Sandreas.sandberg@arm.com                             exception='').split()
71611513Sandreas.sandberg@arm.com
71711513Sandreas.sandberg@arm.com# First two words should be "libprotoc x.y.z"
71811513Sandreas.sandberg@arm.comif len(protoc_version) < 2 or protoc_version[0] != 'libprotoc':
71911513Sandreas.sandberg@arm.com    print termcap.Yellow + termcap.Bold + \
72011513Sandreas.sandberg@arm.com        'Warning: Protocol buffer compiler (protoc) not found.\n' + \
72111513Sandreas.sandberg@arm.com        '         Please install protobuf-compiler for tracing support.' + \
72211513Sandreas.sandberg@arm.com        termcap.Normal
72311513Sandreas.sandberg@arm.com    main['PROTOC'] = False
72411513Sandreas.sandberg@arm.comelse:
72511513Sandreas.sandberg@arm.com    # Based on the availability of the compress stream wrappers,
72611513Sandreas.sandberg@arm.com    # require 2.1.0
72711513Sandreas.sandberg@arm.com    min_protoc_version = '2.1.0'
72811513Sandreas.sandberg@arm.com    if compareVersions(protoc_version[1], min_protoc_version) < 0:
72911513Sandreas.sandberg@arm.com        print termcap.Yellow + termcap.Bold + \
73011513Sandreas.sandberg@arm.com            'Warning: protoc version', min_protoc_version, \
73111513Sandreas.sandberg@arm.com            'or newer required.\n' + \
73211513Sandreas.sandberg@arm.com            '         Installed version:', protoc_version[1], \
73311513Sandreas.sandberg@arm.com            termcap.Normal
73411513Sandreas.sandberg@arm.com        main['PROTOC'] = False
73511513Sandreas.sandberg@arm.com    else:
73611513Sandreas.sandberg@arm.com        # Attempt to determine the appropriate include path and
73711513Sandreas.sandberg@arm.com        # library path using pkg-config, that means we also need to
73812403Sgiacomo.travaglini@arm.com        # check for pkg-config. Note that it is possible to use
73912403Sgiacomo.travaglini@arm.com        # protobuf without the involvement of pkg-config. Later on we
74012403Sgiacomo.travaglini@arm.com        # check go a library config check and at that point the test
74112403Sgiacomo.travaglini@arm.com        # will fail if libprotobuf cannot be found.
74212403Sgiacomo.travaglini@arm.com        if readCommand(['pkg-config', '--version'], exception=''):
74312403Sgiacomo.travaglini@arm.com            try:
74412403Sgiacomo.travaglini@arm.com                # Attempt to establish what linking flags to add for protobuf
74512403Sgiacomo.travaglini@arm.com                # using pkg-config
74612403Sgiacomo.travaglini@arm.com                main.ParseConfig('pkg-config --cflags --libs-only-L protobuf')
74712403Sgiacomo.travaglini@arm.com            except:
74812403Sgiacomo.travaglini@arm.com                print termcap.Yellow + termcap.Bold + \
74912403Sgiacomo.travaglini@arm.com                    'Warning: pkg-config could not get protobuf flags.' + \
75012403Sgiacomo.travaglini@arm.com                    termcap.Normal
75112403Sgiacomo.travaglini@arm.com
75212403Sgiacomo.travaglini@arm.com# Check for SWIG
75312403Sgiacomo.travaglini@arm.comif not main.has_key('SWIG'):
75412403Sgiacomo.travaglini@arm.com    print 'Error: SWIG utility not found.'
75512403Sgiacomo.travaglini@arm.com    print '       Please install (see http://www.swig.org) and retry.'
75612403Sgiacomo.travaglini@arm.com    Exit(1)
75712403Sgiacomo.travaglini@arm.com
75812403Sgiacomo.travaglini@arm.com# Check for appropriate SWIG version
75912403Sgiacomo.travaglini@arm.comswig_version = readCommand([main['SWIG'], '-version'], exception='').split()
76012403Sgiacomo.travaglini@arm.com# First 3 words should be "SWIG Version x.y.z"
76112403Sgiacomo.travaglini@arm.comif len(swig_version) < 3 or \
76212403Sgiacomo.travaglini@arm.com        swig_version[0] != 'SWIG' or swig_version[1] != 'Version':
76312403Sgiacomo.travaglini@arm.com    print 'Error determining SWIG version.'
76412403Sgiacomo.travaglini@arm.com    Exit(1)
76512403Sgiacomo.travaglini@arm.com
76612403Sgiacomo.travaglini@arm.commin_swig_version = '2.0.4'
76712403Sgiacomo.travaglini@arm.comif compareVersions(swig_version[2], min_swig_version) < 0:
76812403Sgiacomo.travaglini@arm.com    print 'Error: SWIG version', min_swig_version, 'or newer required.'
76912403Sgiacomo.travaglini@arm.com    print '       Installed version:', swig_version[2]
77012403Sgiacomo.travaglini@arm.com    Exit(1)
77112403Sgiacomo.travaglini@arm.com
77212403Sgiacomo.travaglini@arm.com# Check for known incompatibilities. The standard library shipped with
77312403Sgiacomo.travaglini@arm.com# gcc >= 4.9 does not play well with swig versions prior to 3.0
77412403Sgiacomo.travaglini@arm.comif main['GCC'] and compareVersions(gcc_version, '4.9') >= 0 and \
77512403Sgiacomo.travaglini@arm.com        compareVersions(swig_version[2], '3.0') < 0:
77612403Sgiacomo.travaglini@arm.com    print termcap.Yellow + termcap.Bold + \
77712403Sgiacomo.travaglini@arm.com        'Warning: This combination of gcc and swig have' + \
77812403Sgiacomo.travaglini@arm.com        ' known incompatibilities.\n' + \
77912403Sgiacomo.travaglini@arm.com        '         If you encounter build problems, please update ' + \
78012403Sgiacomo.travaglini@arm.com        'swig to 3.0 or later.' + \
78112403Sgiacomo.travaglini@arm.com        termcap.Normal
78212403Sgiacomo.travaglini@arm.com
78312403Sgiacomo.travaglini@arm.com# Set up SWIG flags & scanner
78412403Sgiacomo.travaglini@arm.comswig_flags=Split('-c++ -python -modern -templatereduce $_CPPINCFLAGS')
78512403Sgiacomo.travaglini@arm.commain.Append(SWIGFLAGS=swig_flags)
78612403Sgiacomo.travaglini@arm.com
78712403Sgiacomo.travaglini@arm.com# Check for 'timeout' from GNU coreutils. If present, regressions will
78812403Sgiacomo.travaglini@arm.com# be run with a time limit. We require version 8.13 since we rely on
78912403Sgiacomo.travaglini@arm.com# support for the '--foreground' option.
79012403Sgiacomo.travaglini@arm.comtimeout_lines = readCommand(['timeout', '--version'],
79112403Sgiacomo.travaglini@arm.com                            exception='').splitlines()
79212403Sgiacomo.travaglini@arm.com# Get the first line and tokenize it
79312403Sgiacomo.travaglini@arm.comtimeout_version = timeout_lines[0].split() if timeout_lines else []
79412403Sgiacomo.travaglini@arm.commain['TIMEOUT'] =  timeout_version and \
79512403Sgiacomo.travaglini@arm.com    compareVersions(timeout_version[-1], '8.13') >= 0
79612403Sgiacomo.travaglini@arm.com
79712403Sgiacomo.travaglini@arm.com# filter out all existing swig scanners, they mess up the dependency
79812403Sgiacomo.travaglini@arm.com# stuff for some reason
79912403Sgiacomo.travaglini@arm.comscanners = []
80012403Sgiacomo.travaglini@arm.comfor scanner in main['SCANNERS']:
80112403Sgiacomo.travaglini@arm.com    skeys = scanner.skeys
80212403Sgiacomo.travaglini@arm.com    if skeys == '.i':
80312403Sgiacomo.travaglini@arm.com        continue
80412403Sgiacomo.travaglini@arm.com
80512403Sgiacomo.travaglini@arm.com    if isinstance(skeys, (list, tuple)) and '.i' in skeys:
80612403Sgiacomo.travaglini@arm.com        continue
80712403Sgiacomo.travaglini@arm.com
80812403Sgiacomo.travaglini@arm.com    scanners.append(scanner)
80912403Sgiacomo.travaglini@arm.com
81012403Sgiacomo.travaglini@arm.com# add the new swig scanner that we like better
81112403Sgiacomo.travaglini@arm.comfrom SCons.Scanner import ClassicCPP as CPPScanner
81212403Sgiacomo.travaglini@arm.comswig_inc_re = '^[ \t]*[%,#][ \t]*(?:include|import)[ \t]*(<|")([^>"]+)(>|")'
81312403Sgiacomo.travaglini@arm.comscanners.append(CPPScanner("SwigScan", [ ".i" ], "CPPPATH", swig_inc_re))
81412403Sgiacomo.travaglini@arm.com
81512403Sgiacomo.travaglini@arm.com# replace the scanners list that has what we want
81612403Sgiacomo.travaglini@arm.commain['SCANNERS'] = scanners
81712403Sgiacomo.travaglini@arm.com
81812403Sgiacomo.travaglini@arm.com# Add a custom Check function to test for structure members.
81912403Sgiacomo.travaglini@arm.comdef CheckMember(context, include, decl, member, include_quotes="<>"):
82012403Sgiacomo.travaglini@arm.com    context.Message("Checking for member %s in %s..." %
82112403Sgiacomo.travaglini@arm.com                    (member, decl))
82212403Sgiacomo.travaglini@arm.com    text = """
82312403Sgiacomo.travaglini@arm.com#include %(header)s
82412403Sgiacomo.travaglini@arm.comint main(){
82512403Sgiacomo.travaglini@arm.com  %(decl)s test;
82612403Sgiacomo.travaglini@arm.com  (void)test.%(member)s;
82712403Sgiacomo.travaglini@arm.com  return 0;
82812403Sgiacomo.travaglini@arm.com};
82912403Sgiacomo.travaglini@arm.com""" % { "header" : include_quotes[0] + include + include_quotes[1],
83012403Sgiacomo.travaglini@arm.com        "decl" : decl,
83112403Sgiacomo.travaglini@arm.com        "member" : member,
83212403Sgiacomo.travaglini@arm.com        }
83312403Sgiacomo.travaglini@arm.com
83412403Sgiacomo.travaglini@arm.com    ret = context.TryCompile(text, extension=".cc")
83512403Sgiacomo.travaglini@arm.com    context.Result(ret)
83612403Sgiacomo.travaglini@arm.com    return ret
83712403Sgiacomo.travaglini@arm.com
83812403Sgiacomo.travaglini@arm.com# Platform-specific configuration.  Note again that we assume that all
83912403Sgiacomo.travaglini@arm.com# builds under a given build root run on the same host platform.
84012403Sgiacomo.travaglini@arm.comconf = Configure(main,
84112403Sgiacomo.travaglini@arm.com                 conf_dir = joinpath(build_root, '.scons_config'),
84212403Sgiacomo.travaglini@arm.com                 log_file = joinpath(build_root, 'scons_config.log'),
84312403Sgiacomo.travaglini@arm.com                 custom_tests = {
84412403Sgiacomo.travaglini@arm.com        'CheckMember' : CheckMember,
84512403Sgiacomo.travaglini@arm.com        })
84612403Sgiacomo.travaglini@arm.com
84712403Sgiacomo.travaglini@arm.com# Check if we should compile a 64 bit binary on Mac OS X/Darwin
84812403Sgiacomo.travaglini@arm.comtry:
84912403Sgiacomo.travaglini@arm.com    import platform
85012403Sgiacomo.travaglini@arm.com    uname = platform.uname()
85112403Sgiacomo.travaglini@arm.com    if uname[0] == 'Darwin' and compareVersions(uname[2], '9.0.0') >= 0:
85212403Sgiacomo.travaglini@arm.com        if int(readCommand('sysctl -n hw.cpu64bit_capable')[0]):
85312403Sgiacomo.travaglini@arm.com            main.Append(CCFLAGS=['-arch', 'x86_64'])
85412403Sgiacomo.travaglini@arm.com            main.Append(CFLAGS=['-arch', 'x86_64'])
85512403Sgiacomo.travaglini@arm.com            main.Append(LINKFLAGS=['-arch', 'x86_64'])
85612403Sgiacomo.travaglini@arm.com            main.Append(ASFLAGS=['-arch', 'x86_64'])
85712403Sgiacomo.travaglini@arm.comexcept:
85812403Sgiacomo.travaglini@arm.com    pass
85912403Sgiacomo.travaglini@arm.com
86012403Sgiacomo.travaglini@arm.com# Recent versions of scons substitute a "Null" object for Configure()
86111513Sandreas.sandberg@arm.com# when configuration isn't necessary, e.g., if the "--help" option is
86212498Sgiacomo.travaglini@arm.com# present.  Unfortuantely this Null object always returns false,
86312498Sgiacomo.travaglini@arm.com# breaking all our configuration checks.  We replace it with our own
86412498Sgiacomo.travaglini@arm.com# more optimistic null object that returns True instead.
86512498Sgiacomo.travaglini@arm.comif not conf:
86612498Sgiacomo.travaglini@arm.com    def NullCheck(*args, **kwargs):
86712498Sgiacomo.travaglini@arm.com        return True
86812498Sgiacomo.travaglini@arm.com
86912498Sgiacomo.travaglini@arm.com    class NullConf:
87012498Sgiacomo.travaglini@arm.com        def __init__(self, env):
87112498Sgiacomo.travaglini@arm.com            self.env = env
87212498Sgiacomo.travaglini@arm.com        def Finish(self):
87312498Sgiacomo.travaglini@arm.com            return self.env
87412498Sgiacomo.travaglini@arm.com        def __getattr__(self, mname):
87512498Sgiacomo.travaglini@arm.com            return NullCheck
87612498Sgiacomo.travaglini@arm.com
87712498Sgiacomo.travaglini@arm.com    conf = NullConf(main)
87812498Sgiacomo.travaglini@arm.com
87912498Sgiacomo.travaglini@arm.com# Cache build files in the supplied directory.
88012498Sgiacomo.travaglini@arm.comif main['M5_BUILD_CACHE']:
88112498Sgiacomo.travaglini@arm.com    print 'Using build cache located at', main['M5_BUILD_CACHE']
88212498Sgiacomo.travaglini@arm.com    CacheDir(main['M5_BUILD_CACHE'])
88312499Sgiacomo.travaglini@arm.com
88412498Sgiacomo.travaglini@arm.comif not GetOption('without_python'):
88512498Sgiacomo.travaglini@arm.com    # Find Python include and library directories for embedding the
88612498Sgiacomo.travaglini@arm.com    # interpreter. We rely on python-config to resolve the appropriate
88712498Sgiacomo.travaglini@arm.com    # includes and linker flags. ParseConfig does not seem to understand
88812498Sgiacomo.travaglini@arm.com    # the more exotic linker flags such as -Xlinker and -export-dynamic so
88912498Sgiacomo.travaglini@arm.com    # we add them explicitly below. If you want to link in an alternate
89012498Sgiacomo.travaglini@arm.com    # version of python, see above for instructions on how to invoke
89112498Sgiacomo.travaglini@arm.com    # scons with the appropriate PATH set.
89212498Sgiacomo.travaglini@arm.com    #
89312498Sgiacomo.travaglini@arm.com    # First we check if python2-config exists, else we use python-config
89412498Sgiacomo.travaglini@arm.com    python_config = readCommand(['which', 'python2-config'],
89512498Sgiacomo.travaglini@arm.com                                exception='').strip()
89612498Sgiacomo.travaglini@arm.com    if not os.path.exists(python_config):
89712498Sgiacomo.travaglini@arm.com        python_config = readCommand(['which', 'python-config'],
89812498Sgiacomo.travaglini@arm.com                                    exception='').strip()
89912498Sgiacomo.travaglini@arm.com    py_includes = readCommand([python_config, '--includes'],
90012498Sgiacomo.travaglini@arm.com                              exception='').split()
90112498Sgiacomo.travaglini@arm.com    # Strip the -I from the include folders before adding them to the
90212498Sgiacomo.travaglini@arm.com    # CPPPATH
90312498Sgiacomo.travaglini@arm.com    main.Append(CPPPATH=map(lambda inc: inc[2:], py_includes))
90412498Sgiacomo.travaglini@arm.com
90512498Sgiacomo.travaglini@arm.com    # Read the linker flags and split them into libraries and other link
90612498Sgiacomo.travaglini@arm.com    # flags. The libraries are added later through the call the CheckLib.
90712498Sgiacomo.travaglini@arm.com    py_ld_flags = readCommand([python_config, '--ldflags'],
90812498Sgiacomo.travaglini@arm.com        exception='').split()
90912498Sgiacomo.travaglini@arm.com    py_libs = []
91012498Sgiacomo.travaglini@arm.com    for lib in py_ld_flags:
91112498Sgiacomo.travaglini@arm.com         if not lib.startswith('-l'):
91212498Sgiacomo.travaglini@arm.com             main.Append(LINKFLAGS=[lib])
91312498Sgiacomo.travaglini@arm.com         else:
91412498Sgiacomo.travaglini@arm.com             lib = lib[2:]
91512498Sgiacomo.travaglini@arm.com             if lib not in py_libs:
91612498Sgiacomo.travaglini@arm.com                 py_libs.append(lib)
91712498Sgiacomo.travaglini@arm.com
91812498Sgiacomo.travaglini@arm.com    # verify that this stuff works
91912498Sgiacomo.travaglini@arm.com    if not conf.CheckHeader('Python.h', '<>'):
92012498Sgiacomo.travaglini@arm.com        print "Error: can't find Python.h header in", py_includes
92112498Sgiacomo.travaglini@arm.com        print "Install Python headers (package python-dev on Ubuntu and RedHat)"
92212498Sgiacomo.travaglini@arm.com        Exit(1)
92312498Sgiacomo.travaglini@arm.com
92412498Sgiacomo.travaglini@arm.com    for lib in py_libs:
92512498Sgiacomo.travaglini@arm.com        if not conf.CheckLib(lib):
92612498Sgiacomo.travaglini@arm.com            print "Error: can't find library %s required by python" % lib
92712498Sgiacomo.travaglini@arm.com            Exit(1)
92812498Sgiacomo.travaglini@arm.com
92912498Sgiacomo.travaglini@arm.com# On Solaris you need to use libsocket for socket ops
93012498Sgiacomo.travaglini@arm.comif not conf.CheckLibWithHeader(None, 'sys/socket.h', 'C++', 'accept(0,0,0);'):
93112498Sgiacomo.travaglini@arm.com   if not conf.CheckLibWithHeader('socket', 'sys/socket.h', 'C++', 'accept(0,0,0);'):
93212498Sgiacomo.travaglini@arm.com       print "Can't find library with socket calls (e.g. accept())"
93311514Sandreas.sandberg@arm.com       Exit(1)
93411514Sandreas.sandberg@arm.com
93511514Sandreas.sandberg@arm.com# Check for zlib.  If the check passes, libz will be automatically
93611514Sandreas.sandberg@arm.com# added to the LIBS environment variable.
93711514Sandreas.sandberg@arm.comif not conf.CheckLibWithHeader('z', 'zlib.h', 'C++','zlibVersion();'):
93811514Sandreas.sandberg@arm.com    print 'Error: did not find needed zlib compression library '\
93911514Sandreas.sandberg@arm.com          'and/or zlib.h header file.'
94011514Sandreas.sandberg@arm.com    print '       Please install zlib and try again.'
94111514Sandreas.sandberg@arm.com    Exit(1)
94211514Sandreas.sandberg@arm.com
94311514Sandreas.sandberg@arm.com# If we have the protobuf compiler, also make sure we have the
94411514Sandreas.sandberg@arm.com# development libraries. If the check passes, libprotobuf will be
94511514Sandreas.sandberg@arm.com# automatically added to the LIBS environment variable. After
94611514Sandreas.sandberg@arm.com# this, we can use the HAVE_PROTOBUF flag to determine if we have
94711514Sandreas.sandberg@arm.com# got both protoc and libprotobuf available.
94811514Sandreas.sandberg@arm.commain['HAVE_PROTOBUF'] = main['PROTOC'] and \
94911514Sandreas.sandberg@arm.com    conf.CheckLibWithHeader('protobuf', 'google/protobuf/message.h',
95011514Sandreas.sandberg@arm.com                            'C++', 'GOOGLE_PROTOBUF_VERIFY_VERSION;')
95111514Sandreas.sandberg@arm.com
95211514Sandreas.sandberg@arm.com# If we have the compiler but not the library, print another warning.
95311514Sandreas.sandberg@arm.comif main['PROTOC'] and not main['HAVE_PROTOBUF']:
95411514Sandreas.sandberg@arm.com    print termcap.Yellow + termcap.Bold + \
95511514Sandreas.sandberg@arm.com        'Warning: did not find protocol buffer library and/or headers.\n' + \
95611514Sandreas.sandberg@arm.com    '       Please install libprotobuf-dev for tracing support.' + \
95711514Sandreas.sandberg@arm.com    termcap.Normal
95811514Sandreas.sandberg@arm.com
95911514Sandreas.sandberg@arm.com# Check for librt.
96011513Sandreas.sandberg@arm.comhave_posix_clock = \
96111514Sandreas.sandberg@arm.com    conf.CheckLibWithHeader(None, 'time.h', 'C',
96211514Sandreas.sandberg@arm.com                            'clock_nanosleep(0,0,NULL,NULL);') or \
96311514Sandreas.sandberg@arm.com    conf.CheckLibWithHeader('rt', 'time.h', 'C',
96411514Sandreas.sandberg@arm.com                            'clock_nanosleep(0,0,NULL,NULL);')
96511514Sandreas.sandberg@arm.com
96611514Sandreas.sandberg@arm.comhave_posix_timers = \
96711514Sandreas.sandberg@arm.com    conf.CheckLibWithHeader([None, 'rt'], [ 'time.h', 'signal.h' ], 'C',
96811514Sandreas.sandberg@arm.com                            'timer_create(CLOCK_MONOTONIC, NULL, NULL);')
96911514Sandreas.sandberg@arm.com
97011514Sandreas.sandberg@arm.comif not GetOption('without_tcmalloc'):
97112497Sgiacomo.travaglini@arm.com    if conf.CheckLib('tcmalloc'):
97212497Sgiacomo.travaglini@arm.com        main.Append(CCFLAGS=main['TCMALLOC_CCFLAGS'])
97312497Sgiacomo.travaglini@arm.com    elif conf.CheckLib('tcmalloc_minimal'):
97412497Sgiacomo.travaglini@arm.com        main.Append(CCFLAGS=main['TCMALLOC_CCFLAGS'])
97511514Sandreas.sandberg@arm.com    else:
97611514Sandreas.sandberg@arm.com        print termcap.Yellow + termcap.Bold + \
97711514Sandreas.sandberg@arm.com              "You can get a 12% performance improvement by "\
97812497Sgiacomo.travaglini@arm.com              "installing tcmalloc (libgoogle-perftools-dev package "\
97911514Sandreas.sandberg@arm.com              "on Ubuntu or RedHat)." + termcap.Normal
98011514Sandreas.sandberg@arm.com
98112497Sgiacomo.travaglini@arm.com
98212497Sgiacomo.travaglini@arm.com# Detect back trace implementations. The last implementation in the
98312497Sgiacomo.travaglini@arm.com# list will be used by default.
98412497Sgiacomo.travaglini@arm.combacktrace_impls = [ "none" ]
98512497Sgiacomo.travaglini@arm.com
98612497Sgiacomo.travaglini@arm.comif conf.CheckLibWithHeader(None, 'execinfo.h', 'C',
98712497Sgiacomo.travaglini@arm.com                           'backtrace_symbols_fd((void*)0, 0, 0);'):
98812497Sgiacomo.travaglini@arm.com    backtrace_impls.append("glibc")
98912497Sgiacomo.travaglini@arm.com
99012497Sgiacomo.travaglini@arm.comif backtrace_impls[-1] == "none":
99112497Sgiacomo.travaglini@arm.com    default_backtrace_impl = "none"
99212497Sgiacomo.travaglini@arm.com    print termcap.Yellow + termcap.Bold + \
99311514Sandreas.sandberg@arm.com        "No suitable back trace implementation found." + \
99411514Sandreas.sandberg@arm.com        termcap.Normal
99511514Sandreas.sandberg@arm.com
99611514Sandreas.sandberg@arm.comif not have_posix_clock:
99711514Sandreas.sandberg@arm.com    print "Can't find library for POSIX clocks."
99811514Sandreas.sandberg@arm.com
99911514Sandreas.sandberg@arm.com# Check for <fenv.h> (C99 FP environment control)
100011514Sandreas.sandberg@arm.comhave_fenv = conf.CheckHeader('fenv.h', '<>')
100111514Sandreas.sandberg@arm.comif not have_fenv:
100211514Sandreas.sandberg@arm.com    print "Warning: Header file <fenv.h> not found."
100311514Sandreas.sandberg@arm.com    print "         This host has no IEEE FP rounding mode control."
100412497Sgiacomo.travaglini@arm.com
100511514Sandreas.sandberg@arm.com# Check if we should enable KVM-based hardware virtualization. The API
100611514Sandreas.sandberg@arm.com# we rely on exists since version 2.6.36 of the kernel, but somehow
100711514Sandreas.sandberg@arm.com# the KVM_API_VERSION does not reflect the change. We test for one of
100811514Sandreas.sandberg@arm.com# the types as a fall back.
100911514Sandreas.sandberg@arm.comhave_kvm = conf.CheckHeader('linux/kvm.h', '<>')
101011514Sandreas.sandberg@arm.comif not have_kvm:
101111514Sandreas.sandberg@arm.com    print "Info: Compatible header file <linux/kvm.h> not found, " \
101211514Sandreas.sandberg@arm.com        "disabling KVM support."
101311514Sandreas.sandberg@arm.com
101411514Sandreas.sandberg@arm.com# x86 needs support for xsave. We test for the structure here since we
101511514Sandreas.sandberg@arm.com# won't be able to run new tests by the time we know which ISA we're
101611514Sandreas.sandberg@arm.com# targeting.
101711514Sandreas.sandberg@arm.comhave_kvm_xsave = conf.CheckTypeSize('struct kvm_xsave',
101811514Sandreas.sandberg@arm.com                                    '#include <linux/kvm.h>') != 0
101911514Sandreas.sandberg@arm.com
102011514Sandreas.sandberg@arm.com# Check if the requested target ISA is compatible with the host
102112510Sgiacomo.travaglini@arm.comdef is_isa_kvm_compatible(isa):
102212510Sgiacomo.travaglini@arm.com    try:
102312510Sgiacomo.travaglini@arm.com        import platform
102411514Sandreas.sandberg@arm.com        host_isa = platform.machine()
102512510Sgiacomo.travaglini@arm.com    except:
102612510Sgiacomo.travaglini@arm.com        print "Warning: Failed to determine host ISA."
102712510Sgiacomo.travaglini@arm.com        return False
102812510Sgiacomo.travaglini@arm.com
102912510Sgiacomo.travaglini@arm.com    if not have_posix_timers:
103012510Sgiacomo.travaglini@arm.com        print "Warning: Can not enable KVM, host seems to lack support " \
103112510Sgiacomo.travaglini@arm.com            "for POSIX timers"
103211514Sandreas.sandberg@arm.com        return False
103311514Sandreas.sandberg@arm.com
103411514Sandreas.sandberg@arm.com    if isa == "arm":
103511514Sandreas.sandberg@arm.com        return host_isa in ( "armv7l", "aarch64" )
103611514Sandreas.sandberg@arm.com    elif isa == "x86":
103711514Sandreas.sandberg@arm.com        if host_isa != "x86_64":
103811514Sandreas.sandberg@arm.com            return False
103911514Sandreas.sandberg@arm.com
104011514Sandreas.sandberg@arm.com        if not have_kvm_xsave:
104111514Sandreas.sandberg@arm.com            print "KVM on x86 requires xsave support in kernel headers."
104211514Sandreas.sandberg@arm.com            return False
104311514Sandreas.sandberg@arm.com
104411514Sandreas.sandberg@arm.com        return True
104511514Sandreas.sandberg@arm.com    else:
104611514Sandreas.sandberg@arm.com        return False
104711514Sandreas.sandberg@arm.com
104811514Sandreas.sandberg@arm.com
104911514Sandreas.sandberg@arm.com# Check if the exclude_host attribute is available. We want this to
105011514Sandreas.sandberg@arm.com# get accurate instruction counts in KVM.
105111514Sandreas.sandberg@arm.commain['HAVE_PERF_ATTR_EXCLUDE_HOST'] = conf.CheckMember(
105211514Sandreas.sandberg@arm.com    'linux/perf_event.h', 'struct perf_event_attr', 'exclude_host')
105311514Sandreas.sandberg@arm.com
105411514Sandreas.sandberg@arm.com
105511514Sandreas.sandberg@arm.com######################################################################
105611514Sandreas.sandberg@arm.com#
105711514Sandreas.sandberg@arm.com# Finish the configuration
105811514Sandreas.sandberg@arm.com#
105911514Sandreas.sandberg@arm.commain = conf.Finish()
106011514Sandreas.sandberg@arm.com
106111514Sandreas.sandberg@arm.com######################################################################
106211514Sandreas.sandberg@arm.com#
106311514Sandreas.sandberg@arm.com# Collect all non-global variables
106411514Sandreas.sandberg@arm.com#
106512498Sgiacomo.travaglini@arm.com
106612498Sgiacomo.travaglini@arm.com# Define the universe of supported ISAs
106712498Sgiacomo.travaglini@arm.comall_isa_list = [ ]
106812498Sgiacomo.travaglini@arm.comall_gpu_isa_list = [ ]
106912498Sgiacomo.travaglini@arm.comExport('all_isa_list')
107012498Sgiacomo.travaglini@arm.comExport('all_gpu_isa_list')
107112498Sgiacomo.travaglini@arm.com
107212498Sgiacomo.travaglini@arm.comclass CpuModel(object):
107312498Sgiacomo.travaglini@arm.com    '''The CpuModel class encapsulates everything the ISA parser needs to
107412498Sgiacomo.travaglini@arm.com    know about a particular CPU model.'''
107512498Sgiacomo.travaglini@arm.com
107612498Sgiacomo.travaglini@arm.com    # Dict of available CPU model objects.  Accessible as CpuModel.dict.
107711514Sandreas.sandberg@arm.com    dict = {}
107811514Sandreas.sandberg@arm.com
107911514Sandreas.sandberg@arm.com    # Constructor.  Automatically adds models to CpuModel.dict.
1080    def __init__(self, name, default=False):
1081        self.name = name           # name of model
1082
1083        # This cpu is enabled by default
1084        self.default = default
1085
1086        # Add self to dict
1087        if name in CpuModel.dict:
1088            raise AttributeError, "CpuModel '%s' already registered" % name
1089        CpuModel.dict[name] = self
1090
1091Export('CpuModel')
1092
1093# Sticky variables get saved in the variables file so they persist from
1094# one invocation to the next (unless overridden, in which case the new
1095# value becomes sticky).
1096sticky_vars = Variables(args=ARGUMENTS)
1097Export('sticky_vars')
1098
1099# Sticky variables that should be exported
1100export_vars = []
1101Export('export_vars')
1102
1103# For Ruby
1104all_protocols = []
1105Export('all_protocols')
1106protocol_dirs = []
1107Export('protocol_dirs')
1108slicc_includes = []
1109Export('slicc_includes')
1110
1111# Walk the tree and execute all SConsopts scripts that wil add to the
1112# above variables
1113if GetOption('verbose'):
1114    print "Reading SConsopts"
1115for bdir in [ base_dir ] + extras_dir_list:
1116    if not isdir(bdir):
1117        print "Error: directory '%s' does not exist" % bdir
1118        Exit(1)
1119    for root, dirs, files in os.walk(bdir):
1120        if 'SConsopts' in files:
1121            if GetOption('verbose'):
1122                print "Reading", joinpath(root, 'SConsopts')
1123            SConscript(joinpath(root, 'SConsopts'))
1124
1125all_isa_list.sort()
1126all_gpu_isa_list.sort()
1127
1128sticky_vars.AddVariables(
1129    EnumVariable('TARGET_ISA', 'Target ISA', 'alpha', all_isa_list),
1130    EnumVariable('TARGET_GPU_ISA', 'Target GPU ISA', 'hsail', all_gpu_isa_list),
1131    ListVariable('CPU_MODELS', 'CPU models',
1132                 sorted(n for n,m in CpuModel.dict.iteritems() if m.default),
1133                 sorted(CpuModel.dict.keys())),
1134    BoolVariable('EFENCE', 'Link with Electric Fence malloc debugger',
1135                 False),
1136    BoolVariable('SS_COMPATIBLE_FP',
1137                 'Make floating-point results compatible with SimpleScalar',
1138                 False),
1139    BoolVariable('USE_SSE2',
1140                 'Compile for SSE2 (-msse2) to get IEEE FP on x86 hosts',
1141                 False),
1142    BoolVariable('USE_POSIX_CLOCK', 'Use POSIX Clocks', have_posix_clock),
1143    BoolVariable('USE_FENV', 'Use <fenv.h> IEEE mode control', have_fenv),
1144    BoolVariable('CP_ANNOTATE', 'Enable critical path annotation capability', False),
1145    BoolVariable('USE_KVM', 'Enable hardware virtualized (KVM) CPU models', have_kvm),
1146    BoolVariable('BUILD_GPU', 'Build the compute-GPU model', False),
1147    EnumVariable('PROTOCOL', 'Coherence protocol for Ruby', 'None',
1148                  all_protocols),
1149    EnumVariable('BACKTRACE_IMPL', 'Post-mortem dump implementation',
1150                 backtrace_impls[-1], backtrace_impls)
1151    )
1152
1153# These variables get exported to #defines in config/*.hh (see src/SConscript).
1154export_vars += ['USE_FENV', 'SS_COMPATIBLE_FP', 'TARGET_ISA', 'TARGET_GPU_ISA',
1155                'CP_ANNOTATE', 'USE_POSIX_CLOCK', 'USE_KVM', 'PROTOCOL',
1156                'HAVE_PROTOBUF', 'HAVE_PERF_ATTR_EXCLUDE_HOST']
1157
1158###################################################
1159#
1160# Define a SCons builder for configuration flag headers.
1161#
1162###################################################
1163
1164# This function generates a config header file that #defines the
1165# variable symbol to the current variable setting (0 or 1).  The source
1166# operands are the name of the variable and a Value node containing the
1167# value of the variable.
1168def build_config_file(target, source, env):
1169    (variable, value) = [s.get_contents() for s in source]
1170    f = file(str(target[0]), 'w')
1171    print >> f, '#define', variable, value
1172    f.close()
1173    return None
1174
1175# Combine the two functions into a scons Action object.
1176config_action = MakeAction(build_config_file, Transform("CONFIG H", 2))
1177
1178# The emitter munges the source & target node lists to reflect what
1179# we're really doing.
1180def config_emitter(target, source, env):
1181    # extract variable name from Builder arg
1182    variable = str(target[0])
1183    # True target is config header file
1184    target = joinpath('config', variable.lower() + '.hh')
1185    val = env[variable]
1186    if isinstance(val, bool):
1187        # Force value to 0/1
1188        val = int(val)
1189    elif isinstance(val, str):
1190        val = '"' + val + '"'
1191
1192    # Sources are variable name & value (packaged in SCons Value nodes)
1193    return ([target], [Value(variable), Value(val)])
1194
1195config_builder = Builder(emitter = config_emitter, action = config_action)
1196
1197main.Append(BUILDERS = { 'ConfigFile' : config_builder })
1198
1199# libelf build is shared across all configs in the build root.
1200main.SConscript('ext/libelf/SConscript',
1201                variant_dir = joinpath(build_root, 'libelf'))
1202
1203# iostream3 build is shared across all configs in the build root.
1204main.SConscript('ext/iostream3/SConscript',
1205                variant_dir = joinpath(build_root, 'iostream3'))
1206
1207# libfdt build is shared across all configs in the build root.
1208main.SConscript('ext/libfdt/SConscript',
1209                variant_dir = joinpath(build_root, 'libfdt'))
1210
1211# fputils build is shared across all configs in the build root.
1212main.SConscript('ext/fputils/SConscript',
1213                variant_dir = joinpath(build_root, 'fputils'))
1214
1215# DRAMSim2 build is shared across all configs in the build root.
1216main.SConscript('ext/dramsim2/SConscript',
1217                variant_dir = joinpath(build_root, 'dramsim2'))
1218
1219# DRAMPower build is shared across all configs in the build root.
1220main.SConscript('ext/drampower/SConscript',
1221                variant_dir = joinpath(build_root, 'drampower'))
1222
1223# nomali build is shared across all configs in the build root.
1224main.SConscript('ext/nomali/SConscript',
1225                variant_dir = joinpath(build_root, 'nomali'))
1226
1227###################################################
1228#
1229# This function is used to set up a directory with switching headers
1230#
1231###################################################
1232
1233main['ALL_ISA_LIST'] = all_isa_list
1234main['ALL_GPU_ISA_LIST'] = all_gpu_isa_list
1235all_isa_deps = {}
1236def make_switching_dir(dname, switch_headers, env):
1237    # Generate the header.  target[0] is the full path of the output
1238    # header to generate.  'source' is a dummy variable, since we get the
1239    # list of ISAs from env['ALL_ISA_LIST'].
1240    def gen_switch_hdr(target, source, env):
1241        fname = str(target[0])
1242        isa = env['TARGET_ISA'].lower()
1243        try:
1244            f = open(fname, 'w')
1245            print >>f, '#include "%s/%s/%s"' % (dname, isa, basename(fname))
1246            f.close()
1247        except IOError:
1248            print "Failed to create %s" % fname
1249            raise
1250
1251    # Build SCons Action object. 'varlist' specifies env vars that this
1252    # action depends on; when env['ALL_ISA_LIST'] changes these actions
1253    # should get re-executed.
1254    switch_hdr_action = MakeAction(gen_switch_hdr,
1255                          Transform("GENERATE"), varlist=['ALL_ISA_LIST'])
1256
1257    # Instantiate actions for each header
1258    for hdr in switch_headers:
1259        env.Command(hdr, [], switch_hdr_action)
1260
1261    isa_target = Dir('.').up().name.lower().replace('_', '-')
1262    env['PHONY_BASE'] = '#'+isa_target
1263    all_isa_deps[isa_target] = None
1264
1265Export('make_switching_dir')
1266
1267def make_gpu_switching_dir(dname, switch_headers, env):
1268    # Generate the header.  target[0] is the full path of the output
1269    # header to generate.  'source' is a dummy variable, since we get the
1270    # list of ISAs from env['ALL_ISA_LIST'].
1271    def gen_switch_hdr(target, source, env):
1272        fname = str(target[0])
1273
1274        isa = env['TARGET_GPU_ISA'].lower()
1275
1276        try:
1277            f = open(fname, 'w')
1278            print >>f, '#include "%s/%s/%s"' % (dname, isa, basename(fname))
1279            f.close()
1280        except IOError:
1281            print "Failed to create %s" % fname
1282            raise
1283
1284    # Build SCons Action object. 'varlist' specifies env vars that this
1285    # action depends on; when env['ALL_ISA_LIST'] changes these actions
1286    # should get re-executed.
1287    switch_hdr_action = MakeAction(gen_switch_hdr,
1288                          Transform("GENERATE"), varlist=['ALL_ISA_GPU_LIST'])
1289
1290    # Instantiate actions for each header
1291    for hdr in switch_headers:
1292        env.Command(hdr, [], switch_hdr_action)
1293
1294Export('make_gpu_switching_dir')
1295
1296# all-isas -> all-deps -> all-environs -> all_targets
1297main.Alias('#all-isas', [])
1298main.Alias('#all-deps', '#all-isas')
1299
1300# Dummy target to ensure all environments are created before telling
1301# SCons what to actually make (the command line arguments).  We attach
1302# them to the dependence graph after the environments are complete.
1303ORIG_BUILD_TARGETS = list(BUILD_TARGETS) # force a copy; gets closure to work.
1304def environsComplete(target, source, env):
1305    for t in ORIG_BUILD_TARGETS:
1306        main.Depends('#all-targets', t)
1307
1308# Each build/* switching_dir attaches its *-environs target to #all-environs.
1309main.Append(BUILDERS = {'CompleteEnvirons' :
1310                        Builder(action=MakeAction(environsComplete, None))})
1311main.CompleteEnvirons('#all-environs', [])
1312
1313def doNothing(**ignored): pass
1314main.Append(BUILDERS = {'Dummy': Builder(action=MakeAction(doNothing, None))})
1315
1316# The final target to which all the original targets ultimately get attached.
1317main.Dummy('#all-targets', '#all-environs')
1318BUILD_TARGETS[:] = ['#all-targets']
1319
1320###################################################
1321#
1322# Define build environments for selected configurations.
1323#
1324###################################################
1325
1326for variant_path in variant_paths:
1327    if not GetOption('silent'):
1328        print "Building in", variant_path
1329
1330    # Make a copy of the build-root environment to use for this config.
1331    env = main.Clone()
1332    env['BUILDDIR'] = variant_path
1333
1334    # variant_dir is the tail component of build path, and is used to
1335    # determine the build parameters (e.g., 'ALPHA_SE')
1336    (build_root, variant_dir) = splitpath(variant_path)
1337
1338    # Set env variables according to the build directory config.
1339    sticky_vars.files = []
1340    # Variables for $BUILD_ROOT/$VARIANT_DIR are stored in
1341    # $BUILD_ROOT/variables/$VARIANT_DIR so you can nuke
1342    # $BUILD_ROOT/$VARIANT_DIR without losing your variables settings.
1343    current_vars_file = joinpath(build_root, 'variables', variant_dir)
1344    if isfile(current_vars_file):
1345        sticky_vars.files.append(current_vars_file)
1346        if not GetOption('silent'):
1347            print "Using saved variables file %s" % current_vars_file
1348    else:
1349        # Build dir-specific variables file doesn't exist.
1350
1351        # Make sure the directory is there so we can create it later
1352        opt_dir = dirname(current_vars_file)
1353        if not isdir(opt_dir):
1354            mkdir(opt_dir)
1355
1356        # Get default build variables from source tree.  Variables are
1357        # normally determined by name of $VARIANT_DIR, but can be
1358        # overridden by '--default=' arg on command line.
1359        default = GetOption('default')
1360        opts_dir = joinpath(main.root.abspath, 'build_opts')
1361        if default:
1362            default_vars_files = [joinpath(build_root, 'variables', default),
1363                                  joinpath(opts_dir, default)]
1364        else:
1365            default_vars_files = [joinpath(opts_dir, variant_dir)]
1366        existing_files = filter(isfile, default_vars_files)
1367        if existing_files:
1368            default_vars_file = existing_files[0]
1369            sticky_vars.files.append(default_vars_file)
1370            print "Variables file %s not found,\n  using defaults in %s" \
1371                  % (current_vars_file, default_vars_file)
1372        else:
1373            print "Error: cannot find variables file %s or " \
1374                  "default file(s) %s" \
1375                  % (current_vars_file, ' or '.join(default_vars_files))
1376            Exit(1)
1377
1378    # Apply current variable settings to env
1379    sticky_vars.Update(env)
1380
1381    help_texts["local_vars"] += \
1382        "Build variables for %s:\n" % variant_dir \
1383                 + sticky_vars.GenerateHelpText(env)
1384
1385    # Process variable settings.
1386
1387    if not have_fenv and env['USE_FENV']:
1388        print "Warning: <fenv.h> not available; " \
1389              "forcing USE_FENV to False in", variant_dir + "."
1390        env['USE_FENV'] = False
1391
1392    if not env['USE_FENV']:
1393        print "Warning: No IEEE FP rounding mode control in", variant_dir + "."
1394        print "         FP results may deviate slightly from other platforms."
1395
1396    if env['EFENCE']:
1397        env.Append(LIBS=['efence'])
1398
1399    if env['USE_KVM']:
1400        if not have_kvm:
1401            print "Warning: Can not enable KVM, host seems to lack KVM support"
1402            env['USE_KVM'] = False
1403        elif not is_isa_kvm_compatible(env['TARGET_ISA']):
1404            print "Info: KVM support disabled due to unsupported host and " \
1405                "target ISA combination"
1406            env['USE_KVM'] = False
1407
1408    # Warn about missing optional functionality
1409    if env['USE_KVM']:
1410        if not main['HAVE_PERF_ATTR_EXCLUDE_HOST']:
1411            print "Warning: perf_event headers lack support for the " \
1412                "exclude_host attribute. KVM instruction counts will " \
1413                "be inaccurate."
1414
1415    # Save sticky variable settings back to current variables file
1416    sticky_vars.Save(current_vars_file, env)
1417
1418    if env['USE_SSE2']:
1419        env.Append(CCFLAGS=['-msse2'])
1420
1421    # The src/SConscript file sets up the build rules in 'env' according
1422    # to the configured variables.  It returns a list of environments,
1423    # one for each variant build (debug, opt, etc.)
1424    SConscript('src/SConscript', variant_dir = variant_path, exports = 'env')
1425
1426def pairwise(iterable):
1427    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
1428    a, b = itertools.tee(iterable)
1429    b.next()
1430    return itertools.izip(a, b)
1431
1432# Create false dependencies so SCons will parse ISAs, establish
1433# dependencies, and setup the build Environments serially. Either
1434# SCons (likely) and/or our SConscripts (possibly) cannot cope with -j
1435# greater than 1. It appears to be standard race condition stuff; it
1436# doesn't always fail, but usually, and the behaviors are different.
1437# Every time I tried to remove this, builds would fail in some
1438# creative new way. So, don't do that. You'll want to, though, because
1439# tests/SConscript takes a long time to make its Environments.
1440for t1, t2 in pairwise(sorted(all_isa_deps.iterkeys())):
1441    main.Depends('#%s-deps'     % t2, '#%s-deps'     % t1)
1442    main.Depends('#%s-environs' % t2, '#%s-environs' % t1)
1443
1444# base help text
1445Help('''
1446Usage: scons [scons options] [build variables] [target(s)]
1447
1448Extra scons options:
1449%(options)s
1450
1451Global build variables:
1452%(global_vars)s
1453
1454%(local_vars)s
1455''' % help_texts)
1456