• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2015, VIXL authors
2# All rights reserved.
3#
4# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions are met:
6#
7#   * Redistributions of source code must retain the above copyright notice,
8#     this list of conditions and the following disclaimer.
9#   * Redistributions in binary form must reproduce the above copyright notice,
10#     this list of conditions and the following disclaimer in the documentation
11#     and/or other materials provided with the distribution.
12#   * Neither the name of ARM Limited nor the names of its contributors may be
13#     used to endorse or promote products derived from this software without
14#     specific prior written permission.
15#
16# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27import glob
28import itertools
29import os
30from os.path import join
31import platform
32import subprocess
33import sys
34from collections import OrderedDict
35
36root_dir = os.path.dirname(File('SConstruct').rfile().abspath)
37sys.path.insert(0, join(root_dir, 'tools'))
38import config
39import util
40
41from SCons.Errors import UserError
42
43
44Help('''
45Build system for the VIXL project.
46See README.md for documentation and details about the build system.
47''')
48
49
50# We track top-level targets to automatically generate help and alias them.
51class VIXLTargets:
52  def __init__(self):
53    self.targets = []
54    self.help_messages = []
55  def Add(self, target, help_message):
56    self.targets.append(target)
57    self.help_messages.append(help_message)
58  def Help(self):
59    res = ""
60    for i in range(len(self.targets)):
61      res += '\t{0:<{1}}{2:<{3}}\n'.format(
62        'scons ' + self.targets[i],
63        len('scons ') + max(map(len, self.targets)),
64        ' : ' + self.help_messages[i],
65        len(' : ') + max(map(len, self.help_messages)))
66    return res
67
68top_level_targets = VIXLTargets()
69
70
71
72# Build options ----------------------------------------------------------------
73
74# Store all the options in a dictionary.
75# The SConstruct will check the build variables and construct the build
76# environment as appropriate.
77options = {
78    'all' : { # Unconditionally processed.
79      'CCFLAGS' : ['-Wall',
80                   '-Werror',
81                   '-fdiagnostics-show-option',
82                   '-Wextra',
83                   '-Wredundant-decls',
84                   '-pedantic',
85                   '-Wwrite-strings',
86                   '-Wunused',
87                   '-Wshadow',
88                   '-Wno-missing-noreturn'],
89      'CPPPATH' : [config.dir_src_vixl]
90      },
91#   'build_option:value' : {
92#     'environment_key' : 'values to append'
93#     },
94    'mode:debug' : {
95      'CCFLAGS' : ['-DVIXL_DEBUG', '-O0']
96      },
97    'mode:release' : {
98      'CCFLAGS' : ['-O3'],
99      },
100    'simulator:aarch64' : {
101      'CCFLAGS' : ['-DVIXL_INCLUDE_SIMULATOR_AARCH64',
102                   '-pthread'],
103      'LINKFLAGS' : ['-pthread']
104      },
105    'symbols:on' : {
106      'CCFLAGS' : ['-g'],
107      'LINKFLAGS' : ['-g']
108      },
109    'negative_testing:on' : {
110      'CCFLAGS' : ['-DVIXL_NEGATIVE_TESTING']
111      },
112    'code_buffer_allocator:mmap' : {
113      'CCFLAGS' : ['-DVIXL_CODE_BUFFER_MMAP']
114      },
115    'code_buffer_allocator:malloc' : {
116      'CCFLAGS' : ['-DVIXL_CODE_BUFFER_MALLOC']
117      },
118    'ubsan:on' : {
119      'CCFLAGS': ['-fsanitize=undefined'],
120      'LINKFLAGS': ['-fsanitize=undefined']
121      },
122    'coverage:on' : {
123      'CCFLAGS': ['-fprofile-instr-generate', '-fcoverage-mapping'],
124      'LINKFLAGS': ['-fprofile-instr-generate', '-fcoverage-mapping']
125      },
126    'implicit_checks:on' : {
127      'CCFLAGS' : ['-DVIXL_ENABLE_IMPLICIT_CHECKS'],
128      }
129    }
130
131
132# A `DefaultVariable` has a default value that depends on elements not known
133# when variables are first evaluated.
134# Each `DefaultVariable` has a handler that will compute the default value for
135# the given environment.
136def modifiable_flags_handler(env):
137  env['modifiable_flags'] = \
138      'on' if 'mode' in env and env['mode'] == 'debug' else 'off'
139
140
141def symbols_handler(env):
142  env['symbols'] = 'on' if 'mode' in env and env['mode'] == 'debug' else 'off'
143
144def Is32BitHost(env):
145  return env['host_arch'] in ['aarch32', 'i386']
146
147def IsAArch64Host(env):
148  return env['host_arch'] == 'aarch64'
149
150def CanTargetA32(env):
151  return 'a32' in env['target']
152
153def CanTargetT32(env):
154  return 't32' in env['target']
155
156def CanTargetAArch32(env):
157  return CanTargetA32(env) or CanTargetT32(env)
158
159def CanTargetA64(env):
160  return 'a64' in env['target']
161
162def CanTargetAArch64(env):
163  return CanTargetA64(env)
164
165
166# By default, include the simulator only if AArch64 is targeted and we are not
167# building VIXL natively for AArch64.
168def simulator_handler(env):
169  if not IsAArch64Host(env) and CanTargetAArch64(env):
170    env['simulator'] = 'aarch64'
171  else:
172    env['simulator'] = 'none'
173
174
175# 'mmap' is required for use with 'mprotect', which is needed for the tests
176# (when running natively), so we use it by default where we can.
177def code_buffer_allocator_handler(env):
178  directives = util.GetCompilerDirectives(env)
179  if '__linux__' in directives:
180    env['code_buffer_allocator'] = 'mmap'
181  else:
182    env['code_buffer_allocator'] = 'malloc'
183
184# A validator checks the consistency of provided options against the environment.
185def default_validator(env):
186  pass
187
188
189def simulator_validator(env):
190  if env['simulator'] == 'aarch64' and not CanTargetAArch64(env):
191    raise UserError('Building an AArch64 simulator implies that VIXL targets '
192                    'AArch64. Set `target` to include `aarch64` or `a64`.')
193
194
195# Default variables may depend on each other, therefore we need this dictionary
196# to be ordered.
197vars_default_handlers = OrderedDict({
198    # variable_name    : [ 'default val', 'handler', 'validator']
199    'symbols'          : [ 'mode==debug', symbols_handler, default_validator ],
200    'modifiable_flags' : [ 'mode==debug', modifiable_flags_handler, default_validator],
201    'simulator'        : [ 'on if the target architectures include AArch64 but '
202                           'the host is not AArch64, else off',
203                           simulator_handler, simulator_validator ],
204    'code_buffer_allocator' : [ 'mmap with __linux__, malloc otherwise',
205                                code_buffer_allocator_handler, default_validator ]
206    })
207
208
209def DefaultVariable(name, help, allowed_values):
210  help = '%s (%s)' % (help, '|'.join(allowed_values))
211  default_value = vars_default_handlers[name][0]
212  def validator(name, value, env):
213    if value != default_value and value not in allowed_values:
214        raise UserError('Invalid value for option {name}: {value}.  '
215                        'Valid values are: {allowed_values}'.format(
216                            name, value, allowed_values))
217  return (name, help, default_value, validator)
218
219
220def SortListVariable(iterator):
221  # Previously this code relied on the order of items in a list
222  # converted from a set. However in Python 3 the order changes each run.
223  # Here we do a custom partial sort to ensure that the build directory
224  # name is stable, the same across Python 2 and 3, and the same as the
225  # old code.
226  result = list(sorted(iterator))
227  result = sorted(result, key=lambda x: x == 't32', reverse=True)
228  result = sorted(result, key=lambda x: x == 'a32', reverse=True)
229  result = sorted(result, key=lambda x: x == 'a64', reverse=True)
230  return result
231
232
233def AliasedListVariable(name, help, default_value, allowed_values, aliasing):
234  help = '%s (all|auto|comma-separated list) (any combination from [%s])' % \
235         (help, ', '.join(allowed_values))
236
237  def validator(name, value, env):
238    # Here list has been converted to space separated strings.
239    if value == '': return  # auto
240    for v in value.split():
241      if v not in allowed_values:
242        raise UserError('Invalid value for %s: %s' % (name, value))
243
244  def converter(value):
245    if value == 'auto': return []
246    if value == 'all':
247      translated = [aliasing[v] for v in allowed_values]
248      return SortListVariable(itertools.chain.from_iterable(translated))
249    # The validator is run later hence the get.
250    translated = [aliasing.get(v, v) for v in value.split(',')]
251    return SortListVariable(itertools.chain.from_iterable(translated))
252
253  return (name, help, default_value, validator, converter)
254
255
256vars = Variables()
257# Define command line build options.
258vars.AddVariables(
259    AliasedListVariable('target', 'Target ISA/Architecture', 'auto',
260                        ['aarch32', 'a32', 't32', 'aarch64', 'a64'],
261                        {'aarch32' : ['a32', 't32'],
262                         'a32' : ['a32'], 't32' : ['t32'],
263                         'aarch64' : ['a64'], 'a64' : ['a64']}),
264    EnumVariable('mode', 'Build mode',
265                 'release', allowed_values=config.build_options_modes),
266    EnumVariable('ubsan', 'Enable undefined behavior checks',
267                 'off', allowed_values=['on', 'off']),
268    EnumVariable('coverage', 'Enable code coverage measurement',
269                 'off', allowed_values=['on', 'off']),
270    EnumVariable('negative_testing',
271                  'Enable negative testing (needs exceptions)',
272                 'off', allowed_values=['on', 'off']),
273    EnumVariable('implicit_checks',
274                 'Allow signals raised from simulated invalid (e.g: out of'
275                 + ' bounds) memory reads to be handled by the host.',
276                 'off', allowed_values=['on', 'off']),
277    DefaultVariable('symbols', 'Include debugging symbols in the binaries',
278                    ['on', 'off']),
279    DefaultVariable('simulator', 'Simulators to include', ['aarch64', 'none']),
280    DefaultVariable('code_buffer_allocator',
281                    'Configure the allocation mechanism in the CodeBuffer',
282                    ['malloc', 'mmap']),
283    ('std',
284     'C++ standard. The standards tested are: %s.' % \
285     ', '.join(config.tested_cpp_standards),
286     config.tested_cpp_standards[0]),
287    ('compiler_wrapper', 'Command to prefix to the C and C++ compiler (e.g ccache)', '')
288    )
289
290# We use 'variant directories' to avoid recompiling multiple times when build
291# options are changed, different build paths are used depending on the options
292# set. These are the options that should be reflected in the build directory
293# path.
294options_influencing_build_path = [
295  'target', 'mode', 'symbols', 'compiler', 'std', 'simulator', 'negative_testing',
296  'code_buffer_allocator'
297]
298
299
300
301# Build helpers ----------------------------------------------------------------
302
303def RetrieveEnvironmentVariables(env):
304  for key in ['CC', 'CXX', 'AR', 'RANLIB', 'LD']:
305    if os.getenv(key): env[key] = os.getenv(key)
306  if os.getenv('LD_LIBRARY_PATH'): env['LIBPATH'] = os.getenv('LD_LIBRARY_PATH')
307  if os.getenv('CCFLAGS'):
308    env.Append(CCFLAGS = os.getenv('CCFLAGS').split())
309  if os.getenv('CXXFLAGS'):
310    env.Append(CXXFLAGS = os.getenv('CXXFLAGS').split())
311  if os.getenv('LINKFLAGS'):
312    env.Append(LINKFLAGS = os.getenv('LINKFLAGS').split())
313
314# The architecture targeted by default will depend on the compiler being
315# used. 'host_arch' is extracted from the compiler while 'target' can be
316# set by the user.
317# By default, we target both AArch32 and AArch64 unless the compiler targets a
318# 32-bit architecture. At the moment, we cannot build VIXL's AArch64 support on
319# a 32-bit platform.
320# TODO: Port VIXL to build on a 32-bit platform.
321def target_handler(env):
322  # Auto detect
323  if Is32BitHost(env):
324    # We use list(set(...)) to keep the same order as if it was specify as
325    # an option.
326    env['target'] = SortListVariable(['a32', 't32'])
327  else:
328    env['target'] = SortListVariable(['a64', 'a32', 't32'])
329
330
331def target_validator(env):
332  # TODO: Port VIXL64 to work on a 32-bit platform.
333  if Is32BitHost(env) and CanTargetAArch64(env):
334    raise UserError('Building VIXL for AArch64 in 32-bit is not supported. Set '
335                    '`target` to `aarch32`')
336
337
338# The target option is handled differently from the rest.
339def ProcessTargetOption(env):
340  if env['target'] == []: target_handler(env)
341
342  if 'a32' in env['target']: env['CCFLAGS'] += ['-DVIXL_INCLUDE_TARGET_A32']
343  if 't32' in env['target']: env['CCFLAGS'] += ['-DVIXL_INCLUDE_TARGET_T32']
344  if 'a64' in env['target']: env['CCFLAGS'] += ['-DVIXL_INCLUDE_TARGET_A64']
345
346  target_validator(env)
347
348
349def ProcessBuildOptions(env):
350  # 'all' is unconditionally processed.
351  if 'all' in options:
352    for var in options['all']:
353      if var in env and env[var]:
354        env[var] += options['all'][var]
355      else:
356        env[var] = options['all'][var]
357
358  # The target option *must* be processed before the options defined in
359  # vars_default_handlers.
360  ProcessTargetOption(env)
361
362  # Other build options must match 'option:value'
363  env_dict = env.Dictionary()
364
365  # First apply the default variables handlers in order.
366  for key, value in vars_default_handlers.items():
367    default = value[0]
368    handler = value[1]
369    if env_dict.get(key) == default:
370      handler(env_dict)
371
372  # Second, run the series of validators, to check for errors.
373  for _, value in vars_default_handlers.items():
374    validator = value[2]
375    validator(env)
376
377  for key in env_dict.keys():
378    # Then update the environment according to the value of the variable.
379    key_val_couple = key + ':%s' % env_dict[key]
380    if key_val_couple in options:
381      for var in options[key_val_couple]:
382        env[var] += options[key_val_couple][var]
383
384
385def ConfigureEnvironmentForCompiler(env):
386  compiler = util.CompilerInformation(env)
387  if compiler == 'clang':
388    # These warnings only work for Clang.
389    # -Wimplicit-fallthrough only works when compiling the code base as C++11 or
390    # newer. The compiler does not complain if the option is passed when
391    # compiling earlier C++ standards.
392    env.Append(CPPFLAGS = ['-Wimplicit-fallthrough', '-Wshorten-64-to-32'])
393
394    # The '-Wunreachable-code' flag breaks builds for clang 3.4.
395    if compiler != 'clang-3.4':
396      env.Append(CPPFLAGS = ['-Wunreachable-code'])
397
398    if env['ubsan'] == 'on':
399      env.Append(LINKFLAGS = ['-fuse-ld=lld'])
400
401  # GCC 4.8 has a bug which produces a warning saying that an anonymous Operand
402  # object might be used uninitialized:
403  #   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57045
404  # The bug does not seem to appear in GCC 4.7, or in debug builds with GCC 4.8.
405  if env['mode'] == 'release':
406    if compiler == 'gcc-4.8':
407      env.Append(CPPFLAGS = ['-Wno-maybe-uninitialized'])
408
409  # GCC 6 and higher is able to detect throwing from inside a destructor and
410  # reports a warning. However, if negative testing is enabled then assertions
411  # will throw exceptions.
412  if env['negative_testing'] == 'on' and env['mode'] == 'debug' \
413      and compiler >= 'gcc-6':
414    env.Append(CPPFLAGS = ['-Wno-terminate'])
415
416  # Suggest missing override keywords on methods.
417  if compiler >= 'gcc-5':
418    env.Append(CPPFLAGS = ['-Wsuggest-override'])
419  elif compiler >= 'clang-3.6':
420    env.Append(CPPFLAGS = ['-Winconsistent-missing-override'])
421
422
423def ConfigureEnvironment(env):
424  RetrieveEnvironmentVariables(env)
425  env['compiler'] = env['CXX']
426  if env['compiler_wrapper'] != '':
427    env['CXX'] = env['compiler_wrapper'] + ' ' + env['CXX']
428    env['CC'] = env['compiler_wrapper'] + ' ' + env['CC']
429  env['host_arch'] = util.GetHostArch(env)
430  ProcessBuildOptions(env)
431  if 'std' in env:
432    env.Append(CPPFLAGS = ['-std=' + env['std']])
433    std_path = env['std']
434  ConfigureEnvironmentForCompiler(env)
435
436
437def TargetBuildDir(env):
438  # Build-time option values are embedded in the build path to avoid requiring a
439  # full build when an option changes.
440  build_dir = config.dir_build
441  for option in options_influencing_build_path:
442    option_value = ''.join(env[option]) if option in env else ''
443    build_dir = join(build_dir, option + '_'+ option_value)
444  return build_dir
445
446
447def PrepareVariantDir(location, build_dir):
448  location_build_dir = join(build_dir, location)
449  VariantDir(location_build_dir, location)
450  return location_build_dir
451
452
453def VIXLLibraryTarget(env):
454  build_dir = TargetBuildDir(env)
455  # Create a link to the latest build directory.
456  # Use `-r` to avoid failure when `latest` exists and is a directory.
457  subprocess.check_call(["rm", "-rf", config.dir_build_latest])
458  util.ensure_dir(build_dir)
459  subprocess.check_call(["ln", "-s", build_dir, config.dir_build_latest])
460  # Source files are in `src` and in `src/aarch64/`.
461  variant_dir_vixl = PrepareVariantDir(join('src'), build_dir)
462  sources = [Glob(join(variant_dir_vixl, '*.cc'))]
463  if CanTargetAArch32(env):
464    variant_dir_aarch32 = PrepareVariantDir(join('src', 'aarch32'), build_dir)
465    sources.append(Glob(join(variant_dir_aarch32, '*.cc')))
466  if CanTargetAArch64(env):
467    variant_dir_aarch64 = PrepareVariantDir(join('src', 'aarch64'), build_dir)
468    sources.append(Glob(join(variant_dir_aarch64, '*.cc')))
469  return env.Library(join(build_dir, 'vixl'), sources)
470
471
472
473# Build ------------------------------------------------------------------------
474
475# The VIXL library, built by default.
476env = Environment(variables = vars,
477                  BUILDERS = {
478                      'Markdown': Builder(action = 'markdown $SOURCE > $TARGET',
479                                          suffix = '.html')
480                  }, ENV = os.environ)
481# Abort the build if any command line option is unknown or invalid.
482unknown_build_options = vars.UnknownVariables()
483if unknown_build_options:
484  print('Unknown build options: ' + str(unknown_build_options.keys()))
485  Exit(1)
486
487if env['negative_testing'] == 'on' and env['mode'] != 'debug':
488  print('negative_testing only works in debug mode')
489  Exit(1)
490
491ConfigureEnvironment(env)
492Help(vars.GenerateHelpText(env))
493libvixl = VIXLLibraryTarget(env)
494Default(libvixl)
495env.Alias('libvixl', libvixl)
496top_level_targets.Add('', 'Build the VIXL library.')
497
498
499# Common test code.
500test_build_dir = PrepareVariantDir('test', TargetBuildDir(env))
501test_objects = [env.Object(Glob(join(test_build_dir, '*.cc'), exclude=join(test_build_dir, 'test-donkey.cc')))]
502
503# AArch32 support
504if CanTargetAArch32(env):
505  # The examples.
506  aarch32_example_names = util.ListCCFilesWithoutExt(config.dir_aarch32_examples)
507  aarch32_examples_build_dir = PrepareVariantDir('examples/aarch32', TargetBuildDir(env))
508  aarch32_example_targets = []
509  for example in aarch32_example_names:
510    prog = env.Program(join(aarch32_examples_build_dir, example),
511                       join(aarch32_examples_build_dir, example + '.cc'),
512                       LIBS=[libvixl])
513    aarch32_example_targets.append(prog)
514  env.Alias('aarch32_examples', aarch32_example_targets)
515  top_level_targets.Add('aarch32_examples', 'Build the examples for AArch32.')
516
517  # The benchmarks
518  aarch32_benchmark_names = util.ListCCFilesWithoutExt(config.dir_aarch32_benchmarks)
519  aarch32_benchmarks_build_dir = PrepareVariantDir('benchmarks/aarch32', TargetBuildDir(env))
520  aarch32_benchmark_targets = []
521  for bench in aarch32_benchmark_names:
522    prog = env.Program(join(aarch32_benchmarks_build_dir, bench),
523                       join(aarch32_benchmarks_build_dir, bench + '.cc'),
524                       LIBS=[libvixl])
525    aarch32_benchmark_targets.append(prog)
526  env.Alias('aarch32_benchmarks', aarch32_benchmark_targets)
527  top_level_targets.Add('aarch32_benchmarks', 'Build the benchmarks for AArch32.')
528
529  # The tests.
530  test_aarch32_build_dir = PrepareVariantDir(join('test', 'aarch32'), TargetBuildDir(env))
531  test_objects.append(env.Object(
532      Glob(join(test_aarch32_build_dir, '*.cc')),
533      CPPPATH = env['CPPPATH'] + [config.dir_tests],
534      CCFLAGS = [flag for flag in env['CCFLAGS'] if flag != '-O3']))
535
536# AArch64 support
537if CanTargetAArch64(env):
538  # The benchmarks.
539  aarch64_benchmark_names = util.ListCCFilesWithoutExt(config.dir_aarch64_benchmarks)
540  aarch64_benchmarks_build_dir = PrepareVariantDir('benchmarks/aarch64', TargetBuildDir(env))
541  aarch64_benchmark_targets = []
542  bench_utils = env.Object(join(aarch64_benchmarks_build_dir, 'bench-utils.o'),
543                           join(aarch64_benchmarks_build_dir, 'bench-utils.cc'))
544  for bench in aarch64_benchmark_names:
545    if bench != 'bench-utils':
546      prog = env.Program(join(aarch64_benchmarks_build_dir, bench),
547                         [join(aarch64_benchmarks_build_dir, bench + '.cc'), bench_utils],
548                         LIBS=[libvixl])
549      aarch64_benchmark_targets.append(prog)
550  env.Alias('aarch64_benchmarks', aarch64_benchmark_targets)
551  top_level_targets.Add('aarch64_benchmarks', 'Build the benchmarks for AArch64.')
552
553  # The examples.
554  aarch64_example_names = util.ListCCFilesWithoutExt(config.dir_aarch64_examples)
555  aarch64_examples_build_dir = PrepareVariantDir('examples/aarch64', TargetBuildDir(env))
556  aarch64_example_targets = []
557  for example in aarch64_example_names:
558    prog = env.Program(join(aarch64_examples_build_dir, example),
559                       join(aarch64_examples_build_dir, example + '.cc'),
560                       LIBS=[libvixl])
561    aarch64_example_targets.append(prog)
562  env.Alias('aarch64_examples', aarch64_example_targets)
563  top_level_targets.Add('aarch64_examples', 'Build the examples for AArch64.')
564
565  # The tests.
566  test_aarch64_build_dir = PrepareVariantDir(join('test', 'aarch64'), TargetBuildDir(env))
567  test_objects.append(env.Object(
568      Glob(join(test_aarch64_build_dir, '*.cc')),
569      CPPPATH = env['CPPPATH'] + [config.dir_tests],
570      CCFLAGS = [flag for flag in env['CCFLAGS'] if flag != '-O3']))
571
572  # The test requires building the example files with specific options, so we
573  # create a separate variant dir for the example objects built this way.
574  test_aarch64_examples_vdir = join(TargetBuildDir(env), 'test', 'aarch64', 'test_examples')
575  VariantDir(test_aarch64_examples_vdir, '.')
576  test_aarch64_examples_obj = env.Object(
577      [Glob(join(test_aarch64_examples_vdir, join('test', 'aarch64', 'examples', '*.cc'))),
578       Glob(join(test_aarch64_examples_vdir, join('examples/aarch64', '*.cc')))],
579      CCFLAGS = env['CCFLAGS'] + ['-DTEST_EXAMPLES'],
580      CPPPATH = env['CPPPATH'] + [config.dir_aarch64_examples] + [config.dir_tests])
581  test_objects.append(test_aarch64_examples_obj)
582
583  # The simulator test generator.
584  donkey_objects = []
585  donkey_objects.append(env.Object(
586      [join(test_build_dir, 'test-donkey.cc'), join(test_aarch64_build_dir, 'test-utils-aarch64.cc')],
587      CPPPATH = env['CPPPATH'] + [config.dir_tests],
588      CCFLAGS = [flag for flag in env['CCFLAGS'] if flag != '-O3']))
589  donkey = env.Program(join(test_build_dir, 'test-donkey'), donkey_objects, LIBS=[libvixl])
590  env.Alias('tests', donkey)
591
592test = env.Program(join(test_build_dir, 'test-runner'), test_objects,
593                   LIBS=[libvixl])
594env.Alias('tests', test)
595top_level_targets.Add('tests', 'Build the tests.')
596
597
598env.Alias('all', top_level_targets.targets)
599top_level_targets.Add('all', 'Build all the targets above.')
600
601Help('\n\nAvailable top level targets:\n' + top_level_targets.Help())
602
603extra_targets = VIXLTargets()
604
605# Build documentation
606doc = [
607    env.Markdown('README.md'),
608    env.Markdown('doc/changelog.md'),
609    env.Markdown('doc/aarch32/getting-started-aarch32.md'),
610    env.Markdown('doc/aarch32/design/code-generation-aarch32.md'),
611    env.Markdown('doc/aarch32/design/literal-pool-aarch32.md'),
612    env.Markdown('doc/aarch64/supported-instructions-aarch64.md'),
613    env.Markdown('doc/aarch64/getting-started-aarch64.md'),
614    env.Markdown('doc/aarch64/topics/ycm.md'),
615    env.Markdown('doc/aarch64/topics/extending-the-disassembler.md'),
616    env.Markdown('doc/aarch64/topics/index.md'),
617]
618env.Alias('doc', doc)
619extra_targets.Add('doc', 'Convert documentation to HTML (requires the '
620                         '`markdown` program).')
621
622Help('\nAvailable extra targets:\n' + extra_targets.Help())
623