SConstruct revision 10456
1# -*- mode:python -*- 2 3# Copyright (c) 2013 ARM Limited 4# All rights reserved. 5# 6# The license below extends only to copyright in the software and shall 7# not be construed as granting a license to any other intellectual 8# property including but not limited to intellectual property relating 9# to a hardware implementation of the functionality of the software 10# licensed hereunder. You may use the software subject to the license 11# terms below provided that you ensure that this notice is replicated 12# unmodified and in its entirety in all distributions of the software, 13# modified or unmodified, in source code or in binary form. 14# 15# Copyright (c) 2011 Advanced Micro Devices, Inc. 16# Copyright (c) 2009 The Hewlett-Packard Development Company 17# Copyright (c) 2004-2005 The Regents of The University of Michigan 18# All rights reserved. 19# 20# Redistribution and use in source and binary forms, with or without 21# modification, are permitted provided that the following conditions are 22# met: redistributions of source code must retain the above copyright 23# notice, this list of conditions and the following disclaimer; 24# redistributions in binary form must reproduce the above copyright 25# notice, this list of conditions and the following disclaimer in the 26# documentation and/or other materials provided with the distribution; 27# neither the name of the copyright holders nor the names of its 28# contributors may be used to endorse or promote products derived from 29# this software without specific prior written permission. 30# 31# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 34# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 36# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 37# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 38# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 39# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 40# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 41# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42# 43# Authors: Steve Reinhardt 44# Nathan Binkert 45 46################################################### 47# 48# SCons top-level build description (SConstruct) file. 49# 50# While in this directory ('gem5'), just type 'scons' to build the default 51# configuration (see below), or type 'scons build/<CONFIG>/<binary>' 52# to build some other configuration (e.g., 'build/ALPHA/gem5.opt' for 53# the optimized full-system version). 54# 55# You can build gem5 in a different directory as long as there is a 56# 'build/<CONFIG>' somewhere along the target path. The build system 57# expects that all configs under the same build directory are being 58# built for the same host system. 59# 60# Examples: 61# 62# The following two commands are equivalent. The '-u' option tells 63# scons to search up the directory tree for this SConstruct file. 64# % cd <path-to-src>/gem5 ; scons build/ALPHA/gem5.debug 65# % cd <path-to-src>/gem5/build/ALPHA; scons -u gem5.debug 66# 67# The following two commands are equivalent and demonstrate building 68# in a directory outside of the source tree. The '-C' option tells 69# scons to chdir to the specified directory to find this SConstruct 70# file. 71# % cd <path-to-src>/gem5 ; scons /local/foo/build/ALPHA/gem5.debug 72# % cd /local/foo/build/ALPHA; scons -C <path-to-src>/gem5 gem5.debug 73# 74# You can use 'scons -H' to print scons options. If you're in this 75# 'gem5' directory (or use -u or -C to tell scons where to find this 76# file), you can use 'scons -h' to print all the gem5-specific build 77# options as well. 78# 79################################################### 80 81# Check for recent-enough Python and SCons versions. 82try: 83 # Really old versions of scons only take two options for the 84 # function, so check once without the revision and once with the 85 # revision, the first instance will fail for stuff other than 86 # 0.98, and the second will fail for 0.98.0 87 EnsureSConsVersion(0, 98) 88 EnsureSConsVersion(0, 98, 1) 89except SystemExit, e: 90 print """ 91For more details, see: 92 http://gem5.org/Dependencies 93""" 94 raise 95 96# We ensure the python version early because because python-config 97# requires python 2.5 98try: 99 EnsurePythonVersion(2, 5) 100except SystemExit, e: 101 print """ 102You can use a non-default installation of the Python interpreter by 103rearranging your PATH so that scons finds the non-default 'python' and 104'python-config' first. 105 106For more details, see: 107 http://gem5.org/wiki/index.php/Using_a_non-default_Python_installation 108""" 109 raise 110 111# Global Python includes 112import itertools 113import os 114import re 115import subprocess 116import sys 117 118from os import mkdir, environ 119from os.path import abspath, basename, dirname, expanduser, normpath 120from os.path import exists, isdir, isfile 121from os.path import join as joinpath, split as splitpath 122 123# SCons includes 124import SCons 125import SCons.Node 126 127extra_python_paths = [ 128 Dir('src/python').srcnode().abspath, # gem5 includes 129 Dir('ext/ply').srcnode().abspath, # ply is used by several files 130 ] 131 132sys.path[1:1] = extra_python_paths 133 134from m5.util import compareVersions, readCommand 135from m5.util.terminal import get_termcap 136 137help_texts = { 138 "options" : "", 139 "global_vars" : "", 140 "local_vars" : "" 141} 142 143Export("help_texts") 144 145 146# There's a bug in scons in that (1) by default, the help texts from 147# AddOption() are supposed to be displayed when you type 'scons -h' 148# and (2) you can override the help displayed by 'scons -h' using the 149# Help() function, but these two features are incompatible: once 150# you've overridden the help text using Help(), there's no way to get 151# at the help texts from AddOptions. See: 152# http://scons.tigris.org/issues/show_bug.cgi?id=2356 153# http://scons.tigris.org/issues/show_bug.cgi?id=2611 154# This hack lets us extract the help text from AddOptions and 155# re-inject it via Help(). Ideally someday this bug will be fixed and 156# we can just use AddOption directly. 157def AddLocalOption(*args, **kwargs): 158 col_width = 30 159 160 help = " " + ", ".join(args) 161 if "help" in kwargs: 162 length = len(help) 163 if length >= col_width: 164 help += "\n" + " " * col_width 165 else: 166 help += " " * (col_width - length) 167 help += kwargs["help"] 168 help_texts["options"] += help + "\n" 169 170 AddOption(*args, **kwargs) 171 172AddLocalOption('--colors', dest='use_colors', action='store_true', 173 help="Add color to abbreviated scons output") 174AddLocalOption('--no-colors', dest='use_colors', action='store_false', 175 help="Don't add color to abbreviated scons output") 176AddLocalOption('--default', dest='default', type='string', action='store', 177 help='Override which build_opts file to use for defaults') 178AddLocalOption('--ignore-style', dest='ignore_style', action='store_true', 179 help='Disable style checking hooks') 180AddLocalOption('--no-lto', dest='no_lto', action='store_true', 181 help='Disable Link-Time Optimization for fast') 182AddLocalOption('--update-ref', dest='update_ref', action='store_true', 183 help='Update test reference outputs') 184AddLocalOption('--verbose', dest='verbose', action='store_true', 185 help='Print full tool command lines') 186AddLocalOption('--without-python', dest='without_python', 187 action='store_true', 188 help='Build without Python configuration support') 189AddLocalOption('--without-tcmalloc', dest='without_tcmalloc', 190 action='store_true', 191 help='Disable linking against tcmalloc') 192 193termcap = get_termcap(GetOption('use_colors')) 194 195######################################################################## 196# 197# Set up the main build environment. 198# 199######################################################################## 200 201# export TERM so that clang reports errors in color 202use_vars = set([ 'AS', 'AR', 'CC', 'CXX', 'HOME', 'LD_LIBRARY_PATH', 203 'LIBRARY_PATH', 'PATH', 'PKG_CONFIG_PATH', 'PROTOC', 204 'PYTHONPATH', 'RANLIB', 'SWIG', 'TERM' ]) 205 206use_prefixes = [ 207 "M5", # M5 configuration (e.g., path to kernels) 208 "DISTCC_", # distcc (distributed compiler wrapper) configuration 209 "CCACHE_", # ccache (caching compiler wrapper) configuration 210 "CCC_", # clang static analyzer configuration 211 ] 212 213use_env = {} 214for key,val in os.environ.iteritems(): 215 if key in use_vars or \ 216 any([key.startswith(prefix) for prefix in use_prefixes]): 217 use_env[key] = val 218 219main = Environment(ENV=use_env) 220main.Decider('MD5-timestamp') 221main.root = Dir(".") # The current directory (where this file lives). 222main.srcdir = Dir("src") # The source directory 223 224main_dict_keys = main.Dictionary().keys() 225 226# Check that we have a C/C++ compiler 227if not ('CC' in main_dict_keys and 'CXX' in main_dict_keys): 228 print "No C++ compiler installed (package g++ on Ubuntu and RedHat)" 229 Exit(1) 230 231# Check that swig is present 232if not 'SWIG' in main_dict_keys: 233 print "swig is not installed (package swig on Ubuntu and RedHat)" 234 Exit(1) 235 236# add useful python code PYTHONPATH so it can be used by subprocesses 237# as well 238main.AppendENVPath('PYTHONPATH', extra_python_paths) 239 240######################################################################## 241# 242# Mercurial Stuff. 243# 244# If the gem5 directory is a mercurial repository, we should do some 245# extra things. 246# 247######################################################################## 248 249hgdir = main.root.Dir(".hg") 250 251mercurial_style_message = """ 252You're missing the gem5 style hook, which automatically checks your code 253against the gem5 style rules on hg commit and qrefresh commands. This 254script will now install the hook in your .hg/hgrc file. 255Press enter to continue, or ctrl-c to abort: """ 256 257mercurial_style_hook = """ 258# The following lines were automatically added by gem5/SConstruct 259# to provide the gem5 style-checking hooks 260[extensions] 261style = %s/util/style.py 262 263[hooks] 264pretxncommit.style = python:style.check_style 265pre-qrefresh.style = python:style.check_style 266# End of SConstruct additions 267 268""" % (main.root.abspath) 269 270mercurial_lib_not_found = """ 271Mercurial libraries cannot be found, ignoring style hook. If 272you are a gem5 developer, please fix this and run the style 273hook. It is important. 274""" 275 276# Check for style hook and prompt for installation if it's not there. 277# Skip this if --ignore-style was specified, there's no .hg dir to 278# install a hook in, or there's no interactive terminal to prompt. 279if not GetOption('ignore_style') and hgdir.exists() and sys.stdin.isatty(): 280 style_hook = True 281 try: 282 from mercurial import ui 283 ui = ui.ui() 284 ui.readconfig(hgdir.File('hgrc').abspath) 285 style_hook = ui.config('hooks', 'pretxncommit.style', None) and \ 286 ui.config('hooks', 'pre-qrefresh.style', None) 287 except ImportError: 288 print mercurial_lib_not_found 289 290 if not style_hook: 291 print mercurial_style_message, 292 # continue unless user does ctrl-c/ctrl-d etc. 293 try: 294 raw_input() 295 except: 296 print "Input exception, exiting scons.\n" 297 sys.exit(1) 298 hgrc_path = '%s/.hg/hgrc' % main.root.abspath 299 print "Adding style hook to", hgrc_path, "\n" 300 try: 301 hgrc = open(hgrc_path, 'a') 302 hgrc.write(mercurial_style_hook) 303 hgrc.close() 304 except: 305 print "Error updating", hgrc_path 306 sys.exit(1) 307 308 309################################################### 310# 311# Figure out which configurations to set up based on the path(s) of 312# the target(s). 313# 314################################################### 315 316# Find default configuration & binary. 317Default(environ.get('M5_DEFAULT_BINARY', 'build/ALPHA/gem5.debug')) 318 319# helper function: find last occurrence of element in list 320def rfind(l, elt, offs = -1): 321 for i in range(len(l)+offs, 0, -1): 322 if l[i] == elt: 323 return i 324 raise ValueError, "element not found" 325 326# Take a list of paths (or SCons Nodes) and return a list with all 327# paths made absolute and ~-expanded. Paths will be interpreted 328# relative to the launch directory unless a different root is provided 329def makePathListAbsolute(path_list, root=GetLaunchDir()): 330 return [abspath(joinpath(root, expanduser(str(p)))) 331 for p in path_list] 332 333# Each target must have 'build' in the interior of the path; the 334# directory below this will determine the build parameters. For 335# example, for target 'foo/bar/build/ALPHA_SE/arch/alpha/blah.do' we 336# recognize that ALPHA_SE specifies the configuration because it 337# follow 'build' in the build path. 338 339# The funky assignment to "[:]" is needed to replace the list contents 340# in place rather than reassign the symbol to a new list, which 341# doesn't work (obviously!). 342BUILD_TARGETS[:] = makePathListAbsolute(BUILD_TARGETS) 343 344# Generate a list of the unique build roots and configs that the 345# collected targets reference. 346variant_paths = [] 347build_root = None 348for t in BUILD_TARGETS: 349 path_dirs = t.split('/') 350 try: 351 build_top = rfind(path_dirs, 'build', -2) 352 except: 353 print "Error: no non-leaf 'build' dir found on target path", t 354 Exit(1) 355 this_build_root = joinpath('/',*path_dirs[:build_top+1]) 356 if not build_root: 357 build_root = this_build_root 358 else: 359 if this_build_root != build_root: 360 print "Error: build targets not under same build root\n"\ 361 " %s\n %s" % (build_root, this_build_root) 362 Exit(1) 363 variant_path = joinpath('/',*path_dirs[:build_top+2]) 364 if variant_path not in variant_paths: 365 variant_paths.append(variant_path) 366 367# Make sure build_root exists (might not if this is the first build there) 368if not isdir(build_root): 369 mkdir(build_root) 370main['BUILDROOT'] = build_root 371 372Export('main') 373 374main.SConsignFile(joinpath(build_root, "sconsign")) 375 376# Default duplicate option is to use hard links, but this messes up 377# when you use emacs to edit a file in the target dir, as emacs moves 378# file to file~ then copies to file, breaking the link. Symbolic 379# (soft) links work better. 380main.SetOption('duplicate', 'soft-copy') 381 382# 383# Set up global sticky variables... these are common to an entire build 384# tree (not specific to a particular build like ALPHA_SE) 385# 386 387global_vars_file = joinpath(build_root, 'variables.global') 388 389global_vars = Variables(global_vars_file, args=ARGUMENTS) 390 391global_vars.AddVariables( 392 ('CC', 'C compiler', environ.get('CC', main['CC'])), 393 ('CXX', 'C++ compiler', environ.get('CXX', main['CXX'])), 394 ('SWIG', 'SWIG tool', environ.get('SWIG', main['SWIG'])), 395 ('PROTOC', 'protoc tool', environ.get('PROTOC', 'protoc')), 396 ('BATCH', 'Use batch pool for build and tests', False), 397 ('BATCH_CMD', 'Batch pool submission command name', 'qdo'), 398 ('M5_BUILD_CACHE', 'Cache built objects in this directory', False), 399 ('EXTRAS', 'Add extra directories to the compilation', '') 400 ) 401 402# Update main environment with values from ARGUMENTS & global_vars_file 403global_vars.Update(main) 404help_texts["global_vars"] += global_vars.GenerateHelpText(main) 405 406# Save sticky variable settings back to current variables file 407global_vars.Save(global_vars_file, main) 408 409# Parse EXTRAS variable to build list of all directories where we're 410# look for sources etc. This list is exported as extras_dir_list. 411base_dir = main.srcdir.abspath 412if main['EXTRAS']: 413 extras_dir_list = makePathListAbsolute(main['EXTRAS'].split(':')) 414else: 415 extras_dir_list = [] 416 417Export('base_dir') 418Export('extras_dir_list') 419 420# the ext directory should be on the #includes path 421main.Append(CPPPATH=[Dir('ext')]) 422 423def strip_build_path(path, env): 424 path = str(path) 425 variant_base = env['BUILDROOT'] + os.path.sep 426 if path.startswith(variant_base): 427 path = path[len(variant_base):] 428 elif path.startswith('build/'): 429 path = path[6:] 430 return path 431 432# Generate a string of the form: 433# common/path/prefix/src1, src2 -> tgt1, tgt2 434# to print while building. 435class Transform(object): 436 # all specific color settings should be here and nowhere else 437 tool_color = termcap.Normal 438 pfx_color = termcap.Yellow 439 srcs_color = termcap.Yellow + termcap.Bold 440 arrow_color = termcap.Blue + termcap.Bold 441 tgts_color = termcap.Yellow + termcap.Bold 442 443 def __init__(self, tool, max_sources=99): 444 self.format = self.tool_color + (" [%8s] " % tool) \ 445 + self.pfx_color + "%s" \ 446 + self.srcs_color + "%s" \ 447 + self.arrow_color + " -> " \ 448 + self.tgts_color + "%s" \ 449 + termcap.Normal 450 self.max_sources = max_sources 451 452 def __call__(self, target, source, env, for_signature=None): 453 # truncate source list according to max_sources param 454 source = source[0:self.max_sources] 455 def strip(f): 456 return strip_build_path(str(f), env) 457 if len(source) > 0: 458 srcs = map(strip, source) 459 else: 460 srcs = [''] 461 tgts = map(strip, target) 462 # surprisingly, os.path.commonprefix is a dumb char-by-char string 463 # operation that has nothing to do with paths. 464 com_pfx = os.path.commonprefix(srcs + tgts) 465 com_pfx_len = len(com_pfx) 466 if com_pfx: 467 # do some cleanup and sanity checking on common prefix 468 if com_pfx[-1] == ".": 469 # prefix matches all but file extension: ok 470 # back up one to change 'foo.cc -> o' to 'foo.cc -> .o' 471 com_pfx = com_pfx[0:-1] 472 elif com_pfx[-1] == "/": 473 # common prefix is directory path: OK 474 pass 475 else: 476 src0_len = len(srcs[0]) 477 tgt0_len = len(tgts[0]) 478 if src0_len == com_pfx_len: 479 # source is a substring of target, OK 480 pass 481 elif tgt0_len == com_pfx_len: 482 # target is a substring of source, need to back up to 483 # avoid empty string on RHS of arrow 484 sep_idx = com_pfx.rfind(".") 485 if sep_idx != -1: 486 com_pfx = com_pfx[0:sep_idx] 487 else: 488 com_pfx = '' 489 elif src0_len > com_pfx_len and srcs[0][com_pfx_len] == ".": 490 # still splitting at file extension: ok 491 pass 492 else: 493 # probably a fluke; ignore it 494 com_pfx = '' 495 # recalculate length in case com_pfx was modified 496 com_pfx_len = len(com_pfx) 497 def fmt(files): 498 f = map(lambda s: s[com_pfx_len:], files) 499 return ', '.join(f) 500 return self.format % (com_pfx, fmt(srcs), fmt(tgts)) 501 502Export('Transform') 503 504# enable the regression script to use the termcap 505main['TERMCAP'] = termcap 506 507if GetOption('verbose'): 508 def MakeAction(action, string, *args, **kwargs): 509 return Action(action, *args, **kwargs) 510else: 511 MakeAction = Action 512 main['CCCOMSTR'] = Transform("CC") 513 main['CXXCOMSTR'] = Transform("CXX") 514 main['ASCOMSTR'] = Transform("AS") 515 main['SWIGCOMSTR'] = Transform("SWIG") 516 main['ARCOMSTR'] = Transform("AR", 0) 517 main['LINKCOMSTR'] = Transform("LINK", 0) 518 main['RANLIBCOMSTR'] = Transform("RANLIB", 0) 519 main['M4COMSTR'] = Transform("M4") 520 main['SHCCCOMSTR'] = Transform("SHCC") 521 main['SHCXXCOMSTR'] = Transform("SHCXX") 522Export('MakeAction') 523 524# Initialize the Link-Time Optimization (LTO) flags 525main['LTO_CCFLAGS'] = [] 526main['LTO_LDFLAGS'] = [] 527 528# According to the readme, tcmalloc works best if the compiler doesn't 529# assume that we're using the builtin malloc and friends. These flags 530# are compiler-specific, so we need to set them after we detect which 531# compiler we're using. 532main['TCMALLOC_CCFLAGS'] = [] 533 534CXX_version = readCommand([main['CXX'],'--version'], exception=False) 535CXX_V = readCommand([main['CXX'],'-V'], exception=False) 536 537main['GCC'] = CXX_version and CXX_version.find('g++') >= 0 538main['CLANG'] = CXX_version and CXX_version.find('clang') >= 0 539if main['GCC'] + main['CLANG'] > 1: 540 print 'Error: How can we have two at the same time?' 541 Exit(1) 542 543# Set up default C++ compiler flags 544if main['GCC'] or main['CLANG']: 545 # As gcc and clang share many flags, do the common parts here 546 main.Append(CCFLAGS=['-pipe']) 547 main.Append(CCFLAGS=['-fno-strict-aliasing']) 548 # Enable -Wall and then disable the few warnings that we 549 # consistently violate 550 main.Append(CCFLAGS=['-Wall', '-Wno-sign-compare', '-Wundef']) 551 # We always compile using C++11, but only gcc >= 4.7 and clang 3.1 552 # actually use that name, so we stick with c++0x 553 main.Append(CXXFLAGS=['-std=c++0x']) 554 # Add selected sanity checks from -Wextra 555 main.Append(CXXFLAGS=['-Wmissing-field-initializers', 556 '-Woverloaded-virtual']) 557else: 558 print termcap.Yellow + termcap.Bold + 'Error' + termcap.Normal, 559 print "Don't know what compiler options to use for your compiler." 560 print termcap.Yellow + ' compiler:' + termcap.Normal, main['CXX'] 561 print termcap.Yellow + ' version:' + termcap.Normal, 562 if not CXX_version: 563 print termcap.Yellow + termcap.Bold + "COMMAND NOT FOUND!" +\ 564 termcap.Normal 565 else: 566 print CXX_version.replace('\n', '<nl>') 567 print " If you're trying to use a compiler other than GCC" 568 print " or clang, there appears to be something wrong with your" 569 print " environment." 570 print " " 571 print " If you are trying to use a compiler other than those listed" 572 print " above you will need to ease fix SConstruct and " 573 print " src/SConscript to support that compiler." 574 Exit(1) 575 576if main['GCC']: 577 # Check for a supported version of gcc. >= 4.6 is chosen for its 578 # level of c++11 support. See 579 # http://gcc.gnu.org/projects/cxx0x.html for details. 4.6 is also 580 # the first version with proper LTO support. 581 gcc_version = readCommand([main['CXX'], '-dumpversion'], exception=False) 582 if compareVersions(gcc_version, "4.6") < 0: 583 print 'Error: gcc version 4.6 or newer required.' 584 print ' Installed version:', gcc_version 585 Exit(1) 586 587 main['GCC_VERSION'] = gcc_version 588 589 # gcc from version 4.8 and above generates "rep; ret" instructions 590 # to avoid performance penalties on certain AMD chips. Older 591 # assemblers detect this as an error, "Error: expecting string 592 # instruction after `rep'" 593 if compareVersions(gcc_version, "4.8") > 0: 594 as_version = readCommand([main['AS'], '-v', '/dev/null'], 595 exception=False).split() 596 597 if not as_version or compareVersions(as_version[-1], "2.23") < 0: 598 print termcap.Yellow + termcap.Bold + \ 599 'Warning: This combination of gcc and binutils have' + \ 600 ' known incompatibilities.\n' + \ 601 ' If you encounter build problems, please update ' + \ 602 'binutils to 2.23.' + \ 603 termcap.Normal 604 605 # Add the appropriate Link-Time Optimization (LTO) flags 606 # unless LTO is explicitly turned off. Note that these flags 607 # are only used by the fast target. 608 if not GetOption('no_lto'): 609 # Pass the LTO flag when compiling to produce GIMPLE 610 # output, we merely create the flags here and only append 611 # them later 612 main['LTO_CCFLAGS'] = ['-flto=%d' % GetOption('num_jobs')] 613 614 # Use the same amount of jobs for LTO as we are running 615 # scons with 616 main['LTO_LDFLAGS'] = ['-flto=%d' % GetOption('num_jobs')] 617 618 main.Append(TCMALLOC_CCFLAGS=['-fno-builtin-malloc', '-fno-builtin-calloc', 619 '-fno-builtin-realloc', '-fno-builtin-free']) 620 621elif main['CLANG']: 622 # Check for a supported version of clang, >= 3.0 is needed to 623 # support similar features as gcc 4.6. See 624 # http://clang.llvm.org/cxx_status.html for details 625 clang_version_re = re.compile(".* version (\d+\.\d+)") 626 clang_version_match = clang_version_re.search(CXX_version) 627 if (clang_version_match): 628 clang_version = clang_version_match.groups()[0] 629 if compareVersions(clang_version, "3.0") < 0: 630 print 'Error: clang version 3.0 or newer required.' 631 print ' Installed version:', clang_version 632 Exit(1) 633 else: 634 print 'Error: Unable to determine clang version.' 635 Exit(1) 636 637 # clang has a few additional warnings that we disable, 638 # tautological comparisons are allowed due to unsigned integers 639 # being compared to constants that happen to be 0, and extraneous 640 # parantheses are allowed due to Ruby's printing of the AST, 641 # finally self assignments are allowed as the generated CPU code 642 # is relying on this 643 main.Append(CCFLAGS=['-Wno-tautological-compare', 644 '-Wno-parentheses', 645 '-Wno-self-assign', 646 # Some versions of libstdc++ (4.8?) seem to 647 # use struct hash and class hash 648 # interchangeably. 649 '-Wno-mismatched-tags', 650 ]) 651 652 main.Append(TCMALLOC_CCFLAGS=['-fno-builtin']) 653 654 # On Mac OS X/Darwin we need to also use libc++ (part of XCode) as 655 # opposed to libstdc++, as the later is dated. 656 if sys.platform == "darwin": 657 main.Append(CXXFLAGS=['-stdlib=libc++']) 658 main.Append(LIBS=['c++']) 659 660else: 661 print termcap.Yellow + termcap.Bold + 'Error' + termcap.Normal, 662 print "Don't know what compiler options to use for your compiler." 663 print termcap.Yellow + ' compiler:' + termcap.Normal, main['CXX'] 664 print termcap.Yellow + ' version:' + termcap.Normal, 665 if not CXX_version: 666 print termcap.Yellow + termcap.Bold + "COMMAND NOT FOUND!" +\ 667 termcap.Normal 668 else: 669 print CXX_version.replace('\n', '<nl>') 670 print " If you're trying to use a compiler other than GCC" 671 print " or clang, there appears to be something wrong with your" 672 print " environment." 673 print " " 674 print " If you are trying to use a compiler other than those listed" 675 print " above you will need to ease fix SConstruct and " 676 print " src/SConscript to support that compiler." 677 Exit(1) 678 679# Set up common yacc/bison flags (needed for Ruby) 680main['YACCFLAGS'] = '-d' 681main['YACCHXXFILESUFFIX'] = '.hh' 682 683# Do this after we save setting back, or else we'll tack on an 684# extra 'qdo' every time we run scons. 685if main['BATCH']: 686 main['CC'] = main['BATCH_CMD'] + ' ' + main['CC'] 687 main['CXX'] = main['BATCH_CMD'] + ' ' + main['CXX'] 688 main['AS'] = main['BATCH_CMD'] + ' ' + main['AS'] 689 main['AR'] = main['BATCH_CMD'] + ' ' + main['AR'] 690 main['RANLIB'] = main['BATCH_CMD'] + ' ' + main['RANLIB'] 691 692if sys.platform == 'cygwin': 693 # cygwin has some header file issues... 694 main.Append(CCFLAGS=["-Wno-uninitialized"]) 695 696# Check for the protobuf compiler 697protoc_version = readCommand([main['PROTOC'], '--version'], 698 exception='').split() 699 700# First two words should be "libprotoc x.y.z" 701if len(protoc_version) < 2 or protoc_version[0] != 'libprotoc': 702 print termcap.Yellow + termcap.Bold + \ 703 'Warning: Protocol buffer compiler (protoc) not found.\n' + \ 704 ' Please install protobuf-compiler for tracing support.' + \ 705 termcap.Normal 706 main['PROTOC'] = False 707else: 708 # Based on the availability of the compress stream wrappers, 709 # require 2.1.0 710 min_protoc_version = '2.1.0' 711 if compareVersions(protoc_version[1], min_protoc_version) < 0: 712 print termcap.Yellow + termcap.Bold + \ 713 'Warning: protoc version', min_protoc_version, \ 714 'or newer required.\n' + \ 715 ' Installed version:', protoc_version[1], \ 716 termcap.Normal 717 main['PROTOC'] = False 718 else: 719 # Attempt to determine the appropriate include path and 720 # library path using pkg-config, that means we also need to 721 # check for pkg-config. Note that it is possible to use 722 # protobuf without the involvement of pkg-config. Later on we 723 # check go a library config check and at that point the test 724 # will fail if libprotobuf cannot be found. 725 if readCommand(['pkg-config', '--version'], exception=''): 726 try: 727 # Attempt to establish what linking flags to add for protobuf 728 # using pkg-config 729 main.ParseConfig('pkg-config --cflags --libs-only-L protobuf') 730 except: 731 print termcap.Yellow + termcap.Bold + \ 732 'Warning: pkg-config could not get protobuf flags.' + \ 733 termcap.Normal 734 735# Check for SWIG 736if not main.has_key('SWIG'): 737 print 'Error: SWIG utility not found.' 738 print ' Please install (see http://www.swig.org) and retry.' 739 Exit(1) 740 741# Check for appropriate SWIG version 742swig_version = readCommand([main['SWIG'], '-version'], exception='').split() 743# First 3 words should be "SWIG Version x.y.z" 744if len(swig_version) < 3 or \ 745 swig_version[0] != 'SWIG' or swig_version[1] != 'Version': 746 print 'Error determining SWIG version.' 747 Exit(1) 748 749min_swig_version = '2.0.4' 750if compareVersions(swig_version[2], min_swig_version) < 0: 751 print 'Error: SWIG version', min_swig_version, 'or newer required.' 752 print ' Installed version:', swig_version[2] 753 Exit(1) 754 755# Check for known incompatibilities. The standard library shipped with 756# gcc >= 4.9 does not play well with swig versions prior to 3.0 757if main['GCC'] and compareVersions(gcc_version, '4.9') >= 0 and \ 758 compareVersions(swig_version[2], '3.0') < 0: 759 print termcap.Yellow + termcap.Bold + \ 760 'Warning: This combination of gcc and swig have' + \ 761 ' known incompatibilities.\n' + \ 762 ' If you encounter build problems, please update ' + \ 763 'swig to 3.0 or later.' + \ 764 termcap.Normal 765 766# Set up SWIG flags & scanner 767swig_flags=Split('-c++ -python -modern -templatereduce $_CPPINCFLAGS') 768main.Append(SWIGFLAGS=swig_flags) 769 770# Check for 'timeout' from GNU coreutils. If present, regressions 771# will be run with a time limit. 772TIMEOUT_version = readCommand(['timeout', '--version'], exception=False) 773main['TIMEOUT'] = TIMEOUT_version and TIMEOUT_version.find('timeout') == 0 774 775# filter out all existing swig scanners, they mess up the dependency 776# stuff for some reason 777scanners = [] 778for scanner in main['SCANNERS']: 779 skeys = scanner.skeys 780 if skeys == '.i': 781 continue 782 783 if isinstance(skeys, (list, tuple)) and '.i' in skeys: 784 continue 785 786 scanners.append(scanner) 787 788# add the new swig scanner that we like better 789from SCons.Scanner import ClassicCPP as CPPScanner 790swig_inc_re = '^[ \t]*[%,#][ \t]*(?:include|import)[ \t]*(<|")([^>"]+)(>|")' 791scanners.append(CPPScanner("SwigScan", [ ".i" ], "CPPPATH", swig_inc_re)) 792 793# replace the scanners list that has what we want 794main['SCANNERS'] = scanners 795 796# Add a custom Check function to the Configure context so that we can 797# figure out if the compiler adds leading underscores to global 798# variables. This is needed for the autogenerated asm files that we 799# use for embedding the python code. 800def CheckLeading(context): 801 context.Message("Checking for leading underscore in global variables...") 802 # 1) Define a global variable called x from asm so the C compiler 803 # won't change the symbol at all. 804 # 2) Declare that variable. 805 # 3) Use the variable 806 # 807 # If the compiler prepends an underscore, this will successfully 808 # link because the external symbol 'x' will be called '_x' which 809 # was defined by the asm statement. If the compiler does not 810 # prepend an underscore, this will not successfully link because 811 # '_x' will have been defined by assembly, while the C portion of 812 # the code will be trying to use 'x' 813 ret = context.TryLink(''' 814 asm(".globl _x; _x: .byte 0"); 815 extern int x; 816 int main() { return x; } 817 ''', extension=".c") 818 context.env.Append(LEADING_UNDERSCORE=ret) 819 context.Result(ret) 820 return ret 821 822# Add a custom Check function to test for structure members. 823def CheckMember(context, include, decl, member, include_quotes="<>"): 824 context.Message("Checking for member %s in %s..." % 825 (member, decl)) 826 text = """ 827#include %(header)s 828int main(){ 829 %(decl)s test; 830 (void)test.%(member)s; 831 return 0; 832}; 833""" % { "header" : include_quotes[0] + include + include_quotes[1], 834 "decl" : decl, 835 "member" : member, 836 } 837 838 ret = context.TryCompile(text, extension=".cc") 839 context.Result(ret) 840 return ret 841 842# Platform-specific configuration. Note again that we assume that all 843# builds under a given build root run on the same host platform. 844conf = Configure(main, 845 conf_dir = joinpath(build_root, '.scons_config'), 846 log_file = joinpath(build_root, 'scons_config.log'), 847 custom_tests = { 848 'CheckLeading' : CheckLeading, 849 'CheckMember' : CheckMember, 850 }) 851 852# Check for leading underscores. Don't really need to worry either 853# way so don't need to check the return code. 854conf.CheckLeading() 855 856# Check if we should compile a 64 bit binary on Mac OS X/Darwin 857try: 858 import platform 859 uname = platform.uname() 860 if uname[0] == 'Darwin' and compareVersions(uname[2], '9.0.0') >= 0: 861 if int(readCommand('sysctl -n hw.cpu64bit_capable')[0]): 862 main.Append(CCFLAGS=['-arch', 'x86_64']) 863 main.Append(CFLAGS=['-arch', 'x86_64']) 864 main.Append(LINKFLAGS=['-arch', 'x86_64']) 865 main.Append(ASFLAGS=['-arch', 'x86_64']) 866except: 867 pass 868 869# Recent versions of scons substitute a "Null" object for Configure() 870# when configuration isn't necessary, e.g., if the "--help" option is 871# present. Unfortuantely this Null object always returns false, 872# breaking all our configuration checks. We replace it with our own 873# more optimistic null object that returns True instead. 874if not conf: 875 def NullCheck(*args, **kwargs): 876 return True 877 878 class NullConf: 879 def __init__(self, env): 880 self.env = env 881 def Finish(self): 882 return self.env 883 def __getattr__(self, mname): 884 return NullCheck 885 886 conf = NullConf(main) 887 888# Cache build files in the supplied directory. 889if main['M5_BUILD_CACHE']: 890 print 'Using build cache located at', main['M5_BUILD_CACHE'] 891 CacheDir(main['M5_BUILD_CACHE']) 892 893if not GetOption('without_python'): 894 # Find Python include and library directories for embedding the 895 # interpreter. We rely on python-config to resolve the appropriate 896 # includes and linker flags. ParseConfig does not seem to understand 897 # the more exotic linker flags such as -Xlinker and -export-dynamic so 898 # we add them explicitly below. If you want to link in an alternate 899 # version of python, see above for instructions on how to invoke 900 # scons with the appropriate PATH set. 901 # 902 # First we check if python2-config exists, else we use python-config 903 python_config = readCommand(['which', 'python2-config'], 904 exception='').strip() 905 if not os.path.exists(python_config): 906 python_config = readCommand(['which', 'python-config'], 907 exception='').strip() 908 py_includes = readCommand([python_config, '--includes'], 909 exception='').split() 910 # Strip the -I from the include folders before adding them to the 911 # CPPPATH 912 main.Append(CPPPATH=map(lambda inc: inc[2:], py_includes)) 913 914 # Read the linker flags and split them into libraries and other link 915 # flags. The libraries are added later through the call the CheckLib. 916 py_ld_flags = readCommand([python_config, '--ldflags'], 917 exception='').split() 918 py_libs = [] 919 for lib in py_ld_flags: 920 if not lib.startswith('-l'): 921 main.Append(LINKFLAGS=[lib]) 922 else: 923 lib = lib[2:] 924 if lib not in py_libs: 925 py_libs.append(lib) 926 927 # verify that this stuff works 928 if not conf.CheckHeader('Python.h', '<>'): 929 print "Error: can't find Python.h header in", py_includes 930 print "Install Python headers (package python-dev on Ubuntu and RedHat)" 931 Exit(1) 932 933 for lib in py_libs: 934 if not conf.CheckLib(lib): 935 print "Error: can't find library %s required by python" % lib 936 Exit(1) 937 938# On Solaris you need to use libsocket for socket ops 939if not conf.CheckLibWithHeader(None, 'sys/socket.h', 'C++', 'accept(0,0,0);'): 940 if not conf.CheckLibWithHeader('socket', 'sys/socket.h', 'C++', 'accept(0,0,0);'): 941 print "Can't find library with socket calls (e.g. accept())" 942 Exit(1) 943 944# Check for zlib. If the check passes, libz will be automatically 945# added to the LIBS environment variable. 946if not conf.CheckLibWithHeader('z', 'zlib.h', 'C++','zlibVersion();'): 947 print 'Error: did not find needed zlib compression library '\ 948 'and/or zlib.h header file.' 949 print ' Please install zlib and try again.' 950 Exit(1) 951 952# If we have the protobuf compiler, also make sure we have the 953# development libraries. If the check passes, libprotobuf will be 954# automatically added to the LIBS environment variable. After 955# this, we can use the HAVE_PROTOBUF flag to determine if we have 956# got both protoc and libprotobuf available. 957main['HAVE_PROTOBUF'] = main['PROTOC'] and \ 958 conf.CheckLibWithHeader('protobuf', 'google/protobuf/message.h', 959 'C++', 'GOOGLE_PROTOBUF_VERIFY_VERSION;') 960 961# If we have the compiler but not the library, print another warning. 962if main['PROTOC'] and not main['HAVE_PROTOBUF']: 963 print termcap.Yellow + termcap.Bold + \ 964 'Warning: did not find protocol buffer library and/or headers.\n' + \ 965 ' Please install libprotobuf-dev for tracing support.' + \ 966 termcap.Normal 967 968# Check for librt. 969have_posix_clock = \ 970 conf.CheckLibWithHeader(None, 'time.h', 'C', 971 'clock_nanosleep(0,0,NULL,NULL);') or \ 972 conf.CheckLibWithHeader('rt', 'time.h', 'C', 973 'clock_nanosleep(0,0,NULL,NULL);') 974 975have_posix_timers = \ 976 conf.CheckLibWithHeader([None, 'rt'], [ 'time.h', 'signal.h' ], 'C', 977 'timer_create(CLOCK_MONOTONIC, NULL, NULL);') 978 979if not GetOption('without_tcmalloc'): 980 if conf.CheckLib('tcmalloc'): 981 main.Append(CCFLAGS=main['TCMALLOC_CCFLAGS']) 982 elif conf.CheckLib('tcmalloc_minimal'): 983 main.Append(CCFLAGS=main['TCMALLOC_CCFLAGS']) 984 else: 985 print termcap.Yellow + termcap.Bold + \ 986 "You can get a 12% performance improvement by "\ 987 "installing tcmalloc (libgoogle-perftools-dev package "\ 988 "on Ubuntu or RedHat)." + termcap.Normal 989 990if not have_posix_clock: 991 print "Can't find library for POSIX clocks." 992 993# Check for <fenv.h> (C99 FP environment control) 994have_fenv = conf.CheckHeader('fenv.h', '<>') 995if not have_fenv: 996 print "Warning: Header file <fenv.h> not found." 997 print " This host has no IEEE FP rounding mode control." 998 999# Check if we should enable KVM-based hardware virtualization. The API 1000# we rely on exists since version 2.6.36 of the kernel, but somehow 1001# the KVM_API_VERSION does not reflect the change. We test for one of 1002# the types as a fall back. 1003have_kvm = conf.CheckHeader('linux/kvm.h', '<>') and \ 1004 conf.CheckTypeSize('struct kvm_xsave', '#include <linux/kvm.h>') != 0 1005if not have_kvm: 1006 print "Info: Compatible header file <linux/kvm.h> not found, " \ 1007 "disabling KVM support." 1008 1009# Check if the requested target ISA is compatible with the host 1010def is_isa_kvm_compatible(isa): 1011 isa_comp_table = { 1012 "arm" : ( "armv7l" ), 1013 "x86" : ( "x86_64" ), 1014 } 1015 try: 1016 import platform 1017 host_isa = platform.machine() 1018 except: 1019 print "Warning: Failed to determine host ISA." 1020 return False 1021 1022 return host_isa in isa_comp_table.get(isa, []) 1023 1024 1025# Check if the exclude_host attribute is available. We want this to 1026# get accurate instruction counts in KVM. 1027main['HAVE_PERF_ATTR_EXCLUDE_HOST'] = conf.CheckMember( 1028 'linux/perf_event.h', 'struct perf_event_attr', 'exclude_host') 1029 1030 1031###################################################################### 1032# 1033# Finish the configuration 1034# 1035main = conf.Finish() 1036 1037###################################################################### 1038# 1039# Collect all non-global variables 1040# 1041 1042# Define the universe of supported ISAs 1043all_isa_list = [ ] 1044Export('all_isa_list') 1045 1046class CpuModel(object): 1047 '''The CpuModel class encapsulates everything the ISA parser needs to 1048 know about a particular CPU model.''' 1049 1050 # Dict of available CPU model objects. Accessible as CpuModel.dict. 1051 dict = {} 1052 1053 # Constructor. Automatically adds models to CpuModel.dict. 1054 def __init__(self, name, default=False): 1055 self.name = name # name of model 1056 1057 # This cpu is enabled by default 1058 self.default = default 1059 1060 # Add self to dict 1061 if name in CpuModel.dict: 1062 raise AttributeError, "CpuModel '%s' already registered" % name 1063 CpuModel.dict[name] = self 1064 1065Export('CpuModel') 1066 1067# Sticky variables get saved in the variables file so they persist from 1068# one invocation to the next (unless overridden, in which case the new 1069# value becomes sticky). 1070sticky_vars = Variables(args=ARGUMENTS) 1071Export('sticky_vars') 1072 1073# Sticky variables that should be exported 1074export_vars = [] 1075Export('export_vars') 1076 1077# For Ruby 1078all_protocols = [] 1079Export('all_protocols') 1080protocol_dirs = [] 1081Export('protocol_dirs') 1082slicc_includes = [] 1083Export('slicc_includes') 1084 1085# Walk the tree and execute all SConsopts scripts that wil add to the 1086# above variables 1087if GetOption('verbose'): 1088 print "Reading SConsopts" 1089for bdir in [ base_dir ] + extras_dir_list: 1090 if not isdir(bdir): 1091 print "Error: directory '%s' does not exist" % bdir 1092 Exit(1) 1093 for root, dirs, files in os.walk(bdir): 1094 if 'SConsopts' in files: 1095 if GetOption('verbose'): 1096 print "Reading", joinpath(root, 'SConsopts') 1097 SConscript(joinpath(root, 'SConsopts')) 1098 1099all_isa_list.sort() 1100 1101sticky_vars.AddVariables( 1102 EnumVariable('TARGET_ISA', 'Target ISA', 'alpha', all_isa_list), 1103 ListVariable('CPU_MODELS', 'CPU models', 1104 sorted(n for n,m in CpuModel.dict.iteritems() if m.default), 1105 sorted(CpuModel.dict.keys())), 1106 BoolVariable('EFENCE', 'Link with Electric Fence malloc debugger', 1107 False), 1108 BoolVariable('SS_COMPATIBLE_FP', 1109 'Make floating-point results compatible with SimpleScalar', 1110 False), 1111 BoolVariable('USE_SSE2', 1112 'Compile for SSE2 (-msse2) to get IEEE FP on x86 hosts', 1113 False), 1114 BoolVariable('USE_POSIX_CLOCK', 'Use POSIX Clocks', have_posix_clock), 1115 BoolVariable('USE_FENV', 'Use <fenv.h> IEEE mode control', have_fenv), 1116 BoolVariable('CP_ANNOTATE', 'Enable critical path annotation capability', False), 1117 BoolVariable('USE_KVM', 'Enable hardware virtualized (KVM) CPU models', have_kvm), 1118 EnumVariable('PROTOCOL', 'Coherence protocol for Ruby', 'None', 1119 all_protocols), 1120 ) 1121 1122# These variables get exported to #defines in config/*.hh (see src/SConscript). 1123export_vars += ['USE_FENV', 'SS_COMPATIBLE_FP', 'TARGET_ISA', 'CP_ANNOTATE', 1124 'USE_POSIX_CLOCK', 'PROTOCOL', 'HAVE_PROTOBUF', 1125 'HAVE_PERF_ATTR_EXCLUDE_HOST'] 1126 1127################################################### 1128# 1129# Define a SCons builder for configuration flag headers. 1130# 1131################################################### 1132 1133# This function generates a config header file that #defines the 1134# variable symbol to the current variable setting (0 or 1). The source 1135# operands are the name of the variable and a Value node containing the 1136# value of the variable. 1137def build_config_file(target, source, env): 1138 (variable, value) = [s.get_contents() for s in source] 1139 f = file(str(target[0]), 'w') 1140 print >> f, '#define', variable, value 1141 f.close() 1142 return None 1143 1144# Combine the two functions into a scons Action object. 1145config_action = MakeAction(build_config_file, Transform("CONFIG H", 2)) 1146 1147# The emitter munges the source & target node lists to reflect what 1148# we're really doing. 1149def config_emitter(target, source, env): 1150 # extract variable name from Builder arg 1151 variable = str(target[0]) 1152 # True target is config header file 1153 target = joinpath('config', variable.lower() + '.hh') 1154 val = env[variable] 1155 if isinstance(val, bool): 1156 # Force value to 0/1 1157 val = int(val) 1158 elif isinstance(val, str): 1159 val = '"' + val + '"' 1160 1161 # Sources are variable name & value (packaged in SCons Value nodes) 1162 return ([target], [Value(variable), Value(val)]) 1163 1164config_builder = Builder(emitter = config_emitter, action = config_action) 1165 1166main.Append(BUILDERS = { 'ConfigFile' : config_builder }) 1167 1168# libelf build is shared across all configs in the build root. 1169main.SConscript('ext/libelf/SConscript', 1170 variant_dir = joinpath(build_root, 'libelf')) 1171 1172# gzstream build is shared across all configs in the build root. 1173main.SConscript('ext/gzstream/SConscript', 1174 variant_dir = joinpath(build_root, 'gzstream')) 1175 1176# libfdt build is shared across all configs in the build root. 1177main.SConscript('ext/libfdt/SConscript', 1178 variant_dir = joinpath(build_root, 'libfdt')) 1179 1180# fputils build is shared across all configs in the build root. 1181main.SConscript('ext/fputils/SConscript', 1182 variant_dir = joinpath(build_root, 'fputils')) 1183 1184# DRAMSim2 build is shared across all configs in the build root. 1185main.SConscript('ext/dramsim2/SConscript', 1186 variant_dir = joinpath(build_root, 'dramsim2')) 1187 1188# DRAMPower build is shared across all configs in the build root. 1189main.SConscript('ext/drampower/SConscript', 1190 variant_dir = joinpath(build_root, 'drampower')) 1191 1192################################################### 1193# 1194# This function is used to set up a directory with switching headers 1195# 1196################################################### 1197 1198main['ALL_ISA_LIST'] = all_isa_list 1199all_isa_deps = {} 1200def make_switching_dir(dname, switch_headers, env): 1201 # Generate the header. target[0] is the full path of the output 1202 # header to generate. 'source' is a dummy variable, since we get the 1203 # list of ISAs from env['ALL_ISA_LIST']. 1204 def gen_switch_hdr(target, source, env): 1205 fname = str(target[0]) 1206 isa = env['TARGET_ISA'].lower() 1207 try: 1208 f = open(fname, 'w') 1209 print >>f, '#include "%s/%s/%s"' % (dname, isa, basename(fname)) 1210 f.close() 1211 except IOError: 1212 print "Failed to create %s" % fname 1213 raise 1214 1215 # Build SCons Action object. 'varlist' specifies env vars that this 1216 # action depends on; when env['ALL_ISA_LIST'] changes these actions 1217 # should get re-executed. 1218 switch_hdr_action = MakeAction(gen_switch_hdr, 1219 Transform("GENERATE"), varlist=['ALL_ISA_LIST']) 1220 1221 # Instantiate actions for each header 1222 for hdr in switch_headers: 1223 env.Command(hdr, [], switch_hdr_action) 1224 1225 isa_target = Dir('.').up().name.lower().replace('_', '-') 1226 env['PHONY_BASE'] = '#'+isa_target 1227 all_isa_deps[isa_target] = None 1228 1229Export('make_switching_dir') 1230 1231# all-isas -> all-deps -> all-environs -> all_targets 1232main.Alias('#all-isas', []) 1233main.Alias('#all-deps', '#all-isas') 1234 1235# Dummy target to ensure all environments are created before telling 1236# SCons what to actually make (the command line arguments). We attach 1237# them to the dependence graph after the environments are complete. 1238ORIG_BUILD_TARGETS = list(BUILD_TARGETS) # force a copy; gets closure to work. 1239def environsComplete(target, source, env): 1240 for t in ORIG_BUILD_TARGETS: 1241 main.Depends('#all-targets', t) 1242 1243# Each build/* switching_dir attaches its *-environs target to #all-environs. 1244main.Append(BUILDERS = {'CompleteEnvirons' : 1245 Builder(action=MakeAction(environsComplete, None))}) 1246main.CompleteEnvirons('#all-environs', []) 1247 1248def doNothing(**ignored): pass 1249main.Append(BUILDERS = {'Dummy': Builder(action=MakeAction(doNothing, None))}) 1250 1251# The final target to which all the original targets ultimately get attached. 1252main.Dummy('#all-targets', '#all-environs') 1253BUILD_TARGETS[:] = ['#all-targets'] 1254 1255################################################### 1256# 1257# Define build environments for selected configurations. 1258# 1259################################################### 1260 1261for variant_path in variant_paths: 1262 if not GetOption('silent'): 1263 print "Building in", variant_path 1264 1265 # Make a copy of the build-root environment to use for this config. 1266 env = main.Clone() 1267 env['BUILDDIR'] = variant_path 1268 1269 # variant_dir is the tail component of build path, and is used to 1270 # determine the build parameters (e.g., 'ALPHA_SE') 1271 (build_root, variant_dir) = splitpath(variant_path) 1272 1273 # Set env variables according to the build directory config. 1274 sticky_vars.files = [] 1275 # Variables for $BUILD_ROOT/$VARIANT_DIR are stored in 1276 # $BUILD_ROOT/variables/$VARIANT_DIR so you can nuke 1277 # $BUILD_ROOT/$VARIANT_DIR without losing your variables settings. 1278 current_vars_file = joinpath(build_root, 'variables', variant_dir) 1279 if isfile(current_vars_file): 1280 sticky_vars.files.append(current_vars_file) 1281 if not GetOption('silent'): 1282 print "Using saved variables file %s" % current_vars_file 1283 else: 1284 # Build dir-specific variables file doesn't exist. 1285 1286 # Make sure the directory is there so we can create it later 1287 opt_dir = dirname(current_vars_file) 1288 if not isdir(opt_dir): 1289 mkdir(opt_dir) 1290 1291 # Get default build variables from source tree. Variables are 1292 # normally determined by name of $VARIANT_DIR, but can be 1293 # overridden by '--default=' arg on command line. 1294 default = GetOption('default') 1295 opts_dir = joinpath(main.root.abspath, 'build_opts') 1296 if default: 1297 default_vars_files = [joinpath(build_root, 'variables', default), 1298 joinpath(opts_dir, default)] 1299 else: 1300 default_vars_files = [joinpath(opts_dir, variant_dir)] 1301 existing_files = filter(isfile, default_vars_files) 1302 if existing_files: 1303 default_vars_file = existing_files[0] 1304 sticky_vars.files.append(default_vars_file) 1305 print "Variables file %s not found,\n using defaults in %s" \ 1306 % (current_vars_file, default_vars_file) 1307 else: 1308 print "Error: cannot find variables file %s or " \ 1309 "default file(s) %s" \ 1310 % (current_vars_file, ' or '.join(default_vars_files)) 1311 Exit(1) 1312 1313 # Apply current variable settings to env 1314 sticky_vars.Update(env) 1315 1316 help_texts["local_vars"] += \ 1317 "Build variables for %s:\n" % variant_dir \ 1318 + sticky_vars.GenerateHelpText(env) 1319 1320 # Process variable settings. 1321 1322 if not have_fenv and env['USE_FENV']: 1323 print "Warning: <fenv.h> not available; " \ 1324 "forcing USE_FENV to False in", variant_dir + "." 1325 env['USE_FENV'] = False 1326 1327 if not env['USE_FENV']: 1328 print "Warning: No IEEE FP rounding mode control in", variant_dir + "." 1329 print " FP results may deviate slightly from other platforms." 1330 1331 if env['EFENCE']: 1332 env.Append(LIBS=['efence']) 1333 1334 if env['USE_KVM']: 1335 if not have_kvm: 1336 print "Warning: Can not enable KVM, host seems to lack KVM support" 1337 env['USE_KVM'] = False 1338 elif not have_posix_timers: 1339 print "Warning: Can not enable KVM, host seems to lack support " \ 1340 "for POSIX timers" 1341 env['USE_KVM'] = False 1342 elif not is_isa_kvm_compatible(env['TARGET_ISA']): 1343 print "Info: KVM support disabled due to unsupported host and " \ 1344 "target ISA combination" 1345 env['USE_KVM'] = False 1346 1347 # Warn about missing optional functionality 1348 if env['USE_KVM']: 1349 if not main['HAVE_PERF_ATTR_EXCLUDE_HOST']: 1350 print "Warning: perf_event headers lack support for the " \ 1351 "exclude_host attribute. KVM instruction counts will " \ 1352 "be inaccurate." 1353 1354 # Save sticky variable settings back to current variables file 1355 sticky_vars.Save(current_vars_file, env) 1356 1357 if env['USE_SSE2']: 1358 env.Append(CCFLAGS=['-msse2']) 1359 1360 # The src/SConscript file sets up the build rules in 'env' according 1361 # to the configured variables. It returns a list of environments, 1362 # one for each variant build (debug, opt, etc.) 1363 SConscript('src/SConscript', variant_dir = variant_path, exports = 'env') 1364 1365def pairwise(iterable): 1366 "s -> (s0,s1), (s1,s2), (s2, s3), ..." 1367 a, b = itertools.tee(iterable) 1368 b.next() 1369 return itertools.izip(a, b) 1370 1371# Create false dependencies so SCons will parse ISAs, establish 1372# dependencies, and setup the build Environments serially. Either 1373# SCons (likely) and/or our SConscripts (possibly) cannot cope with -j 1374# greater than 1. It appears to be standard race condition stuff; it 1375# doesn't always fail, but usually, and the behaviors are different. 1376# Every time I tried to remove this, builds would fail in some 1377# creative new way. So, don't do that. You'll want to, though, because 1378# tests/SConscript takes a long time to make its Environments. 1379for t1, t2 in pairwise(sorted(all_isa_deps.iterkeys())): 1380 main.Depends('#%s-deps' % t2, '#%s-deps' % t1) 1381 main.Depends('#%s-environs' % t2, '#%s-environs' % t1) 1382 1383# base help text 1384Help(''' 1385Usage: scons [scons options] [build variables] [target(s)] 1386 1387Extra scons options: 1388%(options)s 1389 1390Global build variables: 1391%(global_vars)s 1392 1393%(local_vars)s 1394''' % help_texts) 1395