SConstruct revision 10160:3f4372fa8e6c
12381SN/A# -*- mode:python -*- 28853Sandreas.hansson@arm.com 38711Sandreas.hansson@arm.com# Copyright (c) 2013 ARM Limited 48711Sandreas.hansson@arm.com# All rights reserved. 58711Sandreas.hansson@arm.com# 68711Sandreas.hansson@arm.com# The license below extends only to copyright in the software and shall 78711Sandreas.hansson@arm.com# not be construed as granting a license to any other intellectual 88711Sandreas.hansson@arm.com# property including but not limited to intellectual property relating 98711Sandreas.hansson@arm.com# to a hardware implementation of the functionality of the software 108711Sandreas.hansson@arm.com# licensed hereunder. You may use the software subject to the license 118711Sandreas.hansson@arm.com# terms below provided that you ensure that this notice is replicated 128711Sandreas.hansson@arm.com# unmodified and in its entirety in all distributions of the software, 138711Sandreas.hansson@arm.com# modified or unmodified, in source code or in binary form. 142381SN/A# 152381SN/A# Copyright (c) 2011 Advanced Micro Devices, Inc. 162381SN/A# Copyright (c) 2009 The Hewlett-Packard Development Company 172381SN/A# Copyright (c) 2004-2005 The Regents of The University of Michigan 182381SN/A# All rights reserved. 192381SN/A# 202381SN/A# Redistribution and use in source and binary forms, with or without 212381SN/A# modification, are permitted provided that the following conditions are 222381SN/A# met: redistributions of source code must retain the above copyright 232381SN/A# notice, this list of conditions and the following disclaimer; 242381SN/A# redistributions in binary form must reproduce the above copyright 252381SN/A# notice, this list of conditions and the following disclaimer in the 262381SN/A# documentation and/or other materials provided with the distribution; 272381SN/A# neither the name of the copyright holders nor the names of its 282381SN/A# contributors may be used to endorse or promote products derived from 292381SN/A# this software without specific prior written permission. 302381SN/A# 312381SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 322381SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 332381SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 342381SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 352381SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 362381SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 372381SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 382381SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 392665Ssaidi@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 402665Ssaidi@eecs.umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 418853Sandreas.hansson@arm.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 428922Swilliam.wang@arm.com# 432381SN/A# Authors: Steve Reinhardt 442381SN/A# Nathan Binkert 452381SN/A 462381SN/A################################################### 478922Swilliam.wang@arm.com# 482381SN/A# SCons top-level build description (SConstruct) file. 492381SN/A# 502381SN/A# While in this directory ('gem5'), just type 'scons' to build the default 512381SN/A# configuration (see below), or type 'scons build/<CONFIG>/<binary>' 522381SN/A# to build some other configuration (e.g., 'build/ALPHA/gem5.opt' for 532381SN/A# the optimized full-system version). 542381SN/A# 559235Sandreas.hansson@arm.com# You can build gem5 in a different directory as long as there is a 562381SN/A# 'build/<CONFIG>' somewhere along the target path. The build system 572381SN/A# expects that all configs under the same build directory are being 588922Swilliam.wang@arm.com# built for the same host system. 598922Swilliam.wang@arm.com# 602407SN/A# Examples: 612407SN/A# 622407SN/A# The following two commands are equivalent. The '-u' option tells 632407SN/A# scons to search up the directory tree for this SConstruct file. 642407SN/A# % cd <path-to-src>/gem5 ; scons build/ALPHA/gem5.debug 659235Sandreas.hansson@arm.com# % cd <path-to-src>/gem5/build/ALPHA; scons -u gem5.debug 669235Sandreas.hansson@arm.com# 679235Sandreas.hansson@arm.com# The following two commands are equivalent and demonstrate building 682407SN/A# in a directory outside of the source tree. The '-C' option tells 693401Sktlim@umich.edu# scons to chdir to the specified directory to find this SConstruct 703401Sktlim@umich.edu# file. 712381SN/A# % cd <path-to-src>/gem5 ; scons /local/foo/build/ALPHA/gem5.debug 728922Swilliam.wang@arm.com# % cd /local/foo/build/ALPHA; scons -C <path-to-src>/gem5 gem5.debug 738922Swilliam.wang@arm.com# 749087Sandreas.hansson@arm.com# You can use 'scons -H' to print scons options. If you're in this 752381SN/A# 'gem5' directory (or use -u or -C to tell scons where to find this 768708Sandreas.hansson@arm.com# file), you can use 'scons -h' to print all the gem5-specific build 772381SN/A# options as well. 788922Swilliam.wang@arm.com# 798922Swilliam.wang@arm.com################################################### 808922Swilliam.wang@arm.com 818922Swilliam.wang@arm.com# Check for recent-enough Python and SCons versions. 828922Swilliam.wang@arm.comtry: 838922Swilliam.wang@arm.com # Really old versions of scons only take two options for the 845476Snate@binkert.org # function, so check once without the revision and once with the 852640Sstever@eecs.umich.edu # revision, the first instance will fail for stuff other than 868965Sandreas.hansson@arm.com # 0.98, and the second will fail for 0.98.0 878965Sandreas.hansson@arm.com EnsureSConsVersion(0, 98) 889031Sandreas.hansson@arm.com EnsureSConsVersion(0, 98, 1) 898965Sandreas.hansson@arm.comexcept SystemExit, e: 909031Sandreas.hansson@arm.com print """ 918965Sandreas.hansson@arm.comFor more details, see: 928922Swilliam.wang@arm.com http://gem5.org/Dependencies 938922Swilliam.wang@arm.com""" 948922Swilliam.wang@arm.com raise 958922Swilliam.wang@arm.com 968922Swilliam.wang@arm.com# We ensure the python version early because because python-config 978922Swilliam.wang@arm.com# requires python 2.5 988922Swilliam.wang@arm.comtry: 998922Swilliam.wang@arm.com EnsurePythonVersion(2, 5) 1008965Sandreas.hansson@arm.comexcept SystemExit, e: 1018922Swilliam.wang@arm.com print """ 1029031Sandreas.hansson@arm.comYou can use a non-default installation of the Python interpreter by 1038922Swilliam.wang@arm.comrearranging your PATH so that scons finds the non-default 'python' and 1048922Swilliam.wang@arm.com'python-config' first. 1058922Swilliam.wang@arm.com 1068922Swilliam.wang@arm.comFor more details, see: 1078922Swilliam.wang@arm.com http://gem5.org/wiki/index.php/Using_a_non-default_Python_installation 1083401Sktlim@umich.edu""" 1092381SN/A raise 1102640Sstever@eecs.umich.edu 1112640Sstever@eecs.umich.edu# Global Python includes 1128922Swilliam.wang@arm.comimport os 1134190Ssaidi@eecs.umich.eduimport re 1148965Sandreas.hansson@arm.comimport subprocess 1159031Sandreas.hansson@arm.comimport sys 1168965Sandreas.hansson@arm.com 1178922Swilliam.wang@arm.comfrom os import mkdir, environ 1188922Swilliam.wang@arm.comfrom os.path import abspath, basename, dirname, expanduser, normpath 1198922Swilliam.wang@arm.comfrom os.path import exists, isdir, isfile 1208922Swilliam.wang@arm.comfrom os.path import join as joinpath, split as splitpath 1218922Swilliam.wang@arm.com 1228922Swilliam.wang@arm.com# SCons includes 1238922Swilliam.wang@arm.comimport SCons 1248922Swilliam.wang@arm.comimport SCons.Node 1258922Swilliam.wang@arm.com 1268922Swilliam.wang@arm.comextra_python_paths = [ 1278922Swilliam.wang@arm.com Dir('src/python').srcnode().abspath, # gem5 includes 1288922Swilliam.wang@arm.com Dir('ext/ply').srcnode().abspath, # ply is used by several files 1298922Swilliam.wang@arm.com ] 1308922Swilliam.wang@arm.com 1318975Sandreas.hansson@arm.comsys.path[1:1] = extra_python_paths 1328975Sandreas.hansson@arm.com 1338922Swilliam.wang@arm.comfrom m5.util import compareVersions, readCommand 1348922Swilliam.wang@arm.comfrom m5.util.terminal import get_termcap 1358922Swilliam.wang@arm.com 1368922Swilliam.wang@arm.comhelp_texts = { 1378922Swilliam.wang@arm.com "options" : "", 1388922Swilliam.wang@arm.com "global_vars" : "", 1398965Sandreas.hansson@arm.com "local_vars" : "" 1409031Sandreas.hansson@arm.com} 1418922Swilliam.wang@arm.com 1428922Swilliam.wang@arm.comExport("help_texts") 1439178Sandreas.hansson@arm.com 1449178Sandreas.hansson@arm.com 1459178Sandreas.hansson@arm.com# There's a bug in scons in that (1) by default, the help texts from 1469178Sandreas.hansson@arm.com# AddOption() are supposed to be displayed when you type 'scons -h' 1478922Swilliam.wang@arm.com# and (2) you can override the help displayed by 'scons -h' using the 1489178Sandreas.hansson@arm.com# Help() function, but these two features are incompatible: once 1499178Sandreas.hansson@arm.com# you've overridden the help text using Help(), there's no way to get 1509178Sandreas.hansson@arm.com# at the help texts from AddOptions. See: 1519178Sandreas.hansson@arm.com# http://scons.tigris.org/issues/show_bug.cgi?id=2356 1529178Sandreas.hansson@arm.com# http://scons.tigris.org/issues/show_bug.cgi?id=2611 1539178Sandreas.hansson@arm.com# This hack lets us extract the help text from AddOptions and 1548922Swilliam.wang@arm.com# re-inject it via Help(). Ideally someday this bug will be fixed and 1558922Swilliam.wang@arm.com# we can just use AddOption directly. 1568922Swilliam.wang@arm.comdef AddLocalOption(*args, **kwargs): 1578922Swilliam.wang@arm.com col_width = 30 1588948Sandreas.hansson@arm.com 1598948Sandreas.hansson@arm.com help = " " + ", ".join(args) 1608948Sandreas.hansson@arm.com if "help" in kwargs: 1618948Sandreas.hansson@arm.com length = len(help) 1628948Sandreas.hansson@arm.com if length >= col_width: 1638948Sandreas.hansson@arm.com help += "\n" + " " * col_width 1648948Sandreas.hansson@arm.com else: 1658948Sandreas.hansson@arm.com help += " " * (col_width - length) 1668948Sandreas.hansson@arm.com help += kwargs["help"] 1678948Sandreas.hansson@arm.com help_texts["options"] += help + "\n" 1688948Sandreas.hansson@arm.com 1698948Sandreas.hansson@arm.com AddOption(*args, **kwargs) 1708948Sandreas.hansson@arm.com 1718948Sandreas.hansson@arm.comAddLocalOption('--colors', dest='use_colors', action='store_true', 1728948Sandreas.hansson@arm.com help="Add color to abbreviated scons output") 1738948Sandreas.hansson@arm.comAddLocalOption('--no-colors', dest='use_colors', action='store_false', 1748948Sandreas.hansson@arm.com help="Don't add color to abbreviated scons output") 1758948Sandreas.hansson@arm.comAddLocalOption('--default', dest='default', type='string', action='store', 1768948Sandreas.hansson@arm.com help='Override which build_opts file to use for defaults') 1778948Sandreas.hansson@arm.comAddLocalOption('--ignore-style', dest='ignore_style', action='store_true', 1788975Sandreas.hansson@arm.com help='Disable style checking hooks') 1798975Sandreas.hansson@arm.comAddLocalOption('--no-lto', dest='no_lto', action='store_true', 1808975Sandreas.hansson@arm.com help='Disable Link-Time Optimization for fast') 1818975Sandreas.hansson@arm.comAddLocalOption('--update-ref', dest='update_ref', action='store_true', 1828975Sandreas.hansson@arm.com help='Update test reference outputs') 1838975Sandreas.hansson@arm.comAddLocalOption('--verbose', dest='verbose', action='store_true', 1848975Sandreas.hansson@arm.com help='Print full tool command lines') 1858975Sandreas.hansson@arm.com 1868975Sandreas.hansson@arm.comtermcap = get_termcap(GetOption('use_colors')) 1878975Sandreas.hansson@arm.com 1888975Sandreas.hansson@arm.com######################################################################## 1898948Sandreas.hansson@arm.com# 1908948Sandreas.hansson@arm.com# Set up the main build environment. 1918975Sandreas.hansson@arm.com# 1928975Sandreas.hansson@arm.com######################################################################## 1938975Sandreas.hansson@arm.com 1948975Sandreas.hansson@arm.com# export TERM so that clang reports errors in color 1958975Sandreas.hansson@arm.comuse_vars = set([ 'AS', 'AR', 'CC', 'CXX', 'HOME', 'LD_LIBRARY_PATH', 1968975Sandreas.hansson@arm.com 'LIBRARY_PATH', 'PATH', 'PKG_CONFIG_PATH', 'PROTOC', 1978975Sandreas.hansson@arm.com 'PYTHONPATH', 'RANLIB', 'SWIG', 'TERM' ]) 1988948Sandreas.hansson@arm.com 1998975Sandreas.hansson@arm.comuse_prefixes = [ 2008922Swilliam.wang@arm.com "M5", # M5 configuration (e.g., path to kernels) 2018922Swilliam.wang@arm.com "DISTCC_", # distcc (distributed compiler wrapper) configuration 2029087Sandreas.hansson@arm.com "CCACHE_", # ccache (caching compiler wrapper) configuration 2039087Sandreas.hansson@arm.com "CCC_", # clang static analyzer configuration 2049087Sandreas.hansson@arm.com ] 2059087Sandreas.hansson@arm.com 2069087Sandreas.hansson@arm.comuse_env = {} 2079087Sandreas.hansson@arm.comfor key,val in os.environ.iteritems(): 2088922Swilliam.wang@arm.com if key in use_vars or \ 2098711Sandreas.hansson@arm.com any([key.startswith(prefix) for prefix in use_prefixes]): 2108922Swilliam.wang@arm.com use_env[key] = val 2118922Swilliam.wang@arm.com 2128922Swilliam.wang@arm.commain = Environment(ENV=use_env) 2138711Sandreas.hansson@arm.commain.Decider('MD5-timestamp') 2148711Sandreas.hansson@arm.commain.root = Dir(".") # The current directory (where this file lives). 2158711Sandreas.hansson@arm.commain.srcdir = Dir("src") # The source directory 2168922Swilliam.wang@arm.com 2172381SN/Amain_dict_keys = main.Dictionary().keys() 2188711Sandreas.hansson@arm.com 2198922Swilliam.wang@arm.com# Check that we have a C/C++ compiler 2208922Swilliam.wang@arm.comif not ('CC' in main_dict_keys and 'CXX' in main_dict_keys): 2218711Sandreas.hansson@arm.com print "No C++ compiler installed (package g++ on Ubuntu and RedHat)" 2228922Swilliam.wang@arm.com Exit(1) 2232381SN/A 2242381SN/A# Check that swig is present 2252381SN/Aif not 'SWIG' in main_dict_keys: 2262381SN/A print "swig is not installed (package swig on Ubuntu and RedHat)" 2278922Swilliam.wang@arm.com Exit(1) 2282381SN/A 2299089Sandreas.hansson@arm.com# add useful python code PYTHONPATH so it can be used by subprocesses 2309089Sandreas.hansson@arm.com# as well 2319089Sandreas.hansson@arm.commain.AppendENVPath('PYTHONPATH', extra_python_paths) 2329089Sandreas.hansson@arm.com 2339089Sandreas.hansson@arm.com######################################################################## 2345314Sstever@gmail.com# 2355314Sstever@gmail.com# Mercurial Stuff. 2365314Sstever@gmail.com# 2375314Sstever@gmail.com# If the gem5 directory is a mercurial repository, we should do some 2388975Sandreas.hansson@arm.com# extra things. 2398975Sandreas.hansson@arm.com# 2408975Sandreas.hansson@arm.com######################################################################## 2418975Sandreas.hansson@arm.com 2428975Sandreas.hansson@arm.comhgdir = main.root.Dir(".hg") 2438975Sandreas.hansson@arm.com 2448975Sandreas.hansson@arm.commercurial_style_message = """ 2458975Sandreas.hansson@arm.comYou're missing the gem5 style hook, which automatically checks your code 2468975Sandreas.hansson@arm.comagainst the gem5 style rules on hg commit and qrefresh commands. This 2478975Sandreas.hansson@arm.comscript will now install the hook in your .hg/hgrc file. 2488975Sandreas.hansson@arm.comPress enter to continue, or ctrl-c to abort: """ 2498975Sandreas.hansson@arm.com 2508975Sandreas.hansson@arm.commercurial_style_hook = """ 2518975Sandreas.hansson@arm.com# The following lines were automatically added by gem5/SConstruct 2528975Sandreas.hansson@arm.com# to provide the gem5 style-checking hooks 2538975Sandreas.hansson@arm.com[extensions] 2548975Sandreas.hansson@arm.comstyle = %s/util/style.py 2558975Sandreas.hansson@arm.com 2568975Sandreas.hansson@arm.com[hooks] 2578975Sandreas.hansson@arm.compretxncommit.style = python:style.check_style 2588975Sandreas.hansson@arm.compre-qrefresh.style = python:style.check_style 2598975Sandreas.hansson@arm.com# End of SConstruct additions 2608975Sandreas.hansson@arm.com 2618975Sandreas.hansson@arm.com""" % (main.root.abspath) 2628975Sandreas.hansson@arm.com 2638975Sandreas.hansson@arm.commercurial_lib_not_found = """ 2648975Sandreas.hansson@arm.comMercurial libraries cannot be found, ignoring style hook. If 2658975Sandreas.hansson@arm.comyou are a gem5 developer, please fix this and run the style 2668975Sandreas.hansson@arm.comhook. It is important. 2678975Sandreas.hansson@arm.com""" 2688975Sandreas.hansson@arm.com 2698975Sandreas.hansson@arm.com# Check for style hook and prompt for installation if it's not there. 2708975Sandreas.hansson@arm.com# Skip this if --ignore-style was specified, there's no .hg dir to 2718975Sandreas.hansson@arm.com# install a hook in, or there's no interactive terminal to prompt. 2729087Sandreas.hansson@arm.comif not GetOption('ignore_style') and hgdir.exists() and sys.stdin.isatty(): 2739087Sandreas.hansson@arm.com style_hook = True 2749087Sandreas.hansson@arm.com try: 2759087Sandreas.hansson@arm.com from mercurial import ui 2769087Sandreas.hansson@arm.com ui = ui.ui() 2779087Sandreas.hansson@arm.com ui.readconfig(hgdir.File('hgrc').abspath) 2789087Sandreas.hansson@arm.com style_hook = ui.config('hooks', 'pretxncommit.style', None) and \ 2799087Sandreas.hansson@arm.com ui.config('hooks', 'pre-qrefresh.style', None) 2808975Sandreas.hansson@arm.com except ImportError: 2818975Sandreas.hansson@arm.com print mercurial_lib_not_found 2828975Sandreas.hansson@arm.com 2838975Sandreas.hansson@arm.com if not style_hook: 2848975Sandreas.hansson@arm.com print mercurial_style_message, 2858975Sandreas.hansson@arm.com # continue unless user does ctrl-c/ctrl-d etc. 2868975Sandreas.hansson@arm.com try: 2872381SN/A raw_input() 2882381SN/A except: 2898922Swilliam.wang@arm.com print "Input exception, exiting scons.\n" 2908922Swilliam.wang@arm.com sys.exit(1) 2918922Swilliam.wang@arm.com hgrc_path = '%s/.hg/hgrc' % main.root.abspath 2928922Swilliam.wang@arm.com print "Adding style hook to", hgrc_path, "\n" 2938922Swilliam.wang@arm.com try: 2948922Swilliam.wang@arm.com hgrc = open(hgrc_path, 'a') 2958922Swilliam.wang@arm.com hgrc.write(mercurial_style_hook) 2968922Swilliam.wang@arm.com hgrc.close() 2978922Swilliam.wang@arm.com except: 2988975Sandreas.hansson@arm.com print "Error updating", hgrc_path 2998975Sandreas.hansson@arm.com sys.exit(1) 3008922Swilliam.wang@arm.com 3018922Swilliam.wang@arm.com 3028922Swilliam.wang@arm.com################################################### 3038922Swilliam.wang@arm.com# 3048922Swilliam.wang@arm.com# Figure out which configurations to set up based on the path(s) of 3058922Swilliam.wang@arm.com# the target(s). 3068965Sandreas.hansson@arm.com# 3079031Sandreas.hansson@arm.com################################################### 3088922Swilliam.wang@arm.com 3098922Swilliam.wang@arm.com# Find default configuration & binary. 3108922Swilliam.wang@arm.comDefault(environ.get('M5_DEFAULT_BINARY', 'build/ALPHA/gem5.debug')) 3118922Swilliam.wang@arm.com 3128922Swilliam.wang@arm.com# helper function: find last occurrence of element in list 3138922Swilliam.wang@arm.comdef rfind(l, elt, offs = -1): 3148948Sandreas.hansson@arm.com for i in range(len(l)+offs, 0, -1): 3158948Sandreas.hansson@arm.com if l[i] == elt: 3168948Sandreas.hansson@arm.com return i 3178948Sandreas.hansson@arm.com raise ValueError, "element not found" 3188948Sandreas.hansson@arm.com 3198948Sandreas.hansson@arm.com# Take a list of paths (or SCons Nodes) and return a list with all 3208948Sandreas.hansson@arm.com# paths made absolute and ~-expanded. Paths will be interpreted 3218948Sandreas.hansson@arm.com# relative to the launch directory unless a different root is provided 3228948Sandreas.hansson@arm.comdef makePathListAbsolute(path_list, root=GetLaunchDir()): 3238948Sandreas.hansson@arm.com return [abspath(joinpath(root, expanduser(str(p)))) 3248948Sandreas.hansson@arm.com for p in path_list] 3258948Sandreas.hansson@arm.com 3268948Sandreas.hansson@arm.com# Each target must have 'build' in the interior of the path; the 3278948Sandreas.hansson@arm.com# directory below this will determine the build parameters. For 3288948Sandreas.hansson@arm.com# example, for target 'foo/bar/build/ALPHA_SE/arch/alpha/blah.do' we 3298948Sandreas.hansson@arm.com# recognize that ALPHA_SE specifies the configuration because it 3308948Sandreas.hansson@arm.com# follow 'build' in the build path. 3318948Sandreas.hansson@arm.com 3328948Sandreas.hansson@arm.com# The funky assignment to "[:]" is needed to replace the list contents 3338948Sandreas.hansson@arm.com# in place rather than reassign the symbol to a new list, which 3348975Sandreas.hansson@arm.com# doesn't work (obviously!). 3358975Sandreas.hansson@arm.comBUILD_TARGETS[:] = makePathListAbsolute(BUILD_TARGETS) 3368975Sandreas.hansson@arm.com 3378975Sandreas.hansson@arm.com# Generate a list of the unique build roots and configs that the 3388975Sandreas.hansson@arm.com# collected targets reference. 3398975Sandreas.hansson@arm.comvariant_paths = [] 3408975Sandreas.hansson@arm.combuild_root = None 3418975Sandreas.hansson@arm.comfor t in BUILD_TARGETS: 3428975Sandreas.hansson@arm.com path_dirs = t.split('/') 3438975Sandreas.hansson@arm.com try: 3448975Sandreas.hansson@arm.com build_top = rfind(path_dirs, 'build', -2) 3458948Sandreas.hansson@arm.com except: 3468948Sandreas.hansson@arm.com print "Error: no non-leaf 'build' dir found on target path", t 3478975Sandreas.hansson@arm.com Exit(1) 3488975Sandreas.hansson@arm.com this_build_root = joinpath('/',*path_dirs[:build_top+1]) 3498975Sandreas.hansson@arm.com if not build_root: 3508975Sandreas.hansson@arm.com build_root = this_build_root 3518975Sandreas.hansson@arm.com else: 3528948Sandreas.hansson@arm.com if this_build_root != build_root: 3538975Sandreas.hansson@arm.com print "Error: build targets not under same build root\n"\ 3548948Sandreas.hansson@arm.com " %s\n %s" % (build_root, this_build_root) 3558948Sandreas.hansson@arm.com Exit(1) 3569087Sandreas.hansson@arm.com variant_path = joinpath('/',*path_dirs[:build_top+2]) 3579087Sandreas.hansson@arm.com if variant_path not in variant_paths: 3589087Sandreas.hansson@arm.com variant_paths.append(variant_path) 3599087Sandreas.hansson@arm.com 3609087Sandreas.hansson@arm.com# Make sure build_root exists (might not if this is the first build there) 3619087Sandreas.hansson@arm.comif not isdir(build_root): 3629087Sandreas.hansson@arm.com mkdir(build_root) 3638922Swilliam.wang@arm.commain['BUILDROOT'] = build_root 3648922Swilliam.wang@arm.com 3658922Swilliam.wang@arm.comExport('main') 3668922Swilliam.wang@arm.com 3678922Swilliam.wang@arm.commain.SConsignFile(joinpath(build_root, "sconsign")) 3688922Swilliam.wang@arm.com 3698922Swilliam.wang@arm.com# Default duplicate option is to use hard links, but this messes up 3708922Swilliam.wang@arm.com# when you use emacs to edit a file in the target dir, as emacs moves 3718922Swilliam.wang@arm.com# file to file~ then copies to file, breaking the link. Symbolic 3728922Swilliam.wang@arm.com# (soft) links work better. 3738922Swilliam.wang@arm.commain.SetOption('duplicate', 'soft-copy') 3749088Sandreas.hansson@arm.com 3759088Sandreas.hansson@arm.com# 3769088Sandreas.hansson@arm.com# Set up global sticky variables... these are common to an entire build 3779088Sandreas.hansson@arm.com# tree (not specific to a particular build like ALPHA_SE) 3789088Sandreas.hansson@arm.com# 3799088Sandreas.hansson@arm.com 3809088Sandreas.hansson@arm.comglobal_vars_file = joinpath(build_root, 'variables.global') 3818922Swilliam.wang@arm.com 3828922Swilliam.wang@arm.comglobal_vars = Variables(global_vars_file, args=ARGUMENTS) 3838922Swilliam.wang@arm.com 3848922Swilliam.wang@arm.comglobal_vars.AddVariables( 3858922Swilliam.wang@arm.com ('CC', 'C compiler', environ.get('CC', main['CC'])), 3868922Swilliam.wang@arm.com ('CXX', 'C++ compiler', environ.get('CXX', main['CXX'])), 3878922Swilliam.wang@arm.com ('SWIG', 'SWIG tool', environ.get('SWIG', main['SWIG'])), 3888922Swilliam.wang@arm.com ('PROTOC', 'protoc tool', environ.get('PROTOC', 'protoc')), 3898922Swilliam.wang@arm.com ('BATCH', 'Use batch pool for build and tests', False), 3908922Swilliam.wang@arm.com ('BATCH_CMD', 'Batch pool submission command name', 'qdo'), 3918922Swilliam.wang@arm.com ('M5_BUILD_CACHE', 'Cache built objects in this directory', False), 3929090Sandreas.hansson@arm.com ('EXTRAS', 'Add extra directories to the compilation', '') 3938975Sandreas.hansson@arm.com ) 3948975Sandreas.hansson@arm.com 3958975Sandreas.hansson@arm.com# Update main environment with values from ARGUMENTS & global_vars_file 3968975Sandreas.hansson@arm.comglobal_vars.Update(main) 3979178Sandreas.hansson@arm.comhelp_texts["global_vars"] += global_vars.GenerateHelpText(main) 3989178Sandreas.hansson@arm.com 3999178Sandreas.hansson@arm.com# Save sticky variable settings back to current variables file 4009178Sandreas.hansson@arm.comglobal_vars.Save(global_vars_file, main) 4019178Sandreas.hansson@arm.com 4029178Sandreas.hansson@arm.com# Parse EXTRAS variable to build list of all directories where we're 4039178Sandreas.hansson@arm.com# look for sources etc. This list is exported as extras_dir_list. 4049178Sandreas.hansson@arm.combase_dir = main.srcdir.abspath 4059178Sandreas.hansson@arm.comif main['EXTRAS']: 4069178Sandreas.hansson@arm.com extras_dir_list = makePathListAbsolute(main['EXTRAS'].split(':')) 4079178Sandreas.hansson@arm.comelse: 4089178Sandreas.hansson@arm.com extras_dir_list = [] 4098975Sandreas.hansson@arm.com 4108975Sandreas.hansson@arm.comExport('base_dir') 4118975Sandreas.hansson@arm.comExport('extras_dir_list') 4128975Sandreas.hansson@arm.com 4138975Sandreas.hansson@arm.com# the ext directory should be on the #includes path 4148975Sandreas.hansson@arm.commain.Append(CPPPATH=[Dir('ext')]) 4158975Sandreas.hansson@arm.com 4168975Sandreas.hansson@arm.comdef strip_build_path(path, env): 4178975Sandreas.hansson@arm.com path = str(path) 4188975Sandreas.hansson@arm.com variant_base = env['BUILDROOT'] + os.path.sep 4198975Sandreas.hansson@arm.com if path.startswith(variant_base): 4208975Sandreas.hansson@arm.com path = path[len(variant_base):] 4218975Sandreas.hansson@arm.com elif path.startswith('build/'): 4228975Sandreas.hansson@arm.com path = path[6:] 4238975Sandreas.hansson@arm.com return path 4248975Sandreas.hansson@arm.com 4258975Sandreas.hansson@arm.com# Generate a string of the form: 4268975Sandreas.hansson@arm.com# common/path/prefix/src1, src2 -> tgt1, tgt2 4278975Sandreas.hansson@arm.com# to print while building. 4288975Sandreas.hansson@arm.comclass Transform(object): 4298975Sandreas.hansson@arm.com # all specific color settings should be here and nowhere else 4308975Sandreas.hansson@arm.com tool_color = termcap.Normal 4319087Sandreas.hansson@arm.com pfx_color = termcap.Yellow 4329087Sandreas.hansson@arm.com srcs_color = termcap.Yellow + termcap.Bold 4339087Sandreas.hansson@arm.com arrow_color = termcap.Blue + termcap.Bold 4349087Sandreas.hansson@arm.com tgts_color = termcap.Yellow + termcap.Bold 4359087Sandreas.hansson@arm.com 4369087Sandreas.hansson@arm.com def __init__(self, tool, max_sources=99): 4379087Sandreas.hansson@arm.com self.format = self.tool_color + (" [%8s] " % tool) \ 4388922Swilliam.wang@arm.com + self.pfx_color + "%s" \ 4398922Swilliam.wang@arm.com + self.srcs_color + "%s" \ 4402381SN/A + self.arrow_color + " -> " \ 441 + self.tgts_color + "%s" \ 442 + termcap.Normal 443 self.max_sources = max_sources 444 445 def __call__(self, target, source, env, for_signature=None): 446 # truncate source list according to max_sources param 447 source = source[0:self.max_sources] 448 def strip(f): 449 return strip_build_path(str(f), env) 450 if len(source) > 0: 451 srcs = map(strip, source) 452 else: 453 srcs = [''] 454 tgts = map(strip, target) 455 # surprisingly, os.path.commonprefix is a dumb char-by-char string 456 # operation that has nothing to do with paths. 457 com_pfx = os.path.commonprefix(srcs + tgts) 458 com_pfx_len = len(com_pfx) 459 if com_pfx: 460 # do some cleanup and sanity checking on common prefix 461 if com_pfx[-1] == ".": 462 # prefix matches all but file extension: ok 463 # back up one to change 'foo.cc -> o' to 'foo.cc -> .o' 464 com_pfx = com_pfx[0:-1] 465 elif com_pfx[-1] == "/": 466 # common prefix is directory path: OK 467 pass 468 else: 469 src0_len = len(srcs[0]) 470 tgt0_len = len(tgts[0]) 471 if src0_len == com_pfx_len: 472 # source is a substring of target, OK 473 pass 474 elif tgt0_len == com_pfx_len: 475 # target is a substring of source, need to back up to 476 # avoid empty string on RHS of arrow 477 sep_idx = com_pfx.rfind(".") 478 if sep_idx != -1: 479 com_pfx = com_pfx[0:sep_idx] 480 else: 481 com_pfx = '' 482 elif src0_len > com_pfx_len and srcs[0][com_pfx_len] == ".": 483 # still splitting at file extension: ok 484 pass 485 else: 486 # probably a fluke; ignore it 487 com_pfx = '' 488 # recalculate length in case com_pfx was modified 489 com_pfx_len = len(com_pfx) 490 def fmt(files): 491 f = map(lambda s: s[com_pfx_len:], files) 492 return ', '.join(f) 493 return self.format % (com_pfx, fmt(srcs), fmt(tgts)) 494 495Export('Transform') 496 497# enable the regression script to use the termcap 498main['TERMCAP'] = termcap 499 500if GetOption('verbose'): 501 def MakeAction(action, string, *args, **kwargs): 502 return Action(action, *args, **kwargs) 503else: 504 MakeAction = Action 505 main['CCCOMSTR'] = Transform("CC") 506 main['CXXCOMSTR'] = Transform("CXX") 507 main['ASCOMSTR'] = Transform("AS") 508 main['SWIGCOMSTR'] = Transform("SWIG") 509 main['ARCOMSTR'] = Transform("AR", 0) 510 main['LINKCOMSTR'] = Transform("LINK", 0) 511 main['RANLIBCOMSTR'] = Transform("RANLIB", 0) 512 main['M4COMSTR'] = Transform("M4") 513 main['SHCCCOMSTR'] = Transform("SHCC") 514 main['SHCXXCOMSTR'] = Transform("SHCXX") 515Export('MakeAction') 516 517# Initialize the Link-Time Optimization (LTO) flags 518main['LTO_CCFLAGS'] = [] 519main['LTO_LDFLAGS'] = [] 520 521# According to the readme, tcmalloc works best if the compiler doesn't 522# assume that we're using the builtin malloc and friends. These flags 523# are compiler-specific, so we need to set them after we detect which 524# compiler we're using. 525main['TCMALLOC_CCFLAGS'] = [] 526 527CXX_version = readCommand([main['CXX'],'--version'], exception=False) 528CXX_V = readCommand([main['CXX'],'-V'], exception=False) 529 530main['GCC'] = CXX_version and CXX_version.find('g++') >= 0 531main['CLANG'] = CXX_version and CXX_version.find('clang') >= 0 532if main['GCC'] + main['CLANG'] > 1: 533 print 'Error: How can we have two at the same time?' 534 Exit(1) 535 536# Set up default C++ compiler flags 537if main['GCC'] or main['CLANG']: 538 # As gcc and clang share many flags, do the common parts here 539 main.Append(CCFLAGS=['-pipe']) 540 main.Append(CCFLAGS=['-fno-strict-aliasing']) 541 # Enable -Wall and then disable the few warnings that we 542 # consistently violate 543 main.Append(CCFLAGS=['-Wall', '-Wno-sign-compare', '-Wundef']) 544 # We always compile using C++11, but only gcc >= 4.7 and clang 3.1 545 # actually use that name, so we stick with c++0x 546 main.Append(CXXFLAGS=['-std=c++0x']) 547 # Add selected sanity checks from -Wextra 548 main.Append(CXXFLAGS=['-Wmissing-field-initializers', 549 '-Woverloaded-virtual']) 550else: 551 print termcap.Yellow + termcap.Bold + 'Error' + termcap.Normal, 552 print "Don't know what compiler options to use for your compiler." 553 print termcap.Yellow + ' compiler:' + termcap.Normal, main['CXX'] 554 print termcap.Yellow + ' version:' + termcap.Normal, 555 if not CXX_version: 556 print termcap.Yellow + termcap.Bold + "COMMAND NOT FOUND!" +\ 557 termcap.Normal 558 else: 559 print CXX_version.replace('\n', '<nl>') 560 print " If you're trying to use a compiler other than GCC" 561 print " or clang, there appears to be something wrong with your" 562 print " environment." 563 print " " 564 print " If you are trying to use a compiler other than those listed" 565 print " above you will need to ease fix SConstruct and " 566 print " src/SConscript to support that compiler." 567 Exit(1) 568 569if main['GCC']: 570 # Check for a supported version of gcc, >= 4.4 is needed for c++0x 571 # support. See http://gcc.gnu.org/projects/cxx0x.html for details 572 gcc_version = readCommand([main['CXX'], '-dumpversion'], exception=False) 573 if compareVersions(gcc_version, "4.4") < 0: 574 print 'Error: gcc version 4.4 or newer required.' 575 print ' Installed version:', gcc_version 576 Exit(1) 577 578 main['GCC_VERSION'] = gcc_version 579 580 # Check for versions with bugs 581 if not compareVersions(gcc_version, '4.4.1') or \ 582 not compareVersions(gcc_version, '4.4.2'): 583 print 'Info: Tree vectorizer in GCC 4.4.1 & 4.4.2 is buggy, disabling.' 584 main.Append(CCFLAGS=['-fno-tree-vectorize']) 585 586 # LTO support is only really working properly from 4.6 and beyond 587 if compareVersions(gcc_version, '4.6') >= 0: 588 # Add the appropriate Link-Time Optimization (LTO) flags 589 # unless LTO is explicitly turned off. Note that these flags 590 # are only used by the fast target. 591 if not GetOption('no_lto'): 592 # Pass the LTO flag when compiling to produce GIMPLE 593 # output, we merely create the flags here and only append 594 # them later/ 595 main['LTO_CCFLAGS'] = ['-flto=%d' % GetOption('num_jobs')] 596 597 # Use the same amount of jobs for LTO as we are running 598 # scons with, we hardcode the use of the linker plugin 599 # which requires either gold or GNU ld >= 2.21 600 main['LTO_LDFLAGS'] = ['-flto=%d' % GetOption('num_jobs'), 601 '-fuse-linker-plugin'] 602 603 main.Append(TCMALLOC_CCFLAGS=['-fno-builtin-malloc', '-fno-builtin-calloc', 604 '-fno-builtin-realloc', '-fno-builtin-free']) 605 606elif main['CLANG']: 607 # Check for a supported version of clang, >= 2.9 is needed to 608 # support similar features as gcc 4.4. See 609 # http://clang.llvm.org/cxx_status.html for details 610 clang_version_re = re.compile(".* version (\d+\.\d+)") 611 clang_version_match = clang_version_re.search(CXX_version) 612 if (clang_version_match): 613 clang_version = clang_version_match.groups()[0] 614 if compareVersions(clang_version, "2.9") < 0: 615 print 'Error: clang version 2.9 or newer required.' 616 print ' Installed version:', clang_version 617 Exit(1) 618 else: 619 print 'Error: Unable to determine clang version.' 620 Exit(1) 621 622 # clang has a few additional warnings that we disable, 623 # tautological comparisons are allowed due to unsigned integers 624 # being compared to constants that happen to be 0, and extraneous 625 # parantheses are allowed due to Ruby's printing of the AST, 626 # finally self assignments are allowed as the generated CPU code 627 # is relying on this 628 main.Append(CCFLAGS=['-Wno-tautological-compare', 629 '-Wno-parentheses', 630 '-Wno-self-assign']) 631 632 main.Append(TCMALLOC_CCFLAGS=['-fno-builtin']) 633 634 # On Mac OS X/Darwin we need to also use libc++ (part of XCode) as 635 # opposed to libstdc++, as the later is dated. 636 if sys.platform == "darwin": 637 main.Append(CXXFLAGS=['-stdlib=libc++']) 638 main.Append(LIBS=['c++']) 639 640else: 641 print termcap.Yellow + termcap.Bold + 'Error' + termcap.Normal, 642 print "Don't know what compiler options to use for your compiler." 643 print termcap.Yellow + ' compiler:' + termcap.Normal, main['CXX'] 644 print termcap.Yellow + ' version:' + termcap.Normal, 645 if not CXX_version: 646 print termcap.Yellow + termcap.Bold + "COMMAND NOT FOUND!" +\ 647 termcap.Normal 648 else: 649 print CXX_version.replace('\n', '<nl>') 650 print " If you're trying to use a compiler other than GCC" 651 print " or clang, there appears to be something wrong with your" 652 print " environment." 653 print " " 654 print " If you are trying to use a compiler other than those listed" 655 print " above you will need to ease fix SConstruct and " 656 print " src/SConscript to support that compiler." 657 Exit(1) 658 659# Set up common yacc/bison flags (needed for Ruby) 660main['YACCFLAGS'] = '-d' 661main['YACCHXXFILESUFFIX'] = '.hh' 662 663# Do this after we save setting back, or else we'll tack on an 664# extra 'qdo' every time we run scons. 665if main['BATCH']: 666 main['CC'] = main['BATCH_CMD'] + ' ' + main['CC'] 667 main['CXX'] = main['BATCH_CMD'] + ' ' + main['CXX'] 668 main['AS'] = main['BATCH_CMD'] + ' ' + main['AS'] 669 main['AR'] = main['BATCH_CMD'] + ' ' + main['AR'] 670 main['RANLIB'] = main['BATCH_CMD'] + ' ' + main['RANLIB'] 671 672if sys.platform == 'cygwin': 673 # cygwin has some header file issues... 674 main.Append(CCFLAGS=["-Wno-uninitialized"]) 675 676# Check for the protobuf compiler 677protoc_version = readCommand([main['PROTOC'], '--version'], 678 exception='').split() 679 680# First two words should be "libprotoc x.y.z" 681if len(protoc_version) < 2 or protoc_version[0] != 'libprotoc': 682 print termcap.Yellow + termcap.Bold + \ 683 'Warning: Protocol buffer compiler (protoc) not found.\n' + \ 684 ' Please install protobuf-compiler for tracing support.' + \ 685 termcap.Normal 686 main['PROTOC'] = False 687else: 688 # Based on the availability of the compress stream wrappers, 689 # require 2.1.0 690 min_protoc_version = '2.1.0' 691 if compareVersions(protoc_version[1], min_protoc_version) < 0: 692 print termcap.Yellow + termcap.Bold + \ 693 'Warning: protoc version', min_protoc_version, \ 694 'or newer required.\n' + \ 695 ' Installed version:', protoc_version[1], \ 696 termcap.Normal 697 main['PROTOC'] = False 698 else: 699 # Attempt to determine the appropriate include path and 700 # library path using pkg-config, that means we also need to 701 # check for pkg-config. Note that it is possible to use 702 # protobuf without the involvement of pkg-config. Later on we 703 # check go a library config check and at that point the test 704 # will fail if libprotobuf cannot be found. 705 if readCommand(['pkg-config', '--version'], exception=''): 706 try: 707 # Attempt to establish what linking flags to add for protobuf 708 # using pkg-config 709 main.ParseConfig('pkg-config --cflags --libs-only-L protobuf') 710 except: 711 print termcap.Yellow + termcap.Bold + \ 712 'Warning: pkg-config could not get protobuf flags.' + \ 713 termcap.Normal 714 715# Check for SWIG 716if not main.has_key('SWIG'): 717 print 'Error: SWIG utility not found.' 718 print ' Please install (see http://www.swig.org) and retry.' 719 Exit(1) 720 721# Check for appropriate SWIG version 722swig_version = readCommand([main['SWIG'], '-version'], exception='').split() 723# First 3 words should be "SWIG Version x.y.z" 724if len(swig_version) < 3 or \ 725 swig_version[0] != 'SWIG' or swig_version[1] != 'Version': 726 print 'Error determining SWIG version.' 727 Exit(1) 728 729min_swig_version = '1.3.34' 730if compareVersions(swig_version[2], min_swig_version) < 0: 731 print 'Error: SWIG version', min_swig_version, 'or newer required.' 732 print ' Installed version:', swig_version[2] 733 Exit(1) 734 735# Older versions of swig do not play well with more recent versions of 736# gcc due to assumptions on implicit includes (cstddef) and use of 737# namespaces 738if main['GCC'] and compareVersions(gcc_version, '4.6') > 0 and \ 739 compareVersions(swig_version[2], '2') < 0: 740 print '\n' + termcap.Yellow + termcap.Bold + \ 741 'Warning: SWIG 1.x cause issues with gcc 4.6 and later.\n' + \ 742 termcap.Normal + \ 743 'Use SWIG 2.x to avoid assumptions on implicit includes\n' + \ 744 'and use of namespaces\n' 745 746# Set up SWIG flags & scanner 747swig_flags=Split('-c++ -python -modern -templatereduce $_CPPINCFLAGS') 748main.Append(SWIGFLAGS=swig_flags) 749 750# filter out all existing swig scanners, they mess up the dependency 751# stuff for some reason 752scanners = [] 753for scanner in main['SCANNERS']: 754 skeys = scanner.skeys 755 if skeys == '.i': 756 continue 757 758 if isinstance(skeys, (list, tuple)) and '.i' in skeys: 759 continue 760 761 scanners.append(scanner) 762 763# add the new swig scanner that we like better 764from SCons.Scanner import ClassicCPP as CPPScanner 765swig_inc_re = '^[ \t]*[%,#][ \t]*(?:include|import)[ \t]*(<|")([^>"]+)(>|")' 766scanners.append(CPPScanner("SwigScan", [ ".i" ], "CPPPATH", swig_inc_re)) 767 768# replace the scanners list that has what we want 769main['SCANNERS'] = scanners 770 771# Add a custom Check function to the Configure context so that we can 772# figure out if the compiler adds leading underscores to global 773# variables. This is needed for the autogenerated asm files that we 774# use for embedding the python code. 775def CheckLeading(context): 776 context.Message("Checking for leading underscore in global variables...") 777 # 1) Define a global variable called x from asm so the C compiler 778 # won't change the symbol at all. 779 # 2) Declare that variable. 780 # 3) Use the variable 781 # 782 # If the compiler prepends an underscore, this will successfully 783 # link because the external symbol 'x' will be called '_x' which 784 # was defined by the asm statement. If the compiler does not 785 # prepend an underscore, this will not successfully link because 786 # '_x' will have been defined by assembly, while the C portion of 787 # the code will be trying to use 'x' 788 ret = context.TryLink(''' 789 asm(".globl _x; _x: .byte 0"); 790 extern int x; 791 int main() { return x; } 792 ''', extension=".c") 793 context.env.Append(LEADING_UNDERSCORE=ret) 794 context.Result(ret) 795 return ret 796 797# Add a custom Check function to test for structure members. 798def CheckMember(context, include, decl, member, include_quotes="<>"): 799 context.Message("Checking for member %s in %s..." % 800 (member, decl)) 801 text = """ 802#include %(header)s 803int main(){ 804 %(decl)s test; 805 (void)test.%(member)s; 806 return 0; 807}; 808""" % { "header" : include_quotes[0] + include + include_quotes[1], 809 "decl" : decl, 810 "member" : member, 811 } 812 813 ret = context.TryCompile(text, extension=".cc") 814 context.Result(ret) 815 return ret 816 817# Platform-specific configuration. Note again that we assume that all 818# builds under a given build root run on the same host platform. 819conf = Configure(main, 820 conf_dir = joinpath(build_root, '.scons_config'), 821 log_file = joinpath(build_root, 'scons_config.log'), 822 custom_tests = { 823 'CheckLeading' : CheckLeading, 824 'CheckMember' : CheckMember, 825 }) 826 827# Check for leading underscores. Don't really need to worry either 828# way so don't need to check the return code. 829conf.CheckLeading() 830 831# Check if we should compile a 64 bit binary on Mac OS X/Darwin 832try: 833 import platform 834 uname = platform.uname() 835 if uname[0] == 'Darwin' and compareVersions(uname[2], '9.0.0') >= 0: 836 if int(readCommand('sysctl -n hw.cpu64bit_capable')[0]): 837 main.Append(CCFLAGS=['-arch', 'x86_64']) 838 main.Append(CFLAGS=['-arch', 'x86_64']) 839 main.Append(LINKFLAGS=['-arch', 'x86_64']) 840 main.Append(ASFLAGS=['-arch', 'x86_64']) 841except: 842 pass 843 844# Recent versions of scons substitute a "Null" object for Configure() 845# when configuration isn't necessary, e.g., if the "--help" option is 846# present. Unfortuantely this Null object always returns false, 847# breaking all our configuration checks. We replace it with our own 848# more optimistic null object that returns True instead. 849if not conf: 850 def NullCheck(*args, **kwargs): 851 return True 852 853 class NullConf: 854 def __init__(self, env): 855 self.env = env 856 def Finish(self): 857 return self.env 858 def __getattr__(self, mname): 859 return NullCheck 860 861 conf = NullConf(main) 862 863# Cache build files in the supplied directory. 864if main['M5_BUILD_CACHE']: 865 print 'Using build cache located at', main['M5_BUILD_CACHE'] 866 CacheDir(main['M5_BUILD_CACHE']) 867 868# Find Python include and library directories for embedding the 869# interpreter. We rely on python-config to resolve the appropriate 870# includes and linker flags. ParseConfig does not seem to understand 871# the more exotic linker flags such as -Xlinker and -export-dynamic so 872# we add them explicitly below. If you want to link in an alternate 873# version of python, see above for instructions on how to invoke 874# scons with the appropriate PATH set. 875# 876# First we check if python2-config exists, else we use python-config 877python_config = readCommand(['which', 'python2-config'], exception='').strip() 878if not os.path.exists(python_config): 879 python_config = readCommand(['which', 'python-config'], 880 exception='').strip() 881py_includes = readCommand([python_config, '--includes'], 882 exception='').split() 883# Strip the -I from the include folders before adding them to the 884# CPPPATH 885main.Append(CPPPATH=map(lambda inc: inc[2:], py_includes)) 886 887# Read the linker flags and split them into libraries and other link 888# flags. The libraries are added later through the call the CheckLib. 889py_ld_flags = readCommand([python_config, '--ldflags'], exception='').split() 890py_libs = [] 891for lib in py_ld_flags: 892 if not lib.startswith('-l'): 893 main.Append(LINKFLAGS=[lib]) 894 else: 895 lib = lib[2:] 896 if lib not in py_libs: 897 py_libs.append(lib) 898 899# verify that this stuff works 900if not conf.CheckHeader('Python.h', '<>'): 901 print "Error: can't find Python.h header in", py_includes 902 print "Install Python headers (package python-dev on Ubuntu and RedHat)" 903 Exit(1) 904 905for lib in py_libs: 906 if not conf.CheckLib(lib): 907 print "Error: can't find library %s required by python" % lib 908 Exit(1) 909 910# On Solaris you need to use libsocket for socket ops 911if not conf.CheckLibWithHeader(None, 'sys/socket.h', 'C++', 'accept(0,0,0);'): 912 if not conf.CheckLibWithHeader('socket', 'sys/socket.h', 'C++', 'accept(0,0,0);'): 913 print "Can't find library with socket calls (e.g. accept())" 914 Exit(1) 915 916# Check for zlib. If the check passes, libz will be automatically 917# added to the LIBS environment variable. 918if not conf.CheckLibWithHeader('z', 'zlib.h', 'C++','zlibVersion();'): 919 print 'Error: did not find needed zlib compression library '\ 920 'and/or zlib.h header file.' 921 print ' Please install zlib and try again.' 922 Exit(1) 923 924# If we have the protobuf compiler, also make sure we have the 925# development libraries. If the check passes, libprotobuf will be 926# automatically added to the LIBS environment variable. After 927# this, we can use the HAVE_PROTOBUF flag to determine if we have 928# got both protoc and libprotobuf available. 929main['HAVE_PROTOBUF'] = main['PROTOC'] and \ 930 conf.CheckLibWithHeader('protobuf', 'google/protobuf/message.h', 931 'C++', 'GOOGLE_PROTOBUF_VERIFY_VERSION;') 932 933# If we have the compiler but not the library, print another warning. 934if main['PROTOC'] and not main['HAVE_PROTOBUF']: 935 print termcap.Yellow + termcap.Bold + \ 936 'Warning: did not find protocol buffer library and/or headers.\n' + \ 937 ' Please install libprotobuf-dev for tracing support.' + \ 938 termcap.Normal 939 940# Check for librt. 941have_posix_clock = \ 942 conf.CheckLibWithHeader(None, 'time.h', 'C', 943 'clock_nanosleep(0,0,NULL,NULL);') or \ 944 conf.CheckLibWithHeader('rt', 'time.h', 'C', 945 'clock_nanosleep(0,0,NULL,NULL);') 946 947have_posix_timers = \ 948 conf.CheckLibWithHeader([None, 'rt'], [ 'time.h', 'signal.h' ], 'C', 949 'timer_create(CLOCK_MONOTONIC, NULL, NULL);') 950 951if conf.CheckLib('tcmalloc'): 952 main.Append(CCFLAGS=main['TCMALLOC_CCFLAGS']) 953elif conf.CheckLib('tcmalloc_minimal'): 954 main.Append(CCFLAGS=main['TCMALLOC_CCFLAGS']) 955else: 956 print termcap.Yellow + termcap.Bold + \ 957 "You can get a 12% performance improvement by installing tcmalloc "\ 958 "(libgoogle-perftools-dev package on Ubuntu or RedHat)." + \ 959 termcap.Normal 960 961if not have_posix_clock: 962 print "Can't find library for POSIX clocks." 963 964# Check for <fenv.h> (C99 FP environment control) 965have_fenv = conf.CheckHeader('fenv.h', '<>') 966if not have_fenv: 967 print "Warning: Header file <fenv.h> not found." 968 print " This host has no IEEE FP rounding mode control." 969 970# Check if we should enable KVM-based hardware virtualization. The API 971# we rely on exists since version 2.6.36 of the kernel, but somehow 972# the KVM_API_VERSION does not reflect the change. We test for one of 973# the types as a fall back. 974have_kvm = conf.CheckHeader('linux/kvm.h', '<>') and \ 975 conf.CheckTypeSize('struct kvm_xsave', '#include <linux/kvm.h>') != 0 976if not have_kvm: 977 print "Info: Compatible header file <linux/kvm.h> not found, " \ 978 "disabling KVM support." 979 980# Check if the requested target ISA is compatible with the host 981def is_isa_kvm_compatible(isa): 982 isa_comp_table = { 983 "arm" : ( "armv7l" ), 984 "x86" : ( "x86_64" ), 985 } 986 try: 987 import platform 988 host_isa = platform.machine() 989 except: 990 print "Warning: Failed to determine host ISA." 991 return False 992 993 return host_isa in isa_comp_table.get(isa, []) 994 995 996# Check if the exclude_host attribute is available. We want this to 997# get accurate instruction counts in KVM. 998main['HAVE_PERF_ATTR_EXCLUDE_HOST'] = conf.CheckMember( 999 'linux/perf_event.h', 'struct perf_event_attr', 'exclude_host') 1000 1001 1002###################################################################### 1003# 1004# Finish the configuration 1005# 1006main = conf.Finish() 1007 1008###################################################################### 1009# 1010# Collect all non-global variables 1011# 1012 1013# Define the universe of supported ISAs 1014all_isa_list = [ ] 1015Export('all_isa_list') 1016 1017class CpuModel(object): 1018 '''The CpuModel class encapsulates everything the ISA parser needs to 1019 know about a particular CPU model.''' 1020 1021 # Dict of available CPU model objects. Accessible as CpuModel.dict. 1022 dict = {} 1023 list = [] 1024 defaults = [] 1025 1026 # Constructor. Automatically adds models to CpuModel.dict. 1027 def __init__(self, name, filename, includes, strings, default=False): 1028 self.name = name # name of model 1029 self.filename = filename # filename for output exec code 1030 self.includes = includes # include files needed in exec file 1031 # The 'strings' dict holds all the per-CPU symbols we can 1032 # substitute into templates etc. 1033 self.strings = strings 1034 1035 # This cpu is enabled by default 1036 self.default = default 1037 1038 # Add self to dict 1039 if name in CpuModel.dict: 1040 raise AttributeError, "CpuModel '%s' already registered" % name 1041 CpuModel.dict[name] = self 1042 CpuModel.list.append(name) 1043 1044Export('CpuModel') 1045 1046# Sticky variables get saved in the variables file so they persist from 1047# one invocation to the next (unless overridden, in which case the new 1048# value becomes sticky). 1049sticky_vars = Variables(args=ARGUMENTS) 1050Export('sticky_vars') 1051 1052# Sticky variables that should be exported 1053export_vars = [] 1054Export('export_vars') 1055 1056# For Ruby 1057all_protocols = [] 1058Export('all_protocols') 1059protocol_dirs = [] 1060Export('protocol_dirs') 1061slicc_includes = [] 1062Export('slicc_includes') 1063 1064# Walk the tree and execute all SConsopts scripts that wil add to the 1065# above variables 1066if GetOption('verbose'): 1067 print "Reading SConsopts" 1068for bdir in [ base_dir ] + extras_dir_list: 1069 if not isdir(bdir): 1070 print "Error: directory '%s' does not exist" % bdir 1071 Exit(1) 1072 for root, dirs, files in os.walk(bdir): 1073 if 'SConsopts' in files: 1074 if GetOption('verbose'): 1075 print "Reading", joinpath(root, 'SConsopts') 1076 SConscript(joinpath(root, 'SConsopts')) 1077 1078all_isa_list.sort() 1079 1080sticky_vars.AddVariables( 1081 EnumVariable('TARGET_ISA', 'Target ISA', 'alpha', all_isa_list), 1082 ListVariable('CPU_MODELS', 'CPU models', 1083 sorted(n for n,m in CpuModel.dict.iteritems() if m.default), 1084 sorted(CpuModel.list)), 1085 BoolVariable('EFENCE', 'Link with Electric Fence malloc debugger', 1086 False), 1087 BoolVariable('SS_COMPATIBLE_FP', 1088 'Make floating-point results compatible with SimpleScalar', 1089 False), 1090 BoolVariable('USE_SSE2', 1091 'Compile for SSE2 (-msse2) to get IEEE FP on x86 hosts', 1092 False), 1093 BoolVariable('USE_POSIX_CLOCK', 'Use POSIX Clocks', have_posix_clock), 1094 BoolVariable('USE_FENV', 'Use <fenv.h> IEEE mode control', have_fenv), 1095 BoolVariable('CP_ANNOTATE', 'Enable critical path annotation capability', False), 1096 BoolVariable('USE_KVM', 'Enable hardware virtualized (KVM) CPU models', have_kvm), 1097 EnumVariable('PROTOCOL', 'Coherence protocol for Ruby', 'None', 1098 all_protocols), 1099 ) 1100 1101# These variables get exported to #defines in config/*.hh (see src/SConscript). 1102export_vars += ['USE_FENV', 'SS_COMPATIBLE_FP', 'TARGET_ISA', 'CP_ANNOTATE', 1103 'USE_POSIX_CLOCK', 'PROTOCOL', 'HAVE_PROTOBUF', 1104 'HAVE_PERF_ATTR_EXCLUDE_HOST'] 1105 1106################################################### 1107# 1108# Define a SCons builder for configuration flag headers. 1109# 1110################################################### 1111 1112# This function generates a config header file that #defines the 1113# variable symbol to the current variable setting (0 or 1). The source 1114# operands are the name of the variable and a Value node containing the 1115# value of the variable. 1116def build_config_file(target, source, env): 1117 (variable, value) = [s.get_contents() for s in source] 1118 f = file(str(target[0]), 'w') 1119 print >> f, '#define', variable, value 1120 f.close() 1121 return None 1122 1123# Combine the two functions into a scons Action object. 1124config_action = MakeAction(build_config_file, Transform("CONFIG H", 2)) 1125 1126# The emitter munges the source & target node lists to reflect what 1127# we're really doing. 1128def config_emitter(target, source, env): 1129 # extract variable name from Builder arg 1130 variable = str(target[0]) 1131 # True target is config header file 1132 target = joinpath('config', variable.lower() + '.hh') 1133 val = env[variable] 1134 if isinstance(val, bool): 1135 # Force value to 0/1 1136 val = int(val) 1137 elif isinstance(val, str): 1138 val = '"' + val + '"' 1139 1140 # Sources are variable name & value (packaged in SCons Value nodes) 1141 return ([target], [Value(variable), Value(val)]) 1142 1143config_builder = Builder(emitter = config_emitter, action = config_action) 1144 1145main.Append(BUILDERS = { 'ConfigFile' : config_builder }) 1146 1147# libelf build is shared across all configs in the build root. 1148main.SConscript('ext/libelf/SConscript', 1149 variant_dir = joinpath(build_root, 'libelf')) 1150 1151# gzstream build is shared across all configs in the build root. 1152main.SConscript('ext/gzstream/SConscript', 1153 variant_dir = joinpath(build_root, 'gzstream')) 1154 1155# libfdt build is shared across all configs in the build root. 1156main.SConscript('ext/libfdt/SConscript', 1157 variant_dir = joinpath(build_root, 'libfdt')) 1158 1159# fputils build is shared across all configs in the build root. 1160main.SConscript('ext/fputils/SConscript', 1161 variant_dir = joinpath(build_root, 'fputils')) 1162 1163# DRAMSim2 build is shared across all configs in the build root. 1164main.SConscript('ext/dramsim2/SConscript', 1165 variant_dir = joinpath(build_root, 'dramsim2')) 1166 1167################################################### 1168# 1169# This function is used to set up a directory with switching headers 1170# 1171################################################### 1172 1173main['ALL_ISA_LIST'] = all_isa_list 1174def make_switching_dir(dname, switch_headers, env): 1175 # Generate the header. target[0] is the full path of the output 1176 # header to generate. 'source' is a dummy variable, since we get the 1177 # list of ISAs from env['ALL_ISA_LIST']. 1178 def gen_switch_hdr(target, source, env): 1179 fname = str(target[0]) 1180 f = open(fname, 'w') 1181 isa = env['TARGET_ISA'].lower() 1182 print >>f, '#include "%s/%s/%s"' % (dname, isa, basename(fname)) 1183 f.close() 1184 1185 # Build SCons Action object. 'varlist' specifies env vars that this 1186 # action depends on; when env['ALL_ISA_LIST'] changes these actions 1187 # should get re-executed. 1188 switch_hdr_action = MakeAction(gen_switch_hdr, 1189 Transform("GENERATE"), varlist=['ALL_ISA_LIST']) 1190 1191 # Instantiate actions for each header 1192 for hdr in switch_headers: 1193 env.Command(hdr, [], switch_hdr_action) 1194Export('make_switching_dir') 1195 1196################################################### 1197# 1198# Define build environments for selected configurations. 1199# 1200################################################### 1201 1202for variant_path in variant_paths: 1203 if not GetOption('silent'): 1204 print "Building in", variant_path 1205 1206 # Make a copy of the build-root environment to use for this config. 1207 env = main.Clone() 1208 env['BUILDDIR'] = variant_path 1209 1210 # variant_dir is the tail component of build path, and is used to 1211 # determine the build parameters (e.g., 'ALPHA_SE') 1212 (build_root, variant_dir) = splitpath(variant_path) 1213 1214 # Set env variables according to the build directory config. 1215 sticky_vars.files = [] 1216 # Variables for $BUILD_ROOT/$VARIANT_DIR are stored in 1217 # $BUILD_ROOT/variables/$VARIANT_DIR so you can nuke 1218 # $BUILD_ROOT/$VARIANT_DIR without losing your variables settings. 1219 current_vars_file = joinpath(build_root, 'variables', variant_dir) 1220 if isfile(current_vars_file): 1221 sticky_vars.files.append(current_vars_file) 1222 if not GetOption('silent'): 1223 print "Using saved variables file %s" % current_vars_file 1224 else: 1225 # Build dir-specific variables file doesn't exist. 1226 1227 # Make sure the directory is there so we can create it later 1228 opt_dir = dirname(current_vars_file) 1229 if not isdir(opt_dir): 1230 mkdir(opt_dir) 1231 1232 # Get default build variables from source tree. Variables are 1233 # normally determined by name of $VARIANT_DIR, but can be 1234 # overridden by '--default=' arg on command line. 1235 default = GetOption('default') 1236 opts_dir = joinpath(main.root.abspath, 'build_opts') 1237 if default: 1238 default_vars_files = [joinpath(build_root, 'variables', default), 1239 joinpath(opts_dir, default)] 1240 else: 1241 default_vars_files = [joinpath(opts_dir, variant_dir)] 1242 existing_files = filter(isfile, default_vars_files) 1243 if existing_files: 1244 default_vars_file = existing_files[0] 1245 sticky_vars.files.append(default_vars_file) 1246 print "Variables file %s not found,\n using defaults in %s" \ 1247 % (current_vars_file, default_vars_file) 1248 else: 1249 print "Error: cannot find variables file %s or " \ 1250 "default file(s) %s" \ 1251 % (current_vars_file, ' or '.join(default_vars_files)) 1252 Exit(1) 1253 1254 # Apply current variable settings to env 1255 sticky_vars.Update(env) 1256 1257 help_texts["local_vars"] += \ 1258 "Build variables for %s:\n" % variant_dir \ 1259 + sticky_vars.GenerateHelpText(env) 1260 1261 # Process variable settings. 1262 1263 if not have_fenv and env['USE_FENV']: 1264 print "Warning: <fenv.h> not available; " \ 1265 "forcing USE_FENV to False in", variant_dir + "." 1266 env['USE_FENV'] = False 1267 1268 if not env['USE_FENV']: 1269 print "Warning: No IEEE FP rounding mode control in", variant_dir + "." 1270 print " FP results may deviate slightly from other platforms." 1271 1272 if env['EFENCE']: 1273 env.Append(LIBS=['efence']) 1274 1275 if env['USE_KVM']: 1276 if not have_kvm: 1277 print "Warning: Can not enable KVM, host seems to lack KVM support" 1278 env['USE_KVM'] = False 1279 elif not have_posix_timers: 1280 print "Warning: Can not enable KVM, host seems to lack support " \ 1281 "for POSIX timers" 1282 env['USE_KVM'] = False 1283 elif not is_isa_kvm_compatible(env['TARGET_ISA']): 1284 print "Info: KVM support disabled due to unsupported host and " \ 1285 "target ISA combination" 1286 env['USE_KVM'] = False 1287 1288 # Warn about missing optional functionality 1289 if env['USE_KVM']: 1290 if not main['HAVE_PERF_ATTR_EXCLUDE_HOST']: 1291 print "Warning: perf_event headers lack support for the " \ 1292 "exclude_host attribute. KVM instruction counts will " \ 1293 "be inaccurate." 1294 1295 # Save sticky variable settings back to current variables file 1296 sticky_vars.Save(current_vars_file, env) 1297 1298 if env['USE_SSE2']: 1299 env.Append(CCFLAGS=['-msse2']) 1300 1301 # The src/SConscript file sets up the build rules in 'env' according 1302 # to the configured variables. It returns a list of environments, 1303 # one for each variant build (debug, opt, etc.) 1304 envList = SConscript('src/SConscript', variant_dir = variant_path, 1305 exports = 'env') 1306 1307 # Set up the regression tests for each build. 1308 for e in envList: 1309 SConscript('tests/SConscript', 1310 variant_dir = joinpath(variant_path, 'tests', e.Label), 1311 exports = { 'env' : e }, duplicate = False) 1312 1313# base help text 1314Help(''' 1315Usage: scons [scons options] [build variables] [target(s)] 1316 1317Extra scons options: 1318%(options)s 1319 1320Global build variables: 1321%(global_vars)s 1322 1323%(local_vars)s 1324''' % help_texts) 1325