X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;ds=sidebyside;f=SConstruct;h=53b8c9deab1cd1df21786e1b45b74d43fde4fdbd;hb=eba0a509d80182c479e41d28bf71d3061f18590b;hp=ff6de944c49c3716a1d2a1f322a774ea50c2471b;hpb=8eb84518f15fcef59da90e7ec72e2bc88fb5b59d;p=gem5.git diff --git a/SConstruct b/SConstruct index ff6de944c..53b8c9dea 100755 --- a/SConstruct +++ b/SConstruct @@ -1,6 +1,6 @@ # -*- mode:python -*- -# Copyright (c) 2013, 2015, 2016 ARM Limited +# Copyright (c) 2013, 2015-2017 ARM Limited # All rights reserved. # # The license below extends only to copyright in the software and shall @@ -78,35 +78,7 @@ # ################################################### -# Check for recent-enough Python and SCons versions. -try: - # Really old versions of scons only take two options for the - # function, so check once without the revision and once with the - # revision, the first instance will fail for stuff other than - # 0.98, and the second will fail for 0.98.0 - EnsureSConsVersion(0, 98) - EnsureSConsVersion(0, 98, 1) -except SystemExit, e: - print """ -For more details, see: - http://gem5.org/Dependencies -""" - raise - -# We ensure the python version early because because python-config -# requires python 2.5 -try: - EnsurePythonVersion(2, 5) -except SystemExit, e: - print """ -You can use a non-default installation of the Python interpreter by -rearranging your PATH so that scons finds the non-default 'python' and -'python-config' first. - -For more details, see: - http://gem5.org/wiki/index.php/Using_a_non-default_Python_installation -""" - raise +from __future__ import print_function # Global Python includes import itertools @@ -120,20 +92,14 @@ from os import mkdir, environ from os.path import abspath, basename, dirname, expanduser, normpath from os.path import exists, isdir, isfile from os.path import join as joinpath, split as splitpath +from re import match # SCons includes import SCons import SCons.Node - -extra_python_paths = [ - Dir('src/python').srcnode().abspath, # gem5 includes - Dir('ext/ply').srcnode().abspath, # ply is used by several files - ] - -sys.path[1:1] = extra_python_paths +import SCons.Node.FS from m5.util import compareVersions, readCommand -from m5.util.terminal import get_termcap help_texts = { "options" : "", @@ -181,8 +147,13 @@ AddLocalOption('--default', dest='default', type='string', action='store', help='Override which build_opts file to use for defaults') AddLocalOption('--ignore-style', dest='ignore_style', action='store_true', help='Disable style checking hooks') +AddLocalOption('--gold-linker', dest='gold_linker', action='store_true', + help='Use the gold linker') AddLocalOption('--no-lto', dest='no_lto', action='store_true', help='Disable Link-Time Optimization for fast') +AddLocalOption('--force-lto', dest='force_lto', action='store_true', + help='Use Link-Time Optimization instead of partial linking' + + ' when the compiler doesn\'t support using them together.') AddLocalOption('--update-ref', dest='update_ref', action='store_true', help='Update test reference outputs') AddLocalOption('--verbose', dest='verbose', action='store_true', @@ -198,7 +169,9 @@ AddLocalOption('--with-ubsan', dest='with_ubsan', action='store_true', AddLocalOption('--with-asan', dest='with_asan', action='store_true', help='Build with Address Sanitizer if available') -termcap = get_termcap(GetOption('use_colors')) +if GetOption('no_lto') and GetOption('force_lto'): + print('--no-lto and --force-lto are mutually exclusive') + Exit(1) ######################################################################## # @@ -206,234 +179,19 @@ termcap = get_termcap(GetOption('use_colors')) # ######################################################################## -# export TERM so that clang reports errors in color -use_vars = set([ 'AS', 'AR', 'CC', 'CXX', 'HOME', 'LD_LIBRARY_PATH', - 'LIBRARY_PATH', 'PATH', 'PKG_CONFIG_PATH', 'PROTOC', - 'PYTHONPATH', 'RANLIB', 'TERM' ]) - -use_prefixes = [ - "ASAN_", # address sanitizer symbolizer path and settings - "CCACHE_", # ccache (caching compiler wrapper) configuration - "CCC_", # clang static analyzer configuration - "DISTCC_", # distcc (distributed compiler wrapper) configuration - "INCLUDE_SERVER_", # distcc pump server settings - "M5", # M5 configuration (e.g., path to kernels) - ] - -use_env = {} -for key,val in sorted(os.environ.iteritems()): - if key in use_vars or \ - any([key.startswith(prefix) for prefix in use_prefixes]): - use_env[key] = val - -# Tell scons to avoid implicit command dependencies to avoid issues -# with the param wrappes being compiled twice (see -# http://scons.tigris.org/issues/show_bug.cgi?id=2811) -main = Environment(ENV=use_env, IMPLICIT_COMMAND_DEPENDENCIES=0) -main.Decider('MD5-timestamp') -main.root = Dir(".") # The current directory (where this file lives). -main.srcdir = Dir("src") # The source directory +main = Environment() + +from gem5_scons import Transform +from gem5_scons.util import get_termcap +termcap = get_termcap() main_dict_keys = main.Dictionary().keys() # Check that we have a C/C++ compiler if not ('CC' in main_dict_keys and 'CXX' in main_dict_keys): - print "No C++ compiler installed (package g++ on Ubuntu and RedHat)" + print("No C++ compiler installed (package g++ on Ubuntu and RedHat)") Exit(1) -# add useful python code PYTHONPATH so it can be used by subprocesses -# as well -main.AppendENVPath('PYTHONPATH', extra_python_paths) - -######################################################################## -# -# Mercurial Stuff. -# -# If the gem5 directory is a mercurial repository, we should do some -# extra things. -# -######################################################################## - -hgdir = main.root.Dir(".hg") - - -style_message = """ -You're missing the gem5 style hook, which automatically checks your code -against the gem5 style rules on %s. -This script will now install the hook in your %s. -Press enter to continue, or ctrl-c to abort: """ - -mercurial_style_message = """ -You're missing the gem5 style hook, which automatically checks your code -against the gem5 style rules on hg commit and qrefresh commands. -This script will now install the hook in your .hg/hgrc file. -Press enter to continue, or ctrl-c to abort: """ - -git_style_message = """ -You're missing the gem5 style or commit message hook. These hooks help -to ensure that your code follows gem5's style rules on git commit. -This script will now install the hook in your .git/hooks/ directory. -Press enter to continue, or ctrl-c to abort: """ - -mercurial_style_upgrade_message = """ -Your Mercurial style hooks are not up-to-date. This script will now -try to automatically update them. A backup of your hgrc will be saved -in .hg/hgrc.old. -Press enter to continue, or ctrl-c to abort: """ - -mercurial_style_hook = """ -# The following lines were automatically added by gem5/SConstruct -# to provide the gem5 style-checking hooks -[extensions] -hgstyle = %s/util/hgstyle.py - -[hooks] -pretxncommit.style = python:hgstyle.check_style -pre-qrefresh.style = python:hgstyle.check_style -# End of SConstruct additions - -""" % (main.root.abspath) - -mercurial_lib_not_found = """ -Mercurial libraries cannot be found, ignoring style hook. If -you are a gem5 developer, please fix this and run the style -hook. It is important. -""" - -# Check for style hook and prompt for installation if it's not there. -# Skip this if --ignore-style was specified, there's no interactive -# terminal to prompt, or no recognized revision control system can be -# found. -ignore_style = GetOption('ignore_style') or not sys.stdin.isatty() - -# Try wire up Mercurial to the style hooks -if not ignore_style and hgdir.exists(): - style_hook = True - style_hooks = tuple() - hgrc = hgdir.File('hgrc') - hgrc_old = hgdir.File('hgrc.old') - try: - from mercurial import ui - ui = ui.ui() - ui.readconfig(hgrc.abspath) - style_hooks = (ui.config('hooks', 'pretxncommit.style', None), - ui.config('hooks', 'pre-qrefresh.style', None)) - style_hook = all(style_hooks) - style_extension = ui.config('extensions', 'style', None) - except ImportError: - print mercurial_lib_not_found - - if "python:style.check_style" in style_hooks: - # Try to upgrade the style hooks - print mercurial_style_upgrade_message - # continue unless user does ctrl-c/ctrl-d etc. - try: - raw_input() - except: - print "Input exception, exiting scons.\n" - sys.exit(1) - shutil.copyfile(hgrc.abspath, hgrc_old.abspath) - re_style_hook = re.compile(r"^([^=#]+)\.style\s*=\s*([^#\s]+).*") - re_style_extension = re.compile("style\s*=\s*([^#\s]+).*") - old, new = open(hgrc_old.abspath, 'r'), open(hgrc.abspath, 'w') - for l in old: - m_hook = re_style_hook.match(l) - m_ext = re_style_extension.match(l) - if m_hook: - hook, check = m_hook.groups() - if check != "python:style.check_style": - print "Warning: %s.style is using a non-default " \ - "checker: %s" % (hook, check) - if hook not in ("pretxncommit", "pre-qrefresh"): - print "Warning: Updating unknown style hook: %s" % hook - - l = "%s.style = python:hgstyle.check_style\n" % hook - elif m_ext and m_ext.group(1) == style_extension: - l = "hgstyle = %s/util/hgstyle.py\n" % main.root.abspath - - new.write(l) - elif not style_hook: - print mercurial_style_message, - # continue unless user does ctrl-c/ctrl-d etc. - try: - raw_input() - except: - print "Input exception, exiting scons.\n" - sys.exit(1) - hgrc_path = '%s/.hg/hgrc' % main.root.abspath - print "Adding style hook to", hgrc_path, "\n" - try: - with open(hgrc_path, 'a') as f: - f.write(mercurial_style_hook) - except: - print "Error updating", hgrc_path - sys.exit(1) - -def install_git_style_hooks(): - try: - gitdir = Dir(readCommand( - ["git", "rev-parse", "--git-dir"]).strip("\n")) - except Exception, e: - print "Warning: Failed to find git repo directory: %s" % e - return - - git_hooks = gitdir.Dir("hooks") - def hook_exists(hook_name): - hook = git_hooks.File(hook_name) - return hook.exists() - - def hook_install(hook_name, script): - hook = git_hooks.File(hook_name) - if hook.exists(): - print "Warning: Can't install %s, hook already exists." % hook_name - return - - if hook.islink(): - print "Warning: Removing broken symlink for hook %s." % hook_name - os.unlink(hook.get_abspath()) - - if not git_hooks.exists(): - mkdir(git_hooks.get_abspath()) - git_hooks.clear() - - abs_symlink_hooks = git_hooks.islink() and \ - os.path.isabs(os.readlink(git_hooks.get_abspath())) - - # Use a relative symlink if the hooks live in the source directory, - # and the hooks directory is not a symlink to an absolute path. - if hook.is_under(main.root) and not abs_symlink_hooks: - script_path = os.path.relpath( - os.path.realpath(script.get_abspath()), - os.path.realpath(hook.Dir(".").get_abspath())) - else: - script_path = script.get_abspath() - - try: - os.symlink(script_path, hook.get_abspath()) - except: - print "Error updating git %s hook" % hook_name - raise - - if hook_exists("pre-commit") and hook_exists("commit-msg"): - return - - print git_style_message, - try: - raw_input() - except: - print "Input exception, exiting scons.\n" - sys.exit(1) - - git_style_script = File("util/git-pre-commit.py") - git_msg_script = File("ext/git-commit-msg") - - hook_install("pre-commit", git_style_script) - hook_install("commit-msg", git_msg_script) - -# Try to wire up git to the style hooks -if not ignore_style and main.root.Entry(".git").exists(): - install_git_style_hooks() - ################################################### # # Figure out which configurations to set up based on the path(s) of @@ -458,6 +216,19 @@ def makePathListAbsolute(path_list, root=GetLaunchDir()): return [abspath(joinpath(root, expanduser(str(p)))) for p in path_list] +def find_first_prog(prog_names): + """Find the absolute path to the first existing binary in prog_names""" + + if not isinstance(prog_names, (list, tuple)): + prog_names = [ prog_names ] + + for p in prog_names: + p = main.WhereIs(p) + if p is not None: + return p + + return None + # Each target must have 'build' in the interior of the path; the # directory below this will determine the build parameters. For # example, for target 'foo/bar/build/ALPHA_SE/arch/alpha/blah.do' we @@ -478,15 +249,15 @@ for t in BUILD_TARGETS: try: build_top = rfind(path_dirs, 'build', -2) except: - print "Error: no non-leaf 'build' dir found on target path", t + print("Error: no non-leaf 'build' dir found on target path", t) Exit(1) this_build_root = joinpath('/',*path_dirs[:build_top+1]) if not build_root: build_root = this_build_root else: if this_build_root != build_root: - print "Error: build targets not under same build root\n"\ - " %s\n %s" % (build_root, this_build_root) + print("Error: build targets not under same build root\n" + " %s\n %s" % (build_root, this_build_root)) Exit(1) variant_path = joinpath('/',*path_dirs[:build_top+2]) if variant_path not in variant_paths: @@ -519,6 +290,8 @@ global_vars = Variables(global_vars_file, args=ARGUMENTS) global_vars.AddVariables( ('CC', 'C compiler', environ.get('CC', main['CC'])), ('CXX', 'C++ compiler', environ.get('CXX', main['CXX'])), + ('PYTHON_CONFIG', 'Python config binary to use', + [ 'python2.7-config', 'python-config' ]), ('PROTOC', 'protoc tool', environ.get('PROTOC', 'protoc')), ('BATCH', 'Use batch pool for build and tests', False), ('BATCH_CMD', 'Batch pool submission command name', 'qdo'), @@ -547,89 +320,8 @@ Export('extras_dir_list') # the ext directory should be on the #includes path main.Append(CPPPATH=[Dir('ext')]) -def strip_build_path(path, env): - path = str(path) - variant_base = env['BUILDROOT'] + os.path.sep - if path.startswith(variant_base): - path = path[len(variant_base):] - elif path.startswith('build/'): - path = path[6:] - return path - -# Generate a string of the form: -# common/path/prefix/src1, src2 -> tgt1, tgt2 -# to print while building. -class Transform(object): - # all specific color settings should be here and nowhere else - tool_color = termcap.Normal - pfx_color = termcap.Yellow - srcs_color = termcap.Yellow + termcap.Bold - arrow_color = termcap.Blue + termcap.Bold - tgts_color = termcap.Yellow + termcap.Bold - - def __init__(self, tool, max_sources=99): - self.format = self.tool_color + (" [%8s] " % tool) \ - + self.pfx_color + "%s" \ - + self.srcs_color + "%s" \ - + self.arrow_color + " -> " \ - + self.tgts_color + "%s" \ - + termcap.Normal - self.max_sources = max_sources - - def __call__(self, target, source, env, for_signature=None): - # truncate source list according to max_sources param - source = source[0:self.max_sources] - def strip(f): - return strip_build_path(str(f), env) - if len(source) > 0: - srcs = map(strip, source) - else: - srcs = [''] - tgts = map(strip, target) - # surprisingly, os.path.commonprefix is a dumb char-by-char string - # operation that has nothing to do with paths. - com_pfx = os.path.commonprefix(srcs + tgts) - com_pfx_len = len(com_pfx) - if com_pfx: - # do some cleanup and sanity checking on common prefix - if com_pfx[-1] == ".": - # prefix matches all but file extension: ok - # back up one to change 'foo.cc -> o' to 'foo.cc -> .o' - com_pfx = com_pfx[0:-1] - elif com_pfx[-1] == "/": - # common prefix is directory path: OK - pass - else: - src0_len = len(srcs[0]) - tgt0_len = len(tgts[0]) - if src0_len == com_pfx_len: - # source is a substring of target, OK - pass - elif tgt0_len == com_pfx_len: - # target is a substring of source, need to back up to - # avoid empty string on RHS of arrow - sep_idx = com_pfx.rfind(".") - if sep_idx != -1: - com_pfx = com_pfx[0:sep_idx] - else: - com_pfx = '' - elif src0_len > com_pfx_len and srcs[0][com_pfx_len] == ".": - # still splitting at file extension: ok - pass - else: - # probably a fluke; ignore it - com_pfx = '' - # recalculate length in case com_pfx was modified - com_pfx_len = len(com_pfx) - def fmt(files): - f = map(lambda s: s[com_pfx_len:], files) - return ', '.join(f) - return self.format % (com_pfx, fmt(srcs), fmt(tgts)) - -Export('Transform') - -# enable the regression script to use the termcap -main['TERMCAP'] = termcap +# Add shared top-level headers +main.Prepend(CPPPATH=Dir('include')) if GetOption('verbose'): def MakeAction(action, string, *args, **kwargs): @@ -664,7 +356,7 @@ CXX_V = readCommand([main['CXX'],'-V'], exception=False) main['GCC'] = CXX_version and CXX_version.find('g++') >= 0 main['CLANG'] = CXX_version and CXX_version.find('clang') >= 0 if main['GCC'] + main['CLANG'] > 1: - print 'Error: How can we have two at the same time?' + print('Error: How can we have two at the same time?') Exit(1) # Set up default C++ compiler flags @@ -684,27 +376,36 @@ if main['GCC'] or main['CLANG']: main['FILTER_PSHLINKFLAGS'] = lambda x: str(x).replace(' -shared', '') main['PSHLINKFLAGS'] = main.subst('${FILTER_PSHLINKFLAGS(SHLINKFLAGS)}') + if GetOption('gold_linker'): + main.Append(LINKFLAGS='-fuse-ld=gold') main['PLINKFLAGS'] = main.subst('${LINKFLAGS}') - shared_partial_flags = ['-Wl,--relocatable', '-nostdlib'] + shared_partial_flags = ['-r', '-nostdlib'] main.Append(PSHLINKFLAGS=shared_partial_flags) main.Append(PLINKFLAGS=shared_partial_flags) + + # Treat warnings as errors but white list some warnings that we + # want to allow (e.g., deprecation warnings). + main.Append(CCFLAGS=['-Werror', + '-Wno-error=deprecated-declarations', + '-Wno-error=deprecated', + ]) else: - print termcap.Yellow + termcap.Bold + 'Error' + termcap.Normal, - print "Don't know what compiler options to use for your compiler." - print termcap.Yellow + ' compiler:' + termcap.Normal, main['CXX'] - print termcap.Yellow + ' version:' + termcap.Normal, + print(termcap.Yellow + termcap.Bold + 'Error' + termcap.Normal, end=' ') + print("Don't know what compiler options to use for your compiler.") + print(termcap.Yellow + ' compiler:' + termcap.Normal, main['CXX']) + print(termcap.Yellow + ' version:' + termcap.Normal, end = ' ') if not CXX_version: - print termcap.Yellow + termcap.Bold + "COMMAND NOT FOUND!" +\ - termcap.Normal + print(termcap.Yellow + termcap.Bold + "COMMAND NOT FOUND!" + + termcap.Normal) else: - print CXX_version.replace('\n', '') - print " If you're trying to use a compiler other than GCC" - print " or clang, there appears to be something wrong with your" - print " environment." - print " " - print " If you are trying to use a compiler other than those listed" - print " above you will need to ease fix SConstruct and " - print " src/SConscript to support that compiler." + print(CXX_version.replace('\n', '')) + print(" If you're trying to use a compiler other than GCC") + print(" or clang, there appears to be something wrong with your") + print(" environment.") + print(" ") + print(" If you are trying to use a compiler other than those listed") + print(" above you will need to ease fix SConstruct and ") + print(" src/SConscript to support that compiler.") Exit(1) if main['GCC']: @@ -713,46 +414,58 @@ if main['GCC']: # http://gcc.gnu.org/projects/cxx0x.html for details. gcc_version = readCommand([main['CXX'], '-dumpversion'], exception=False) if compareVersions(gcc_version, "4.8") < 0: - print 'Error: gcc version 4.8 or newer required.' - print ' Installed version:', gcc_version + print('Error: gcc version 4.8 or newer required.') + print(' Installed version: ', gcc_version) Exit(1) main['GCC_VERSION'] = gcc_version - # gcc from version 4.8 and above generates "rep; ret" instructions - # to avoid performance penalties on certain AMD chips. Older - # assemblers detect this as an error, "Error: expecting string - # instruction after `rep'" - as_version_raw = readCommand([main['AS'], '-v', '/dev/null', - '-o', '/dev/null'], - exception=False).split() - - # version strings may contain extra distro-specific - # qualifiers, so play it safe and keep only what comes before - # the first hyphen - as_version = as_version_raw[-1].split('-')[0] if as_version_raw else None - - if not as_version or compareVersions(as_version, "2.23") < 0: - print termcap.Yellow + termcap.Bold + \ - 'Warning: This combination of gcc and binutils have' + \ - ' known incompatibilities.\n' + \ - ' If you encounter build problems, please update ' + \ - 'binutils to 2.23.' + \ - termcap.Normal + if compareVersions(gcc_version, '4.9') >= 0: + # Incremental linking with LTO is currently broken in gcc versions + # 4.9 and above. A version where everything works completely hasn't + # yet been identified. + # + # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67548 + main['BROKEN_INCREMENTAL_LTO'] = True + if compareVersions(gcc_version, '6.0') >= 0: + # gcc versions 6.0 and greater accept an -flinker-output flag which + # selects what type of output the linker should generate. This is + # necessary for incremental lto to work, but is also broken in + # current versions of gcc. It may not be necessary in future + # versions. We add it here since it might be, and as a reminder that + # it exists. It's excluded if lto is being forced. + # + # https://gcc.gnu.org/gcc-6/changes.html + # https://gcc.gnu.org/ml/gcc-patches/2015-11/msg03161.html + # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69866 + if not GetOption('force_lto'): + main.Append(PSHLINKFLAGS='-flinker-output=rel') + main.Append(PLINKFLAGS='-flinker-output=rel') # Make sure we warn if the user has requested to compile with the # Undefined Benahvior Sanitizer and this version of gcc does not # support it. if GetOption('with_ubsan') and \ compareVersions(gcc_version, '4.9') < 0: - print termcap.Yellow + termcap.Bold + \ - 'Warning: UBSan is only supported using gcc 4.9 and later.' + \ - termcap.Normal + print(termcap.Yellow + termcap.Bold + + 'Warning: UBSan is only supported using gcc 4.9 and later.' + + termcap.Normal) + + disable_lto = GetOption('no_lto') + if not disable_lto and main.get('BROKEN_INCREMENTAL_LTO', False) and \ + not GetOption('force_lto'): + print(termcap.Yellow + termcap.Bold + + 'Warning: Your compiler doesn\'t support incremental linking' + + ' and lto at the same time, so lto is being disabled. To force' + + ' lto on anyway, use the --force-lto option. That will disable' + + ' partial linking.' + + termcap.Normal) + disable_lto = True # Add the appropriate Link-Time Optimization (LTO) flags # unless LTO is explicitly turned off. Note that these flags # are only used by the fast target. - if not GetOption('no_lto'): + if not disable_lto: # Pass the LTO flag when compiling to produce GIMPLE # output, we merely create the flags here and only append # them later @@ -765,9 +478,24 @@ if main['GCC']: main.Append(TCMALLOC_CCFLAGS=['-fno-builtin-malloc', '-fno-builtin-calloc', '-fno-builtin-realloc', '-fno-builtin-free']) - # add option to check for undeclared overrides - if compareVersions(gcc_version, "5.0") > 0: - main.Append(CCFLAGS=['-Wno-error=suggest-override']) + # The address sanitizer is available for gcc >= 4.8 + if GetOption('with_asan'): + if GetOption('with_ubsan') and \ + compareVersions(main['GCC_VERSION'], '4.9') >= 0: + main.Append(CCFLAGS=['-fsanitize=address,undefined', + '-fno-omit-frame-pointer'], + LINKFLAGS='-fsanitize=address,undefined') + else: + main.Append(CCFLAGS=['-fsanitize=address', + '-fno-omit-frame-pointer'], + LINKFLAGS='-fsanitize=address') + # Only gcc >= 4.9 supports UBSan, so check both the version + # and the command-line option before adding the compiler and + # linker flags. + elif GetOption('with_ubsan') and \ + compareVersions(main['GCC_VERSION'], '4.9') >= 0: + main.Append(CCFLAGS='-fsanitize=undefined') + main.Append(LINKFLAGS='-fsanitize=undefined') elif main['CLANG']: # Check for a supported version of clang, >= 3.1 is needed to @@ -778,11 +506,11 @@ elif main['CLANG']: if (clang_version_match): clang_version = clang_version_match.groups()[0] if compareVersions(clang_version, "3.1") < 0: - print 'Error: clang version 3.1 or newer required.' - print ' Installed version:', clang_version + print('Error: clang version 3.1 or newer required.') + print(' Installed version:', clang_version) Exit(1) else: - print 'Error: Unable to determine clang version.' + print('Error: Unable to determine clang version.') Exit(1) # clang has a few additional warnings that we disable, extraneous @@ -809,23 +537,39 @@ elif main['CLANG']: if sys.platform.startswith('freebsd'): main.Append(LIBS=['thr']) + # We require clang >= 3.1, so there is no need to check any + # versions here. + if GetOption('with_ubsan'): + if GetOption('with_asan'): + main.Append(CCFLAGS=['-fsanitize=address,undefined', + '-fno-omit-frame-pointer'], + LINKFLAGS='-fsanitize=address,undefined') + else: + main.Append(CCFLAGS='-fsanitize=undefined', + LINKFLAGS='-fsanitize=undefined') + + elif GetOption('with_asan'): + main.Append(CCFLAGS=['-fsanitize=address', + '-fno-omit-frame-pointer'], + LINKFLAGS='-fsanitize=address') + else: - print termcap.Yellow + termcap.Bold + 'Error' + termcap.Normal, - print "Don't know what compiler options to use for your compiler." - print termcap.Yellow + ' compiler:' + termcap.Normal, main['CXX'] - print termcap.Yellow + ' version:' + termcap.Normal, + print(termcap.Yellow + termcap.Bold + 'Error' + termcap.Normal, end=' ') + print("Don't know what compiler options to use for your compiler.") + print(termcap.Yellow + ' compiler:' + termcap.Normal, main['CXX']) + print(termcap.Yellow + ' version:' + termcap.Normal, end=' ') if not CXX_version: - print termcap.Yellow + termcap.Bold + "COMMAND NOT FOUND!" +\ - termcap.Normal + print(termcap.Yellow + termcap.Bold + "COMMAND NOT FOUND!" + + termcap.Normal) else: - print CXX_version.replace('\n', '') - print " If you're trying to use a compiler other than GCC" - print " or clang, there appears to be something wrong with your" - print " environment." - print " " - print " If you are trying to use a compiler other than those listed" - print " above you will need to ease fix SConstruct and " - print " src/SConscript to support that compiler." + print(CXX_version.replace('\n', '')) + print(" If you're trying to use a compiler other than GCC") + print(" or clang, there appears to be something wrong with your") + print(" environment.") + print(" ") + print(" If you are trying to use a compiler other than those listed") + print(" above you will need to ease fix SConstruct and ") + print(" src/SConscript to support that compiler.") Exit(1) # Set up common yacc/bison flags (needed for Ruby) @@ -851,21 +595,21 @@ protoc_version = readCommand([main['PROTOC'], '--version'], # First two words should be "libprotoc x.y.z" if len(protoc_version) < 2 or protoc_version[0] != 'libprotoc': - print termcap.Yellow + termcap.Bold + \ - 'Warning: Protocol buffer compiler (protoc) not found.\n' + \ - ' Please install protobuf-compiler for tracing support.' + \ - termcap.Normal + print(termcap.Yellow + termcap.Bold + + 'Warning: Protocol buffer compiler (protoc) not found.\n' + + ' Please install protobuf-compiler for tracing support.' + + termcap.Normal) main['PROTOC'] = False else: # Based on the availability of the compress stream wrappers, # require 2.1.0 min_protoc_version = '2.1.0' if compareVersions(protoc_version[1], min_protoc_version) < 0: - print termcap.Yellow + termcap.Bold + \ - 'Warning: protoc version', min_protoc_version, \ - 'or newer required.\n' + \ - ' Installed version:', protoc_version[1], \ - termcap.Normal + print(termcap.Yellow + termcap.Bold + + 'Warning: protoc version', min_protoc_version, + 'or newer required.\n' + + ' Installed version:', protoc_version[1], + termcap.Normal) main['PROTOC'] = False else: # Attempt to determine the appropriate include path and @@ -880,9 +624,9 @@ else: # using pkg-config main.ParseConfig('pkg-config --cflags --libs-only-L protobuf') except: - print termcap.Yellow + termcap.Bold + \ - 'Warning: pkg-config could not get protobuf flags.' + \ - termcap.Normal + print(termcap.Yellow + termcap.Bold + + 'Warning: pkg-config could not get protobuf flags.' + + termcap.Normal) # Check for 'timeout' from GNU coreutils. If present, regressions will @@ -962,7 +706,7 @@ if not conf: # Cache build files in the supplied directory. if main['M5_BUILD_CACHE']: - print 'Using build cache located at', main['M5_BUILD_CACHE'] + print('Using build cache located at', main['M5_BUILD_CACHE']) CacheDir(main['M5_BUILD_CACHE']) main['USE_PYTHON'] = not GetOption('without_python') @@ -974,18 +718,21 @@ if main['USE_PYTHON']: # we add them explicitly below. If you want to link in an alternate # version of python, see above for instructions on how to invoke # scons with the appropriate PATH set. - # - # First we check if python2-config exists, else we use python-config - python_config = readCommand(['which', 'python2-config'], - exception='').strip() - if not os.path.exists(python_config): - python_config = readCommand(['which', 'python-config'], - exception='').strip() + + python_config = find_first_prog(main['PYTHON_CONFIG']) + if python_config is None: + print("Error: can't find a suitable python-config, tried %s" % \ + main['PYTHON_CONFIG']) + Exit(1) + + print("Info: Using Python config: %s" % (python_config, )) py_includes = readCommand([python_config, '--includes'], exception='').split() + py_includes = filter(lambda s: match(r'.*\/include\/.*',s), py_includes) # Strip the -I from the include folders before adding them to the # CPPPATH - main.Append(CPPPATH=map(lambda inc: inc[2:], py_includes)) + py_includes = map(lambda s: s[2:] if s.startswith('-I') else s, py_includes) + main.Append(CPPPATH=py_includes) # Read the linker flags and split them into libraries and other link # flags. The libraries are added later through the call the CheckLib. @@ -1002,27 +749,32 @@ if main['USE_PYTHON']: # verify that this stuff works if not conf.CheckHeader('Python.h', '<>'): - print "Error: can't find Python.h header in", py_includes - print "Install Python headers (package python-dev on Ubuntu and RedHat)" + print("Error: Check failed for Python.h header in", py_includes) + print("Two possible reasons:") + print("1. Python headers are not installed (You can install the " + "package python-dev on Ubuntu and RedHat)") + print("2. SCons is using a wrong C compiler. This can happen if " + "CC has the wrong value.") + print("CC = %s" % main['CC']) Exit(1) for lib in py_libs: if not conf.CheckLib(lib): - print "Error: can't find library %s required by python" % lib + print("Error: can't find library %s required by python" % lib) Exit(1) # On Solaris you need to use libsocket for socket ops if not conf.CheckLibWithHeader(None, 'sys/socket.h', 'C++', 'accept(0,0,0);'): if not conf.CheckLibWithHeader('socket', 'sys/socket.h', 'C++', 'accept(0,0,0);'): - print "Can't find library with socket calls (e.g. accept())" + print("Can't find library with socket calls (e.g. accept())") Exit(1) # Check for zlib. If the check passes, libz will be automatically # added to the LIBS environment variable. if not conf.CheckLibWithHeader('z', 'zlib.h', 'C++','zlibVersion();'): - print 'Error: did not find needed zlib compression library '\ - 'and/or zlib.h header file.' - print ' Please install zlib and try again.' + print('Error: did not find needed zlib compression library ' + 'and/or zlib.h header file.') + print(' Please install zlib and try again.') Exit(1) # If we have the protobuf compiler, also make sure we have the @@ -1034,12 +786,16 @@ main['HAVE_PROTOBUF'] = main['PROTOC'] and \ conf.CheckLibWithHeader('protobuf', 'google/protobuf/message.h', 'C++', 'GOOGLE_PROTOBUF_VERIFY_VERSION;') +# Valgrind gets much less confused if you tell it when you're using +# alternative stacks. +main['HAVE_VALGRIND'] = conf.CheckCHeader('valgrind/valgrind.h') + # If we have the compiler but not the library, print another warning. if main['PROTOC'] and not main['HAVE_PROTOBUF']: - print termcap.Yellow + termcap.Bold + \ - 'Warning: did not find protocol buffer library and/or headers.\n' + \ - ' Please install libprotobuf-dev for tracing support.' + \ - termcap.Normal + print(termcap.Yellow + termcap.Bold + + 'Warning: did not find protocol buffer library and/or headers.\n' + + ' Please install libprotobuf-dev for tracing support.' + + termcap.Normal) # Check for librt. have_posix_clock = \ @@ -1058,39 +814,48 @@ if not GetOption('without_tcmalloc'): elif conf.CheckLib('tcmalloc_minimal'): main.Append(CCFLAGS=main['TCMALLOC_CCFLAGS']) else: - print termcap.Yellow + termcap.Bold + \ - "You can get a 12% performance improvement by "\ - "installing tcmalloc (libgoogle-perftools-dev package "\ - "on Ubuntu or RedHat)." + termcap.Normal + print(termcap.Yellow + termcap.Bold + + "You can get a 12% performance improvement by " + "installing tcmalloc (libgoogle-perftools-dev package " + "on Ubuntu or RedHat)." + termcap.Normal) # Detect back trace implementations. The last implementation in the # list will be used by default. backtrace_impls = [ "none" ] -if conf.CheckLibWithHeader(None, 'execinfo.h', 'C', - 'backtrace_symbols_fd((void*)0, 0, 0);'): +backtrace_checker = 'char temp;' + \ + ' backtrace_symbols_fd((void*)&temp, 0, 0);' +if conf.CheckLibWithHeader(None, 'execinfo.h', 'C', backtrace_checker): backtrace_impls.append("glibc") elif conf.CheckLibWithHeader('execinfo', 'execinfo.h', 'C', - 'backtrace_symbols_fd((void*)0, 0, 0);'): + backtrace_checker): # NetBSD and FreeBSD need libexecinfo. backtrace_impls.append("glibc") main.Append(LIBS=['execinfo']) if backtrace_impls[-1] == "none": default_backtrace_impl = "none" - print termcap.Yellow + termcap.Bold + \ - "No suitable back trace implementation found." + \ - termcap.Normal + print(termcap.Yellow + termcap.Bold + + "No suitable back trace implementation found." + + termcap.Normal) if not have_posix_clock: - print "Can't find library for POSIX clocks." + print("Can't find library for POSIX clocks.") # Check for (C99 FP environment control) have_fenv = conf.CheckHeader('fenv.h', '<>') if not have_fenv: - print "Warning: Header file not found." - print " This host has no IEEE FP rounding mode control." + print("Warning: Header file not found.") + print(" This host has no IEEE FP rounding mode control.") + +# Check for (libpng library needed if wanting to dump +# frame buffer image in png format) +have_png = conf.CheckHeader('png.h', '<>') +if not have_png: + print("Warning: Header file not found.") + print(" This host has no libpng library.") + print(" Disabling support for PNG framebuffers.") # Check if we should enable KVM-based hardware virtualization. The API # we rely on exists since version 2.6.36 of the kernel, but somehow @@ -1098,8 +863,13 @@ if not have_fenv: # the types as a fall back. have_kvm = conf.CheckHeader('linux/kvm.h', '<>') if not have_kvm: - print "Info: Compatible header file not found, " \ - "disabling KVM support." + print("Info: Compatible header file not found, " + "disabling KVM support.") + +# Check if the TUN/TAP driver is available. +have_tuntap = conf.CheckHeader('linux/if_tun.h', '<>') +if not have_tuntap: + print("Info: Compatible header file not found.") # x86 needs support for xsave. We test for the structure here since we # won't be able to run new tests by the time we know which ISA we're @@ -1113,12 +883,12 @@ def is_isa_kvm_compatible(isa): import platform host_isa = platform.machine() except: - print "Warning: Failed to determine host ISA." + print("Warning: Failed to determine host ISA.") return False if not have_posix_timers: - print "Warning: Can not enable KVM, host seems to lack support " \ - "for POSIX timers" + print("Warning: Can not enable KVM, host seems to lack support " + "for POSIX timers") return False if isa == "arm": @@ -1128,7 +898,7 @@ def is_isa_kvm_compatible(isa): return False if not have_kvm_xsave: - print "KVM on x86 requires xsave support in kernel headers." + print("KVM on x86 requires xsave support in kernel headers.") return False return True @@ -1201,15 +971,15 @@ Export('slicc_includes') # Walk the tree and execute all SConsopts scripts that wil add to the # above variables if GetOption('verbose'): - print "Reading SConsopts" + print("Reading SConsopts") for bdir in [ base_dir ] + extras_dir_list: if not isdir(bdir): - print "Error: directory '%s' does not exist" % bdir + print("Error: directory '%s' does not exist" % bdir) Exit(1) for root, dirs, files in os.walk(bdir): if 'SConsopts' in files: if GetOption('verbose'): - print "Reading", joinpath(root, 'SConsopts') + print("Reading", joinpath(root, 'SConsopts')) SConscript(joinpath(root, 'SConsopts')) all_isa_list.sort() @@ -1231,8 +1001,14 @@ sticky_vars.AddVariables( False), BoolVariable('USE_POSIX_CLOCK', 'Use POSIX Clocks', have_posix_clock), BoolVariable('USE_FENV', 'Use IEEE mode control', have_fenv), - BoolVariable('CP_ANNOTATE', 'Enable critical path annotation capability', False), - BoolVariable('USE_KVM', 'Enable hardware virtualized (KVM) CPU models', have_kvm), + BoolVariable('USE_PNG', 'Enable support for PNG images', have_png), + BoolVariable('CP_ANNOTATE', 'Enable critical path annotation capability', + False), + BoolVariable('USE_KVM', 'Enable hardware virtualized (KVM) CPU models', + have_kvm), + BoolVariable('USE_TUNTAP', + 'Enable using a tap device to bridge to the host network', + have_tuntap), BoolVariable('BUILD_GPU', 'Build the compute-GPU model', False), EnumVariable('PROTOCOL', 'Coherence protocol for Ruby', 'None', all_protocols), @@ -1242,8 +1018,9 @@ sticky_vars.AddVariables( # These variables get exported to #defines in config/*.hh (see src/SConscript). export_vars += ['USE_FENV', 'SS_COMPATIBLE_FP', 'TARGET_ISA', 'TARGET_GPU_ISA', - 'CP_ANNOTATE', 'USE_POSIX_CLOCK', 'USE_KVM', 'PROTOCOL', - 'HAVE_PROTOBUF', 'HAVE_PERF_ATTR_EXCLUDE_HOST'] + 'CP_ANNOTATE', 'USE_POSIX_CLOCK', 'USE_KVM', 'USE_TUNTAP', + 'PROTOCOL', 'HAVE_PROTOBUF', 'HAVE_VALGRIND', + 'HAVE_PERF_ATTR_EXCLUDE_HOST', 'USE_PNG'] ################################################### # @@ -1258,7 +1035,7 @@ export_vars += ['USE_FENV', 'SS_COMPATIBLE_FP', 'TARGET_ISA', 'TARGET_GPU_ISA', def build_config_file(target, source, env): (variable, value) = [s.get_contents() for s in source] f = file(str(target[0]), 'w') - print >> f, '#define', variable, value + print('#define', variable, value, file=f) f.close() return None @@ -1312,108 +1089,76 @@ partial_shared_builder = Builder(action=SCons.Defaults.ShLinkAction, main.Append(BUILDERS = { 'PartialShared' : partial_shared_builder, 'PartialStatic' : partial_static_builder }) +def add_local_rpath(env, *targets): + '''Set up an RPATH for a library which lives in the build directory. + + The construction environment variable BIN_RPATH_PREFIX should be set to + the relative path of the build directory starting from the location of the + binary.''' + for target in targets: + target = env.Entry(target) + if not isinstance(target, SCons.Node.FS.Dir): + target = target.dir + relpath = os.path.relpath(target.abspath, env['BUILDDIR']) + components = [ + '\\$$ORIGIN', + '${BIN_RPATH_PREFIX}', + relpath + ] + env.Append(RPATH=[env.Literal(os.path.join(*components))]) + +if sys.platform != "darwin": + main.Append(LINKFLAGS=Split('-z origin')) + +main.AddMethod(add_local_rpath, 'AddLocalRPATH') + # builds in ext are shared across all configs in the build root. ext_dir = abspath(joinpath(str(main.root), 'ext')) +ext_build_dirs = [] for root, dirs, files in os.walk(ext_dir): if 'SConscript' in files: build_dir = os.path.relpath(root, ext_dir) + ext_build_dirs.append(build_dir) main.SConscript(joinpath(root, 'SConscript'), variant_dir=joinpath(build_root, build_dir)) +gdb_xml_dir = joinpath(ext_dir, 'gdb-xml') +Export('gdb_xml_dir') + main.Prepend(CPPPATH=Dir('ext/pybind11/include/')) ################################################### # -# This function is used to set up a directory with switching headers +# This builder and wrapper method are used to set up a directory with +# switching headers. Those are headers which are in a generic location and +# that include more specific headers from a directory chosen at build time +# based on the current build settings. # ################################################### -main['ALL_ISA_LIST'] = all_isa_list -main['ALL_GPU_ISA_LIST'] = all_gpu_isa_list -all_isa_deps = {} -def make_switching_dir(dname, switch_headers, env): - # Generate the header. target[0] is the full path of the output - # header to generate. 'source' is a dummy variable, since we get the - # list of ISAs from env['ALL_ISA_LIST']. - def gen_switch_hdr(target, source, env): - fname = str(target[0]) - isa = env['TARGET_ISA'].lower() - try: - f = open(fname, 'w') - print >>f, '#include "%s/%s/%s"' % (dname, isa, basename(fname)) - f.close() - except IOError: - print "Failed to create %s" % fname - raise - - # Build SCons Action object. 'varlist' specifies env vars that this - # action depends on; when env['ALL_ISA_LIST'] changes these actions - # should get re-executed. - switch_hdr_action = MakeAction(gen_switch_hdr, - Transform("GENERATE"), varlist=['ALL_ISA_LIST']) - - # Instantiate actions for each header - for hdr in switch_headers: - env.Command(hdr, [], switch_hdr_action) - - isa_target = Dir('.').up().name.lower().replace('_', '-') - env['PHONY_BASE'] = '#'+isa_target - all_isa_deps[isa_target] = None - -Export('make_switching_dir') - -def make_gpu_switching_dir(dname, switch_headers, env): - # Generate the header. target[0] is the full path of the output - # header to generate. 'source' is a dummy variable, since we get the - # list of ISAs from env['ALL_ISA_LIST']. - def gen_switch_hdr(target, source, env): - fname = str(target[0]) - - isa = env['TARGET_GPU_ISA'].lower() - - try: - f = open(fname, 'w') - print >>f, '#include "%s/%s/%s"' % (dname, isa, basename(fname)) - f.close() - except IOError: - print "Failed to create %s" % fname - raise - - # Build SCons Action object. 'varlist' specifies env vars that this - # action depends on; when env['ALL_ISA_LIST'] changes these actions - # should get re-executed. - switch_hdr_action = MakeAction(gen_switch_hdr, - Transform("GENERATE"), varlist=['ALL_ISA_GPU_LIST']) - - # Instantiate actions for each header - for hdr in switch_headers: - env.Command(hdr, [], switch_hdr_action) - -Export('make_gpu_switching_dir') - -# all-isas -> all-deps -> all-environs -> all_targets -main.Alias('#all-isas', []) -main.Alias('#all-deps', '#all-isas') - -# Dummy target to ensure all environments are created before telling -# SCons what to actually make (the command line arguments). We attach -# them to the dependence graph after the environments are complete. -ORIG_BUILD_TARGETS = list(BUILD_TARGETS) # force a copy; gets closure to work. -def environsComplete(target, source, env): - for t in ORIG_BUILD_TARGETS: - main.Depends('#all-targets', t) - -# Each build/* switching_dir attaches its *-environs target to #all-environs. -main.Append(BUILDERS = {'CompleteEnvirons' : - Builder(action=MakeAction(environsComplete, None))}) -main.CompleteEnvirons('#all-environs', []) - -def doNothing(**ignored): pass -main.Append(BUILDERS = {'Dummy': Builder(action=MakeAction(doNothing, None))}) - -# The final target to which all the original targets ultimately get attached. -main.Dummy('#all-targets', '#all-environs') -BUILD_TARGETS[:] = ['#all-targets'] +def build_switching_header(target, source, env): + path = str(target[0]) + subdir = str(source[0]) + dp, fp = os.path.split(path) + dp = os.path.relpath(os.path.realpath(dp), + os.path.realpath(env['BUILDDIR'])) + with open(path, 'w') as hdr: + print('#include "%s/%s/%s"' % (dp, subdir, fp), file=hdr) + +switching_header_action = MakeAction(build_switching_header, + Transform('GENERATE')) + +switching_header_builder = Builder(action=switching_header_action, + source_factory=Value, + single_source=True) + +main.Append(BUILDERS = { 'SwitchingHeader': switching_header_builder }) + +def switching_headers(self, headers, source): + for header in headers: + self.SwitchingHeader(header, source) + +main.AddMethod(switching_headers, 'SwitchingHeaders') ################################################### # @@ -1423,7 +1168,7 @@ BUILD_TARGETS[:] = ['#all-targets'] for variant_path in variant_paths: if not GetOption('silent'): - print "Building in", variant_path + print("Building in", variant_path) # Make a copy of the build-root environment to use for this config. env = main.Clone() @@ -1442,7 +1187,10 @@ for variant_path in variant_paths: if isfile(current_vars_file): sticky_vars.files.append(current_vars_file) if not GetOption('silent'): - print "Using saved variables file %s" % current_vars_file + print("Using saved variables file %s" % current_vars_file) + elif variant_dir in ext_build_dirs: + # Things in ext are built without a variant directory. + continue else: # Build dir-specific variables file doesn't exist. @@ -1465,12 +1213,12 @@ for variant_path in variant_paths: if existing_files: default_vars_file = existing_files[0] sticky_vars.files.append(default_vars_file) - print "Variables file %s not found,\n using defaults in %s" \ - % (current_vars_file, default_vars_file) + print("Variables file %s not found,\n using defaults in %s" + % (current_vars_file, default_vars_file)) else: - print "Error: cannot find variables file %s or " \ - "default file(s) %s" \ - % (current_vars_file, ' or '.join(default_vars_files)) + print("Error: cannot find variables file %s or " + "default file(s) %s" + % (current_vars_file, ' or '.join(default_vars_files))) Exit(1) # Apply current variable settings to env @@ -1483,35 +1231,50 @@ for variant_path in variant_paths: # Process variable settings. if not have_fenv and env['USE_FENV']: - print "Warning: not available; " \ - "forcing USE_FENV to False in", variant_dir + "." + print("Warning: not available; " + "forcing USE_FENV to False in", variant_dir + ".") env['USE_FENV'] = False if not env['USE_FENV']: - print "Warning: No IEEE FP rounding mode control in", variant_dir + "." - print " FP results may deviate slightly from other platforms." + print("Warning: No IEEE FP rounding mode control in", + variant_dir + ".") + print(" FP results may deviate slightly from other platforms.") + + if not have_png and env['USE_PNG']: + print("Warning: not available; " + "forcing USE_PNG to False in", variant_dir + ".") + env['USE_PNG'] = False + + if env['USE_PNG']: + env.Append(LIBS=['png']) if env['EFENCE']: env.Append(LIBS=['efence']) if env['USE_KVM']: if not have_kvm: - print "Warning: Can not enable KVM, host seems to lack KVM support" + print("Warning: Can not enable KVM, host seems to " + "lack KVM support") env['USE_KVM'] = False elif not is_isa_kvm_compatible(env['TARGET_ISA']): - print "Info: KVM support disabled due to unsupported host and " \ - "target ISA combination" + print("Info: KVM support disabled due to unsupported host and " + "target ISA combination") env['USE_KVM'] = False + if env['USE_TUNTAP']: + if not have_tuntap: + print("Warning: Can't connect EtherTap with a tap device.") + env['USE_TUNTAP'] = False + if env['BUILD_GPU']: env.Append(CPPDEFINES=['BUILD_GPU']) # Warn about missing optional functionality if env['USE_KVM']: if not main['HAVE_PERF_ATTR_EXCLUDE_HOST']: - print "Warning: perf_event headers lack support for the " \ - "exclude_host attribute. KVM instruction counts will " \ - "be inaccurate." + print("Warning: perf_event headers lack support for the " + "exclude_host attribute. KVM instruction counts will " + "be inaccurate.") # Save sticky variable settings back to current variables file sticky_vars.Save(current_vars_file, env) @@ -1524,24 +1287,6 @@ for variant_path in variant_paths: # one for each variant build (debug, opt, etc.) SConscript('src/SConscript', variant_dir = variant_path, exports = 'env') -def pairwise(iterable): - "s -> (s0,s1), (s1,s2), (s2, s3), ..." - a, b = itertools.tee(iterable) - b.next() - return itertools.izip(a, b) - -# Create false dependencies so SCons will parse ISAs, establish -# dependencies, and setup the build Environments serially. Either -# SCons (likely) and/or our SConscripts (possibly) cannot cope with -j -# greater than 1. It appears to be standard race condition stuff; it -# doesn't always fail, but usually, and the behaviors are different. -# Every time I tried to remove this, builds would fail in some -# creative new way. So, don't do that. You'll want to, though, because -# tests/SConscript takes a long time to make its Environments. -for t1, t2 in pairwise(sorted(all_isa_deps.iterkeys())): - main.Depends('#%s-deps' % t2, '#%s-deps' % t1) - main.Depends('#%s-environs' % t2, '#%s-environs' % t1) - # base help text Help(''' Usage: scons [scons options] [build variables] [target(s)]