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