SConstruct revision 13027:542176b23324
1# -*- mode:python -*-
2
3# Copyright (c) 2013, 2015-2017 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
81from __future__ import print_function
82
83# Global Python includes
84import itertools
85import os
86import re
87import shutil
88import subprocess
89import sys
90
91from os import mkdir, environ
92from os.path import abspath, basename, dirname, expanduser, normpath
93from os.path import exists,  isdir, isfile
94from os.path import join as joinpath, split as splitpath
95
96# SCons includes
97import SCons
98import SCons.Node
99
100from m5.util import compareVersions, readCommand
101
102help_texts = {
103    "options" : "",
104    "global_vars" : "",
105    "local_vars" : ""
106}
107
108Export("help_texts")
109
110
111# There's a bug in scons in that (1) by default, the help texts from
112# AddOption() are supposed to be displayed when you type 'scons -h'
113# and (2) you can override the help displayed by 'scons -h' using the
114# Help() function, but these two features are incompatible: once
115# you've overridden the help text using Help(), there's no way to get
116# at the help texts from AddOptions.  See:
117#     http://scons.tigris.org/issues/show_bug.cgi?id=2356
118#     http://scons.tigris.org/issues/show_bug.cgi?id=2611
119# This hack lets us extract the help text from AddOptions and
120# re-inject it via Help().  Ideally someday this bug will be fixed and
121# we can just use AddOption directly.
122def AddLocalOption(*args, **kwargs):
123    col_width = 30
124
125    help = "  " + ", ".join(args)
126    if "help" in kwargs:
127        length = len(help)
128        if length >= col_width:
129            help += "\n" + " " * col_width
130        else:
131            help += " " * (col_width - length)
132        help += kwargs["help"]
133    help_texts["options"] += help + "\n"
134
135    AddOption(*args, **kwargs)
136
137AddLocalOption('--colors', dest='use_colors', action='store_true',
138               help="Add color to abbreviated scons output")
139AddLocalOption('--no-colors', dest='use_colors', action='store_false',
140               help="Don't add color to abbreviated scons output")
141AddLocalOption('--with-cxx-config', dest='with_cxx_config',
142               action='store_true',
143               help="Build with support for C++-based configuration")
144AddLocalOption('--default', dest='default', type='string', action='store',
145               help='Override which build_opts file to use for defaults')
146AddLocalOption('--ignore-style', dest='ignore_style', action='store_true',
147               help='Disable style checking hooks')
148AddLocalOption('--no-lto', dest='no_lto', action='store_true',
149               help='Disable Link-Time Optimization for fast')
150AddLocalOption('--force-lto', dest='force_lto', action='store_true',
151               help='Use Link-Time Optimization instead of partial linking' +
152                    ' when the compiler doesn\'t support using them together.')
153AddLocalOption('--update-ref', dest='update_ref', action='store_true',
154               help='Update test reference outputs')
155AddLocalOption('--verbose', dest='verbose', action='store_true',
156               help='Print full tool command lines')
157AddLocalOption('--without-python', dest='without_python',
158               action='store_true',
159               help='Build without Python configuration support')
160AddLocalOption('--without-tcmalloc', dest='without_tcmalloc',
161               action='store_true',
162               help='Disable linking against tcmalloc')
163AddLocalOption('--with-ubsan', dest='with_ubsan', action='store_true',
164               help='Build with Undefined Behavior Sanitizer if available')
165AddLocalOption('--with-asan', dest='with_asan', action='store_true',
166               help='Build with Address Sanitizer if available')
167
168if GetOption('no_lto') and GetOption('force_lto'):
169    print('--no-lto and --force-lto are mutually exclusive')
170    Exit(1)
171
172########################################################################
173#
174# Set up the main build environment.
175#
176########################################################################
177
178main = Environment()
179
180from gem5_scons import Transform
181from gem5_scons.util import get_termcap
182termcap = get_termcap()
183
184main_dict_keys = main.Dictionary().keys()
185
186# Check that we have a C/C++ compiler
187if not ('CC' in main_dict_keys and 'CXX' in main_dict_keys):
188    print("No C++ compiler installed (package g++ on Ubuntu and RedHat)")
189    Exit(1)
190
191###################################################
192#
193# Figure out which configurations to set up based on the path(s) of
194# the target(s).
195#
196###################################################
197
198# Find default configuration & binary.
199Default(environ.get('M5_DEFAULT_BINARY', 'build/ALPHA/gem5.debug'))
200
201# helper function: find last occurrence of element in list
202def rfind(l, elt, offs = -1):
203    for i in range(len(l)+offs, 0, -1):
204        if l[i] == elt:
205            return i
206    raise ValueError, "element not found"
207
208# Take a list of paths (or SCons Nodes) and return a list with all
209# paths made absolute and ~-expanded.  Paths will be interpreted
210# relative to the launch directory unless a different root is provided
211def makePathListAbsolute(path_list, root=GetLaunchDir()):
212    return [abspath(joinpath(root, expanduser(str(p))))
213            for p in path_list]
214
215# Each target must have 'build' in the interior of the path; the
216# directory below this will determine the build parameters.  For
217# example, for target 'foo/bar/build/ALPHA_SE/arch/alpha/blah.do' we
218# recognize that ALPHA_SE specifies the configuration because it
219# follow 'build' in the build path.
220
221# The funky assignment to "[:]" is needed to replace the list contents
222# in place rather than reassign the symbol to a new list, which
223# doesn't work (obviously!).
224BUILD_TARGETS[:] = makePathListAbsolute(BUILD_TARGETS)
225
226# Generate a list of the unique build roots and configs that the
227# collected targets reference.
228variant_paths = []
229build_root = None
230for t in BUILD_TARGETS:
231    path_dirs = t.split('/')
232    try:
233        build_top = rfind(path_dirs, 'build', -2)
234    except:
235        print("Error: no non-leaf 'build' dir found on target path", t)
236        Exit(1)
237    this_build_root = joinpath('/',*path_dirs[:build_top+1])
238    if not build_root:
239        build_root = this_build_root
240    else:
241        if this_build_root != build_root:
242            print("Error: build targets not under same build root\n"
243                  "  %s\n  %s" % (build_root, this_build_root))
244            Exit(1)
245    variant_path = joinpath('/',*path_dirs[:build_top+2])
246    if variant_path not in variant_paths:
247        variant_paths.append(variant_path)
248
249# Make sure build_root exists (might not if this is the first build there)
250if not isdir(build_root):
251    mkdir(build_root)
252main['BUILDROOT'] = build_root
253
254Export('main')
255
256main.SConsignFile(joinpath(build_root, "sconsign"))
257
258# Default duplicate option is to use hard links, but this messes up
259# when you use emacs to edit a file in the target dir, as emacs moves
260# file to file~ then copies to file, breaking the link.  Symbolic
261# (soft) links work better.
262main.SetOption('duplicate', 'soft-copy')
263
264#
265# Set up global sticky variables... these are common to an entire build
266# tree (not specific to a particular build like ALPHA_SE)
267#
268
269global_vars_file = joinpath(build_root, 'variables.global')
270
271global_vars = Variables(global_vars_file, args=ARGUMENTS)
272
273global_vars.AddVariables(
274    ('CC', 'C compiler', environ.get('CC', main['CC'])),
275    ('CXX', 'C++ compiler', environ.get('CXX', main['CXX'])),
276    ('PROTOC', 'protoc tool', environ.get('PROTOC', 'protoc')),
277    ('BATCH', 'Use batch pool for build and tests', False),
278    ('BATCH_CMD', 'Batch pool submission command name', 'qdo'),
279    ('M5_BUILD_CACHE', 'Cache built objects in this directory', False),
280    ('EXTRAS', 'Add extra directories to the compilation', '')
281    )
282
283# Update main environment with values from ARGUMENTS & global_vars_file
284global_vars.Update(main)
285help_texts["global_vars"] += global_vars.GenerateHelpText(main)
286
287# Save sticky variable settings back to current variables file
288global_vars.Save(global_vars_file, main)
289
290# Parse EXTRAS variable to build list of all directories where we're
291# look for sources etc.  This list is exported as extras_dir_list.
292base_dir = main.srcdir.abspath
293if main['EXTRAS']:
294    extras_dir_list = makePathListAbsolute(main['EXTRAS'].split(':'))
295else:
296    extras_dir_list = []
297
298Export('base_dir')
299Export('extras_dir_list')
300
301# the ext directory should be on the #includes path
302main.Append(CPPPATH=[Dir('ext')])
303
304# Add shared top-level headers
305main.Prepend(CPPPATH=Dir('include'))
306
307if GetOption('verbose'):
308    def MakeAction(action, string, *args, **kwargs):
309        return Action(action, *args, **kwargs)
310else:
311    MakeAction = Action
312    main['CCCOMSTR']        = Transform("CC")
313    main['CXXCOMSTR']       = Transform("CXX")
314    main['ASCOMSTR']        = Transform("AS")
315    main['ARCOMSTR']        = Transform("AR", 0)
316    main['LINKCOMSTR']      = Transform("LINK", 0)
317    main['SHLINKCOMSTR']    = Transform("SHLINK", 0)
318    main['RANLIBCOMSTR']    = Transform("RANLIB", 0)
319    main['M4COMSTR']        = Transform("M4")
320    main['SHCCCOMSTR']      = Transform("SHCC")
321    main['SHCXXCOMSTR']     = Transform("SHCXX")
322Export('MakeAction')
323
324# Initialize the Link-Time Optimization (LTO) flags
325main['LTO_CCFLAGS'] = []
326main['LTO_LDFLAGS'] = []
327
328# According to the readme, tcmalloc works best if the compiler doesn't
329# assume that we're using the builtin malloc and friends. These flags
330# are compiler-specific, so we need to set them after we detect which
331# compiler we're using.
332main['TCMALLOC_CCFLAGS'] = []
333
334CXX_version = readCommand([main['CXX'],'--version'], exception=False)
335CXX_V = readCommand([main['CXX'],'-V'], exception=False)
336
337main['GCC'] = CXX_version and CXX_version.find('g++') >= 0
338main['CLANG'] = CXX_version and CXX_version.find('clang') >= 0
339if main['GCC'] + main['CLANG'] > 1:
340    print('Error: How can we have two at the same time?')
341    Exit(1)
342
343# Set up default C++ compiler flags
344if main['GCC'] or main['CLANG']:
345    # As gcc and clang share many flags, do the common parts here
346    main.Append(CCFLAGS=['-pipe'])
347    main.Append(CCFLAGS=['-fno-strict-aliasing'])
348    # Enable -Wall and -Wextra and then disable the few warnings that
349    # we consistently violate
350    main.Append(CCFLAGS=['-Wall', '-Wundef', '-Wextra',
351                         '-Wno-sign-compare', '-Wno-unused-parameter'])
352    # We always compile using C++11
353    main.Append(CXXFLAGS=['-std=c++11'])
354    if sys.platform.startswith('freebsd'):
355        main.Append(CCFLAGS=['-I/usr/local/include'])
356        main.Append(CXXFLAGS=['-I/usr/local/include'])
357
358    main['FILTER_PSHLINKFLAGS'] = lambda x: str(x).replace(' -shared', '')
359    main['PSHLINKFLAGS'] = main.subst('${FILTER_PSHLINKFLAGS(SHLINKFLAGS)}')
360    main['PLINKFLAGS'] = main.subst('${LINKFLAGS}')
361    shared_partial_flags = ['-r', '-nostdlib']
362    main.Append(PSHLINKFLAGS=shared_partial_flags)
363    main.Append(PLINKFLAGS=shared_partial_flags)
364
365    # Treat warnings as errors but white list some warnings that we
366    # want to allow (e.g., deprecation warnings).
367    main.Append(CCFLAGS=['-Werror',
368                         '-Wno-error=deprecated-declarations',
369                         '-Wno-error=deprecated',
370                        ])
371else:
372    print(termcap.Yellow + termcap.Bold + 'Error' + termcap.Normal, end=' ')
373    print("Don't know what compiler options to use for your compiler.")
374    print(termcap.Yellow + '       compiler:' + termcap.Normal, main['CXX'])
375    print(termcap.Yellow + '       version:' + termcap.Normal, end = ' ')
376    if not CXX_version:
377        print(termcap.Yellow + termcap.Bold + "COMMAND NOT FOUND!" +
378              termcap.Normal)
379    else:
380        print(CXX_version.replace('\n', '<nl>'))
381    print("       If you're trying to use a compiler other than GCC")
382    print("       or clang, there appears to be something wrong with your")
383    print("       environment.")
384    print("       ")
385    print("       If you are trying to use a compiler other than those listed")
386    print("       above you will need to ease fix SConstruct and ")
387    print("       src/SConscript to support that compiler.")
388    Exit(1)
389
390if main['GCC']:
391    # Check for a supported version of gcc. >= 4.8 is chosen for its
392    # level of c++11 support. See
393    # http://gcc.gnu.org/projects/cxx0x.html for details.
394    gcc_version = readCommand([main['CXX'], '-dumpversion'], exception=False)
395    if compareVersions(gcc_version, "4.8") < 0:
396        print('Error: gcc version 4.8 or newer required.')
397        print('       Installed version: ', gcc_version)
398        Exit(1)
399
400    main['GCC_VERSION'] = gcc_version
401
402    if compareVersions(gcc_version, '4.9') >= 0:
403        # Incremental linking with LTO is currently broken in gcc versions
404        # 4.9 and above. A version where everything works completely hasn't
405        # yet been identified.
406        #
407        # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67548
408        main['BROKEN_INCREMENTAL_LTO'] = True
409    if compareVersions(gcc_version, '6.0') >= 0:
410        # gcc versions 6.0 and greater accept an -flinker-output flag which
411        # selects what type of output the linker should generate. This is
412        # necessary for incremental lto to work, but is also broken in
413        # current versions of gcc. It may not be necessary in future
414        # versions. We add it here since it might be, and as a reminder that
415        # it exists. It's excluded if lto is being forced.
416        #
417        # https://gcc.gnu.org/gcc-6/changes.html
418        # https://gcc.gnu.org/ml/gcc-patches/2015-11/msg03161.html
419        # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69866
420        if not GetOption('force_lto'):
421            main.Append(PSHLINKFLAGS='-flinker-output=rel')
422            main.Append(PLINKFLAGS='-flinker-output=rel')
423
424    # Make sure we warn if the user has requested to compile with the
425    # Undefined Benahvior Sanitizer and this version of gcc does not
426    # support it.
427    if GetOption('with_ubsan') and \
428            compareVersions(gcc_version, '4.9') < 0:
429        print(termcap.Yellow + termcap.Bold +
430            'Warning: UBSan is only supported using gcc 4.9 and later.' +
431            termcap.Normal)
432
433    disable_lto = GetOption('no_lto')
434    if not disable_lto and main.get('BROKEN_INCREMENTAL_LTO', False) and \
435            not GetOption('force_lto'):
436        print(termcap.Yellow + termcap.Bold +
437            'Warning: Your compiler doesn\'t support incremental linking' +
438            ' and lto at the same time, so lto is being disabled. To force' +
439            ' lto on anyway, use the --force-lto option. That will disable' +
440            ' partial linking.' +
441            termcap.Normal)
442        disable_lto = True
443
444    # Add the appropriate Link-Time Optimization (LTO) flags
445    # unless LTO is explicitly turned off. Note that these flags
446    # are only used by the fast target.
447    if not disable_lto:
448        # Pass the LTO flag when compiling to produce GIMPLE
449        # output, we merely create the flags here and only append
450        # them later
451        main['LTO_CCFLAGS'] = ['-flto=%d' % GetOption('num_jobs')]
452
453        # Use the same amount of jobs for LTO as we are running
454        # scons with
455        main['LTO_LDFLAGS'] = ['-flto=%d' % GetOption('num_jobs')]
456
457    main.Append(TCMALLOC_CCFLAGS=['-fno-builtin-malloc', '-fno-builtin-calloc',
458                                  '-fno-builtin-realloc', '-fno-builtin-free'])
459
460    # The address sanitizer is available for gcc >= 4.8
461    if GetOption('with_asan'):
462        if GetOption('with_ubsan') and \
463                compareVersions(main['GCC_VERSION'], '4.9') >= 0:
464            main.Append(CCFLAGS=['-fsanitize=address,undefined',
465                                 '-fno-omit-frame-pointer'],
466                        LINKFLAGS='-fsanitize=address,undefined')
467        else:
468            main.Append(CCFLAGS=['-fsanitize=address',
469                                 '-fno-omit-frame-pointer'],
470                        LINKFLAGS='-fsanitize=address')
471    # Only gcc >= 4.9 supports UBSan, so check both the version
472    # and the command-line option before adding the compiler and
473    # linker flags.
474    elif GetOption('with_ubsan') and \
475            compareVersions(main['GCC_VERSION'], '4.9') >= 0:
476        main.Append(CCFLAGS='-fsanitize=undefined')
477        main.Append(LINKFLAGS='-fsanitize=undefined')
478
479elif main['CLANG']:
480    # Check for a supported version of clang, >= 3.1 is needed to
481    # support similar features as gcc 4.8. See
482    # http://clang.llvm.org/cxx_status.html for details
483    clang_version_re = re.compile(".* version (\d+\.\d+)")
484    clang_version_match = clang_version_re.search(CXX_version)
485    if (clang_version_match):
486        clang_version = clang_version_match.groups()[0]
487        if compareVersions(clang_version, "3.1") < 0:
488            print('Error: clang version 3.1 or newer required.')
489            print('       Installed version:', clang_version)
490            Exit(1)
491    else:
492        print('Error: Unable to determine clang version.')
493        Exit(1)
494
495    # clang has a few additional warnings that we disable, extraneous
496    # parantheses are allowed due to Ruby's printing of the AST,
497    # finally self assignments are allowed as the generated CPU code
498    # is relying on this
499    main.Append(CCFLAGS=['-Wno-parentheses',
500                         '-Wno-self-assign',
501                         # Some versions of libstdc++ (4.8?) seem to
502                         # use struct hash and class hash
503                         # interchangeably.
504                         '-Wno-mismatched-tags',
505                         ])
506
507    main.Append(TCMALLOC_CCFLAGS=['-fno-builtin'])
508
509    # On Mac OS X/Darwin we need to also use libc++ (part of XCode) as
510    # opposed to libstdc++, as the later is dated.
511    if sys.platform == "darwin":
512        main.Append(CXXFLAGS=['-stdlib=libc++'])
513        main.Append(LIBS=['c++'])
514
515    # On FreeBSD we need libthr.
516    if sys.platform.startswith('freebsd'):
517        main.Append(LIBS=['thr'])
518
519    # We require clang >= 3.1, so there is no need to check any
520    # versions here.
521    if GetOption('with_ubsan'):
522        if GetOption('with_asan'):
523            main.Append(CCFLAGS=['-fsanitize=address,undefined',
524                                 '-fno-omit-frame-pointer'],
525                       LINKFLAGS='-fsanitize=address,undefined')
526        else:
527            main.Append(CCFLAGS='-fsanitize=undefined',
528                        LINKFLAGS='-fsanitize=undefined')
529
530    elif GetOption('with_asan'):
531        main.Append(CCFLAGS=['-fsanitize=address',
532                             '-fno-omit-frame-pointer'],
533                   LINKFLAGS='-fsanitize=address')
534
535else:
536    print(termcap.Yellow + termcap.Bold + 'Error' + termcap.Normal, end=' ')
537    print("Don't know what compiler options to use for your compiler.")
538    print(termcap.Yellow + '       compiler:' + termcap.Normal, main['CXX'])
539    print(termcap.Yellow + '       version:' + termcap.Normal, end=' ')
540    if not CXX_version:
541        print(termcap.Yellow + termcap.Bold + "COMMAND NOT FOUND!" +
542              termcap.Normal)
543    else:
544        print(CXX_version.replace('\n', '<nl>'))
545    print("       If you're trying to use a compiler other than GCC")
546    print("       or clang, there appears to be something wrong with your")
547    print("       environment.")
548    print("       ")
549    print("       If you are trying to use a compiler other than those listed")
550    print("       above you will need to ease fix SConstruct and ")
551    print("       src/SConscript to support that compiler.")
552    Exit(1)
553
554# Set up common yacc/bison flags (needed for Ruby)
555main['YACCFLAGS'] = '-d'
556main['YACCHXXFILESUFFIX'] = '.hh'
557
558# Do this after we save setting back, or else we'll tack on an
559# extra 'qdo' every time we run scons.
560if main['BATCH']:
561    main['CC']     = main['BATCH_CMD'] + ' ' + main['CC']
562    main['CXX']    = main['BATCH_CMD'] + ' ' + main['CXX']
563    main['AS']     = main['BATCH_CMD'] + ' ' + main['AS']
564    main['AR']     = main['BATCH_CMD'] + ' ' + main['AR']
565    main['RANLIB'] = main['BATCH_CMD'] + ' ' + main['RANLIB']
566
567if sys.platform == 'cygwin':
568    # cygwin has some header file issues...
569    main.Append(CCFLAGS=["-Wno-uninitialized"])
570
571# Check for the protobuf compiler
572protoc_version = readCommand([main['PROTOC'], '--version'],
573                             exception='').split()
574
575# First two words should be "libprotoc x.y.z"
576if len(protoc_version) < 2 or protoc_version[0] != 'libprotoc':
577    print(termcap.Yellow + termcap.Bold +
578        'Warning: Protocol buffer compiler (protoc) not found.\n' +
579        '         Please install protobuf-compiler for tracing support.' +
580        termcap.Normal)
581    main['PROTOC'] = False
582else:
583    # Based on the availability of the compress stream wrappers,
584    # require 2.1.0
585    min_protoc_version = '2.1.0'
586    if compareVersions(protoc_version[1], min_protoc_version) < 0:
587        print(termcap.Yellow + termcap.Bold +
588            'Warning: protoc version', min_protoc_version,
589            'or newer required.\n' +
590            '         Installed version:', protoc_version[1],
591            termcap.Normal)
592        main['PROTOC'] = False
593    else:
594        # Attempt to determine the appropriate include path and
595        # library path using pkg-config, that means we also need to
596        # check for pkg-config. Note that it is possible to use
597        # protobuf without the involvement of pkg-config. Later on we
598        # check go a library config check and at that point the test
599        # will fail if libprotobuf cannot be found.
600        if readCommand(['pkg-config', '--version'], exception=''):
601            try:
602                # Attempt to establish what linking flags to add for protobuf
603                # using pkg-config
604                main.ParseConfig('pkg-config --cflags --libs-only-L protobuf')
605            except:
606                print(termcap.Yellow + termcap.Bold +
607                    'Warning: pkg-config could not get protobuf flags.' +
608                    termcap.Normal)
609
610
611# Check for 'timeout' from GNU coreutils. If present, regressions will
612# be run with a time limit. We require version 8.13 since we rely on
613# support for the '--foreground' option.
614if sys.platform.startswith('freebsd'):
615    timeout_lines = readCommand(['gtimeout', '--version'],
616                                exception='').splitlines()
617else:
618    timeout_lines = readCommand(['timeout', '--version'],
619                                exception='').splitlines()
620# Get the first line and tokenize it
621timeout_version = timeout_lines[0].split() if timeout_lines else []
622main['TIMEOUT'] =  timeout_version and \
623    compareVersions(timeout_version[-1], '8.13') >= 0
624
625# Add a custom Check function to test for structure members.
626def CheckMember(context, include, decl, member, include_quotes="<>"):
627    context.Message("Checking for member %s in %s..." %
628                    (member, decl))
629    text = """
630#include %(header)s
631int main(){
632  %(decl)s test;
633  (void)test.%(member)s;
634  return 0;
635};
636""" % { "header" : include_quotes[0] + include + include_quotes[1],
637        "decl" : decl,
638        "member" : member,
639        }
640
641    ret = context.TryCompile(text, extension=".cc")
642    context.Result(ret)
643    return ret
644
645# Platform-specific configuration.  Note again that we assume that all
646# builds under a given build root run on the same host platform.
647conf = Configure(main,
648                 conf_dir = joinpath(build_root, '.scons_config'),
649                 log_file = joinpath(build_root, 'scons_config.log'),
650                 custom_tests = {
651        'CheckMember' : CheckMember,
652        })
653
654# Check if we should compile a 64 bit binary on Mac OS X/Darwin
655try:
656    import platform
657    uname = platform.uname()
658    if uname[0] == 'Darwin' and compareVersions(uname[2], '9.0.0') >= 0:
659        if int(readCommand('sysctl -n hw.cpu64bit_capable')[0]):
660            main.Append(CCFLAGS=['-arch', 'x86_64'])
661            main.Append(CFLAGS=['-arch', 'x86_64'])
662            main.Append(LINKFLAGS=['-arch', 'x86_64'])
663            main.Append(ASFLAGS=['-arch', 'x86_64'])
664except:
665    pass
666
667# Recent versions of scons substitute a "Null" object for Configure()
668# when configuration isn't necessary, e.g., if the "--help" option is
669# present.  Unfortuantely this Null object always returns false,
670# breaking all our configuration checks.  We replace it with our own
671# more optimistic null object that returns True instead.
672if not conf:
673    def NullCheck(*args, **kwargs):
674        return True
675
676    class NullConf:
677        def __init__(self, env):
678            self.env = env
679        def Finish(self):
680            return self.env
681        def __getattr__(self, mname):
682            return NullCheck
683
684    conf = NullConf(main)
685
686# Cache build files in the supplied directory.
687if main['M5_BUILD_CACHE']:
688    print('Using build cache located at', main['M5_BUILD_CACHE'])
689    CacheDir(main['M5_BUILD_CACHE'])
690
691main['USE_PYTHON'] = not GetOption('without_python')
692if main['USE_PYTHON']:
693    # Find Python include and library directories for embedding the
694    # interpreter. We rely on python-config to resolve the appropriate
695    # includes and linker flags. ParseConfig does not seem to understand
696    # the more exotic linker flags such as -Xlinker and -export-dynamic so
697    # we add them explicitly below. If you want to link in an alternate
698    # version of python, see above for instructions on how to invoke
699    # scons with the appropriate PATH set.
700    #
701    # First we check if python2-config exists, else we use python-config
702    python_config = readCommand(['which', 'python2-config'],
703                                exception='').strip()
704    if not os.path.exists(python_config):
705        python_config = readCommand(['which', 'python-config'],
706                                    exception='').strip()
707    py_includes = readCommand([python_config, '--includes'],
708                              exception='').split()
709    # Strip the -I from the include folders before adding them to the
710    # CPPPATH
711    main.Append(CPPPATH=map(lambda inc: inc[2:], py_includes))
712
713    # Read the linker flags and split them into libraries and other link
714    # flags. The libraries are added later through the call the CheckLib.
715    py_ld_flags = readCommand([python_config, '--ldflags'],
716        exception='').split()
717    py_libs = []
718    for lib in py_ld_flags:
719         if not lib.startswith('-l'):
720             main.Append(LINKFLAGS=[lib])
721         else:
722             lib = lib[2:]
723             if lib not in py_libs:
724                 py_libs.append(lib)
725
726    # verify that this stuff works
727    if not conf.CheckHeader('Python.h', '<>'):
728        print("Error: Check failed for Python.h header in", py_includes)
729        print("Two possible reasons:")
730        print("1. Python headers are not installed (You can install the "
731              "package python-dev on Ubuntu and RedHat)")
732        print("2. SCons is using a wrong C compiler. This can happen if "
733              "CC has the wrong value.")
734        print("CC = %s" % main['CC'])
735        Exit(1)
736
737    for lib in py_libs:
738        if not conf.CheckLib(lib):
739            print("Error: can't find library %s required by python" % lib)
740            Exit(1)
741
742# On Solaris you need to use libsocket for socket ops
743if not conf.CheckLibWithHeader(None, 'sys/socket.h', 'C++', 'accept(0,0,0);'):
744   if not conf.CheckLibWithHeader('socket', 'sys/socket.h', 'C++', 'accept(0,0,0);'):
745       print("Can't find library with socket calls (e.g. accept())")
746       Exit(1)
747
748# Check for zlib.  If the check passes, libz will be automatically
749# added to the LIBS environment variable.
750if not conf.CheckLibWithHeader('z', 'zlib.h', 'C++','zlibVersion();'):
751    print('Error: did not find needed zlib compression library '
752          'and/or zlib.h header file.')
753    print('       Please install zlib and try again.')
754    Exit(1)
755
756# If we have the protobuf compiler, also make sure we have the
757# development libraries. If the check passes, libprotobuf will be
758# automatically added to the LIBS environment variable. After
759# this, we can use the HAVE_PROTOBUF flag to determine if we have
760# got both protoc and libprotobuf available.
761main['HAVE_PROTOBUF'] = main['PROTOC'] and \
762    conf.CheckLibWithHeader('protobuf', 'google/protobuf/message.h',
763                            'C++', 'GOOGLE_PROTOBUF_VERIFY_VERSION;')
764
765# Valgrind gets much less confused if you tell it when you're using
766# alternative stacks.
767main['HAVE_VALGRIND'] = conf.CheckCHeader('valgrind/valgrind.h')
768
769# If we have the compiler but not the library, print another warning.
770if main['PROTOC'] and not main['HAVE_PROTOBUF']:
771    print(termcap.Yellow + termcap.Bold +
772        'Warning: did not find protocol buffer library and/or headers.\n' +
773    '       Please install libprotobuf-dev for tracing support.' +
774    termcap.Normal)
775
776# Check for librt.
777have_posix_clock = \
778    conf.CheckLibWithHeader(None, 'time.h', 'C',
779                            'clock_nanosleep(0,0,NULL,NULL);') or \
780    conf.CheckLibWithHeader('rt', 'time.h', 'C',
781                            'clock_nanosleep(0,0,NULL,NULL);')
782
783have_posix_timers = \
784    conf.CheckLibWithHeader([None, 'rt'], [ 'time.h', 'signal.h' ], 'C',
785                            'timer_create(CLOCK_MONOTONIC, NULL, NULL);')
786
787if not GetOption('without_tcmalloc'):
788    if conf.CheckLib('tcmalloc'):
789        main.Append(CCFLAGS=main['TCMALLOC_CCFLAGS'])
790    elif conf.CheckLib('tcmalloc_minimal'):
791        main.Append(CCFLAGS=main['TCMALLOC_CCFLAGS'])
792    else:
793        print(termcap.Yellow + termcap.Bold +
794              "You can get a 12% performance improvement by "
795              "installing tcmalloc (libgoogle-perftools-dev package "
796              "on Ubuntu or RedHat)." + termcap.Normal)
797
798
799# Detect back trace implementations. The last implementation in the
800# list will be used by default.
801backtrace_impls = [ "none" ]
802
803backtrace_checker = 'char temp;' + \
804    ' backtrace_symbols_fd((void*)&temp, 0, 0);'
805if conf.CheckLibWithHeader(None, 'execinfo.h', 'C', backtrace_checker):
806    backtrace_impls.append("glibc")
807elif conf.CheckLibWithHeader('execinfo', 'execinfo.h', 'C',
808                             backtrace_checker):
809    # NetBSD and FreeBSD need libexecinfo.
810    backtrace_impls.append("glibc")
811    main.Append(LIBS=['execinfo'])
812
813if backtrace_impls[-1] == "none":
814    default_backtrace_impl = "none"
815    print(termcap.Yellow + termcap.Bold +
816        "No suitable back trace implementation found." +
817        termcap.Normal)
818
819if not have_posix_clock:
820    print("Can't find library for POSIX clocks.")
821
822# Check for <fenv.h> (C99 FP environment control)
823have_fenv = conf.CheckHeader('fenv.h', '<>')
824if not have_fenv:
825    print("Warning: Header file <fenv.h> not found.")
826    print("         This host has no IEEE FP rounding mode control.")
827
828# Check for <png.h> (libpng library needed if wanting to dump
829# frame buffer image in png format)
830have_png = conf.CheckHeader('png.h', '<>')
831if not have_png:
832    print("Warning: Header file <png.h> not found.")
833    print("         This host has no libpng library.")
834    print("         Disabling support for PNG framebuffers.")
835
836# Check if we should enable KVM-based hardware virtualization. The API
837# we rely on exists since version 2.6.36 of the kernel, but somehow
838# the KVM_API_VERSION does not reflect the change. We test for one of
839# the types as a fall back.
840have_kvm = conf.CheckHeader('linux/kvm.h', '<>')
841if not have_kvm:
842    print("Info: Compatible header file <linux/kvm.h> not found, "
843          "disabling KVM support.")
844
845# Check if the TUN/TAP driver is available.
846have_tuntap = conf.CheckHeader('linux/if_tun.h', '<>')
847if not have_tuntap:
848    print("Info: Compatible header file <linux/if_tun.h> not found.")
849
850# x86 needs support for xsave. We test for the structure here since we
851# won't be able to run new tests by the time we know which ISA we're
852# targeting.
853have_kvm_xsave = conf.CheckTypeSize('struct kvm_xsave',
854                                    '#include <linux/kvm.h>') != 0
855
856# Check if the requested target ISA is compatible with the host
857def is_isa_kvm_compatible(isa):
858    try:
859        import platform
860        host_isa = platform.machine()
861    except:
862        print("Warning: Failed to determine host ISA.")
863        return False
864
865    if not have_posix_timers:
866        print("Warning: Can not enable KVM, host seems to lack support "
867              "for POSIX timers")
868        return False
869
870    if isa == "arm":
871        return host_isa in ( "armv7l", "aarch64" )
872    elif isa == "x86":
873        if host_isa != "x86_64":
874            return False
875
876        if not have_kvm_xsave:
877            print("KVM on x86 requires xsave support in kernel headers.")
878            return False
879
880        return True
881    else:
882        return False
883
884
885# Check if the exclude_host attribute is available. We want this to
886# get accurate instruction counts in KVM.
887main['HAVE_PERF_ATTR_EXCLUDE_HOST'] = conf.CheckMember(
888    'linux/perf_event.h', 'struct perf_event_attr', 'exclude_host')
889
890
891######################################################################
892#
893# Finish the configuration
894#
895main = conf.Finish()
896
897######################################################################
898#
899# Collect all non-global variables
900#
901
902# Define the universe of supported ISAs
903all_isa_list = [ ]
904all_gpu_isa_list = [ ]
905Export('all_isa_list')
906Export('all_gpu_isa_list')
907
908class CpuModel(object):
909    '''The CpuModel class encapsulates everything the ISA parser needs to
910    know about a particular CPU model.'''
911
912    # Dict of available CPU model objects.  Accessible as CpuModel.dict.
913    dict = {}
914
915    # Constructor.  Automatically adds models to CpuModel.dict.
916    def __init__(self, name, default=False):
917        self.name = name           # name of model
918
919        # This cpu is enabled by default
920        self.default = default
921
922        # Add self to dict
923        if name in CpuModel.dict:
924            raise AttributeError, "CpuModel '%s' already registered" % name
925        CpuModel.dict[name] = self
926
927Export('CpuModel')
928
929# Sticky variables get saved in the variables file so they persist from
930# one invocation to the next (unless overridden, in which case the new
931# value becomes sticky).
932sticky_vars = Variables(args=ARGUMENTS)
933Export('sticky_vars')
934
935# Sticky variables that should be exported
936export_vars = []
937Export('export_vars')
938
939# For Ruby
940all_protocols = []
941Export('all_protocols')
942protocol_dirs = []
943Export('protocol_dirs')
944slicc_includes = []
945Export('slicc_includes')
946
947# Walk the tree and execute all SConsopts scripts that wil add to the
948# above variables
949if GetOption('verbose'):
950    print("Reading SConsopts")
951for bdir in [ base_dir ] + extras_dir_list:
952    if not isdir(bdir):
953        print("Error: directory '%s' does not exist" % bdir)
954        Exit(1)
955    for root, dirs, files in os.walk(bdir):
956        if 'SConsopts' in files:
957            if GetOption('verbose'):
958                print("Reading", joinpath(root, 'SConsopts'))
959            SConscript(joinpath(root, 'SConsopts'))
960
961all_isa_list.sort()
962all_gpu_isa_list.sort()
963
964sticky_vars.AddVariables(
965    EnumVariable('TARGET_ISA', 'Target ISA', 'alpha', all_isa_list),
966    EnumVariable('TARGET_GPU_ISA', 'Target GPU ISA', 'hsail', all_gpu_isa_list),
967    ListVariable('CPU_MODELS', 'CPU models',
968                 sorted(n for n,m in CpuModel.dict.iteritems() if m.default),
969                 sorted(CpuModel.dict.keys())),
970    BoolVariable('EFENCE', 'Link with Electric Fence malloc debugger',
971                 False),
972    BoolVariable('SS_COMPATIBLE_FP',
973                 'Make floating-point results compatible with SimpleScalar',
974                 False),
975    BoolVariable('USE_SSE2',
976                 'Compile for SSE2 (-msse2) to get IEEE FP on x86 hosts',
977                 False),
978    BoolVariable('USE_POSIX_CLOCK', 'Use POSIX Clocks', have_posix_clock),
979    BoolVariable('USE_FENV', 'Use <fenv.h> IEEE mode control', have_fenv),
980    BoolVariable('USE_PNG',  'Enable support for PNG images', have_png),
981    BoolVariable('CP_ANNOTATE', 'Enable critical path annotation capability',
982                 False),
983    BoolVariable('USE_KVM', 'Enable hardware virtualized (KVM) CPU models',
984                 have_kvm),
985    BoolVariable('USE_TUNTAP',
986                 'Enable using a tap device to bridge to the host network',
987                 have_tuntap),
988    BoolVariable('BUILD_GPU', 'Build the compute-GPU model', False),
989    EnumVariable('PROTOCOL', 'Coherence protocol for Ruby', 'None',
990                  all_protocols),
991    EnumVariable('BACKTRACE_IMPL', 'Post-mortem dump implementation',
992                 backtrace_impls[-1], backtrace_impls)
993    )
994
995# These variables get exported to #defines in config/*.hh (see src/SConscript).
996export_vars += ['USE_FENV', 'SS_COMPATIBLE_FP', 'TARGET_ISA', 'TARGET_GPU_ISA',
997                'CP_ANNOTATE', 'USE_POSIX_CLOCK', 'USE_KVM', 'USE_TUNTAP',
998                'PROTOCOL', 'HAVE_PROTOBUF', 'HAVE_VALGRIND',
999                'HAVE_PERF_ATTR_EXCLUDE_HOST', 'USE_PNG']
1000
1001###################################################
1002#
1003# Define a SCons builder for configuration flag headers.
1004#
1005###################################################
1006
1007# This function generates a config header file that #defines the
1008# variable symbol to the current variable setting (0 or 1).  The source
1009# operands are the name of the variable and a Value node containing the
1010# value of the variable.
1011def build_config_file(target, source, env):
1012    (variable, value) = [s.get_contents() for s in source]
1013    f = file(str(target[0]), 'w')
1014    print('#define', variable, value, file=f)
1015    f.close()
1016    return None
1017
1018# Combine the two functions into a scons Action object.
1019config_action = MakeAction(build_config_file, Transform("CONFIG H", 2))
1020
1021# The emitter munges the source & target node lists to reflect what
1022# we're really doing.
1023def config_emitter(target, source, env):
1024    # extract variable name from Builder arg
1025    variable = str(target[0])
1026    # True target is config header file
1027    target = joinpath('config', variable.lower() + '.hh')
1028    val = env[variable]
1029    if isinstance(val, bool):
1030        # Force value to 0/1
1031        val = int(val)
1032    elif isinstance(val, str):
1033        val = '"' + val + '"'
1034
1035    # Sources are variable name & value (packaged in SCons Value nodes)
1036    return ([target], [Value(variable), Value(val)])
1037
1038config_builder = Builder(emitter = config_emitter, action = config_action)
1039
1040main.Append(BUILDERS = { 'ConfigFile' : config_builder })
1041
1042###################################################
1043#
1044# Builders for static and shared partially linked object files.
1045#
1046###################################################
1047
1048partial_static_builder = Builder(action=SCons.Defaults.LinkAction,
1049                                 src_suffix='$OBJSUFFIX',
1050                                 src_builder=['StaticObject', 'Object'],
1051                                 LINKFLAGS='$PLINKFLAGS',
1052                                 LIBS='')
1053
1054def partial_shared_emitter(target, source, env):
1055    for tgt in target:
1056        tgt.attributes.shared = 1
1057    return (target, source)
1058partial_shared_builder = Builder(action=SCons.Defaults.ShLinkAction,
1059                                 emitter=partial_shared_emitter,
1060                                 src_suffix='$SHOBJSUFFIX',
1061                                 src_builder='SharedObject',
1062                                 SHLINKFLAGS='$PSHLINKFLAGS',
1063                                 LIBS='')
1064
1065main.Append(BUILDERS = { 'PartialShared' : partial_shared_builder,
1066                         'PartialStatic' : partial_static_builder })
1067
1068# builds in ext are shared across all configs in the build root.
1069ext_dir = abspath(joinpath(str(main.root), 'ext'))
1070ext_build_dirs = []
1071for root, dirs, files in os.walk(ext_dir):
1072    if 'SConscript' in files:
1073        build_dir = os.path.relpath(root, ext_dir)
1074        ext_build_dirs.append(build_dir)
1075        main.SConscript(joinpath(root, 'SConscript'),
1076                        variant_dir=joinpath(build_root, build_dir))
1077
1078main.Prepend(CPPPATH=Dir('ext/pybind11/include/'))
1079
1080###################################################
1081#
1082# This builder and wrapper method are used to set up a directory with
1083# switching headers. Those are headers which are in a generic location and
1084# that include more specific headers from a directory chosen at build time
1085# based on the current build settings.
1086#
1087###################################################
1088
1089def build_switching_header(target, source, env):
1090    path = str(target[0])
1091    subdir = str(source[0])
1092    dp, fp = os.path.split(path)
1093    dp = os.path.relpath(os.path.realpath(dp),
1094                         os.path.realpath(env['BUILDDIR']))
1095    with open(path, 'w') as hdr:
1096        print('#include "%s/%s/%s"' % (dp, subdir, fp), file=hdr)
1097
1098switching_header_action = MakeAction(build_switching_header,
1099                                     Transform('GENERATE'))
1100
1101switching_header_builder = Builder(action=switching_header_action,
1102                                   source_factory=Value,
1103                                   single_source=True)
1104
1105main.Append(BUILDERS = { 'SwitchingHeader': switching_header_builder })
1106
1107def switching_headers(self, headers, source):
1108    for header in headers:
1109        self.SwitchingHeader(header, source)
1110
1111main.AddMethod(switching_headers, 'SwitchingHeaders')
1112
1113###################################################
1114#
1115# Define build environments for selected configurations.
1116#
1117###################################################
1118
1119for variant_path in variant_paths:
1120    if not GetOption('silent'):
1121        print("Building in", variant_path)
1122
1123    # Make a copy of the build-root environment to use for this config.
1124    env = main.Clone()
1125    env['BUILDDIR'] = variant_path
1126
1127    # variant_dir is the tail component of build path, and is used to
1128    # determine the build parameters (e.g., 'ALPHA_SE')
1129    (build_root, variant_dir) = splitpath(variant_path)
1130
1131    # Set env variables according to the build directory config.
1132    sticky_vars.files = []
1133    # Variables for $BUILD_ROOT/$VARIANT_DIR are stored in
1134    # $BUILD_ROOT/variables/$VARIANT_DIR so you can nuke
1135    # $BUILD_ROOT/$VARIANT_DIR without losing your variables settings.
1136    current_vars_file = joinpath(build_root, 'variables', variant_dir)
1137    if isfile(current_vars_file):
1138        sticky_vars.files.append(current_vars_file)
1139        if not GetOption('silent'):
1140            print("Using saved variables file %s" % current_vars_file)
1141    elif variant_dir in ext_build_dirs:
1142        # Things in ext are built without a variant directory.
1143        continue
1144    else:
1145        # Build dir-specific variables file doesn't exist.
1146
1147        # Make sure the directory is there so we can create it later
1148        opt_dir = dirname(current_vars_file)
1149        if not isdir(opt_dir):
1150            mkdir(opt_dir)
1151
1152        # Get default build variables from source tree.  Variables are
1153        # normally determined by name of $VARIANT_DIR, but can be
1154        # overridden by '--default=' arg on command line.
1155        default = GetOption('default')
1156        opts_dir = joinpath(main.root.abspath, 'build_opts')
1157        if default:
1158            default_vars_files = [joinpath(build_root, 'variables', default),
1159                                  joinpath(opts_dir, default)]
1160        else:
1161            default_vars_files = [joinpath(opts_dir, variant_dir)]
1162        existing_files = filter(isfile, default_vars_files)
1163        if existing_files:
1164            default_vars_file = existing_files[0]
1165            sticky_vars.files.append(default_vars_file)
1166            print("Variables file %s not found,\n  using defaults in %s"
1167                  % (current_vars_file, default_vars_file))
1168        else:
1169            print("Error: cannot find variables file %s or "
1170                  "default file(s) %s"
1171                  % (current_vars_file, ' or '.join(default_vars_files)))
1172            Exit(1)
1173
1174    # Apply current variable settings to env
1175    sticky_vars.Update(env)
1176
1177    help_texts["local_vars"] += \
1178        "Build variables for %s:\n" % variant_dir \
1179                 + sticky_vars.GenerateHelpText(env)
1180
1181    # Process variable settings.
1182
1183    if not have_fenv and env['USE_FENV']:
1184        print("Warning: <fenv.h> not available; "
1185              "forcing USE_FENV to False in", variant_dir + ".")
1186        env['USE_FENV'] = False
1187
1188    if not env['USE_FENV']:
1189        print("Warning: No IEEE FP rounding mode control in",
1190              variant_dir + ".")
1191        print("         FP results may deviate slightly from other platforms.")
1192
1193    if not have_png and env['USE_PNG']:
1194        print("Warning: <png.h> not available; "
1195              "forcing USE_PNG to False in", variant_dir + ".")
1196        env['USE_PNG'] = False
1197
1198    if env['USE_PNG']:
1199        env.Append(LIBS=['png'])
1200
1201    if env['EFENCE']:
1202        env.Append(LIBS=['efence'])
1203
1204    if env['USE_KVM']:
1205        if not have_kvm:
1206            print("Warning: Can not enable KVM, host seems to "
1207                  "lack KVM support")
1208            env['USE_KVM'] = False
1209        elif not is_isa_kvm_compatible(env['TARGET_ISA']):
1210            print("Info: KVM support disabled due to unsupported host and "
1211                  "target ISA combination")
1212            env['USE_KVM'] = False
1213
1214    if env['USE_TUNTAP']:
1215        if not have_tuntap:
1216            print("Warning: Can't connect EtherTap with a tap device.")
1217            env['USE_TUNTAP'] = False
1218
1219    if env['BUILD_GPU']:
1220        env.Append(CPPDEFINES=['BUILD_GPU'])
1221
1222    # Warn about missing optional functionality
1223    if env['USE_KVM']:
1224        if not main['HAVE_PERF_ATTR_EXCLUDE_HOST']:
1225            print("Warning: perf_event headers lack support for the "
1226                  "exclude_host attribute. KVM instruction counts will "
1227                  "be inaccurate.")
1228
1229    # Save sticky variable settings back to current variables file
1230    sticky_vars.Save(current_vars_file, env)
1231
1232    if env['USE_SSE2']:
1233        env.Append(CCFLAGS=['-msse2'])
1234
1235    # The src/SConscript file sets up the build rules in 'env' according
1236    # to the configured variables.  It returns a list of environments,
1237    # one for each variant build (debug, opt, etc.)
1238    SConscript('src/SConscript', variant_dir = variant_path, exports = 'env')
1239
1240# base help text
1241Help('''
1242Usage: scons [scons options] [build variables] [target(s)]
1243
1244Extra scons options:
1245%(options)s
1246
1247Global build variables:
1248%(global_vars)s
1249
1250%(local_vars)s
1251''' % help_texts)
1252