• 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      },
103    'symbols:on' : {
104      'CCFLAGS' : ['-g'],
105      'LINKFLAGS' : ['-g']
106      },
107    'negative_testing:on' : {
108      'CCFLAGS' : ['-DVIXL_NEGATIVE_TESTING']
109      },
110    'code_buffer_allocator:mmap' : {
111      'CCFLAGS' : ['-DVIXL_CODE_BUFFER_MMAP']
112      },
113    'code_buffer_allocator:malloc' : {
114      'CCFLAGS' : ['-DVIXL_CODE_BUFFER_MALLOC']
115      },
116    'ubsan:on' : {
117      'CCFLAGS': ['-fsanitize=undefined'],
118      'LINKFLAGS': ['-fsanitize=undefined']
119      },
120    'coverage:on' : {
121      'CCFLAGS': ['-fprofile-instr-generate', '-fcoverage-mapping'],
122      'LINKFLAGS': ['-fprofile-instr-generate', '-fcoverage-mapping']
123      }
124    }
125
126
127# A `DefaultVariable` has a default value that depends on elements not known
128# when variables are first evaluated.
129# Each `DefaultVariable` has a handler that will compute the default value for
130# the given environment.
131def modifiable_flags_handler(env):
132  env['modifiable_flags'] = \
133      'on' if 'mode' in env and env['mode'] == 'debug' else 'off'
134
135
136def symbols_handler(env):
137  env['symbols'] = 'on' if 'mode' in env and env['mode'] == 'debug' else 'off'
138
139def Is32BitHost(env):
140  return env['host_arch'] in ['aarch32', 'i386']
141
142def IsAArch64Host(env):
143  return env['host_arch'] == 'aarch64'
144
145def CanTargetA32(env):
146  return 'a32' in env['target']
147
148def CanTargetT32(env):
149  return 't32' in env['target']
150
151def CanTargetAArch32(env):
152  return CanTargetA32(env) or CanTargetT32(env)
153
154def CanTargetA64(env):
155  return 'a64' in env['target']
156
157def CanTargetAArch64(env):
158  return CanTargetA64(env)
159
160
161# By default, include the simulator only if AArch64 is targeted and we are not
162# building VIXL natively for AArch64.
163def simulator_handler(env):
164  if not IsAArch64Host(env) and CanTargetAArch64(env):
165    env['simulator'] = 'aarch64'
166  else:
167    env['simulator'] = 'none'
168
169
170# 'mmap' is required for use with 'mprotect', which is needed for the tests
171# (when running natively), so we use it by default where we can.
172def code_buffer_allocator_handler(env):
173  directives = util.GetCompilerDirectives(env)
174  if '__linux__' in directives:
175    env['code_buffer_allocator'] = 'mmap'
176  else:
177    env['code_buffer_allocator'] = 'malloc'
178
179# A validator checks the consistency of provided options against the environment.
180def default_validator(env):
181  pass
182
183
184def simulator_validator(env):
185  if env['simulator'] == 'aarch64' and not CanTargetAArch64(env):
186    raise UserError('Building an AArch64 simulator implies that VIXL targets '
187                    'AArch64. Set `target` to include `aarch64` or `a64`.')
188
189
190# Default variables may depend on each other, therefore we need this dictionnary
191# to be ordered.
192vars_default_handlers = OrderedDict({
193    # variable_name    : [ 'default val', 'handler', 'validator']
194    'symbols'          : [ 'mode==debug', symbols_handler, default_validator ],
195    'modifiable_flags' : [ 'mode==debug', modifiable_flags_handler, default_validator],
196    'simulator'        : [ 'on if the target architectures include AArch64 but '
197                           'the host is not AArch64, else off',
198                           simulator_handler, simulator_validator ],
199    'code_buffer_allocator' : [ 'mmap with __linux__, malloc otherwise',
200                                code_buffer_allocator_handler, default_validator ]
201    })
202
203
204def DefaultVariable(name, help, allowed_values):
205  help = '%s (%s)' % (help, '|'.join(allowed_values))
206  default_value = vars_default_handlers[name][0]
207  def validator(name, value, env):
208    if value != default_value and value not in allowed_values:
209        raise UserError('Invalid value for option {name}: {value}.  '
210                        'Valid values are: {allowed_values}'.format(
211                            name, value, allowed_values))
212  return (name, help, default_value, validator)
213
214
215def SortListVariable(iterator):
216  # Previously this code relied on the order of items in a list
217  # converted from a set. However in Python 3 the order changes each run.
218  # Here we do a custom partial sort to ensure that the build directory
219  # name is stable, the same across Python 2 and 3, and the same as the
220  # old code.
221  result = list(sorted(iterator))
222  result = sorted(result, key=lambda x: x == 't32', reverse=True)
223  result = sorted(result, key=lambda x: x == 'a32', reverse=True)
224  result = sorted(result, key=lambda x: x == 'a64', reverse=True)
225  return result
226
227
228def AliasedListVariable(name, help, default_value, allowed_values, aliasing):
229  help = '%s (all|auto|comma-separated list) (any combination from [%s])' % \
230         (help, ', '.join(allowed_values))
231
232  def validator(name, value, env):
233    # Here list has been converted to space separated strings.
234    if value == '': return  # auto
235    for v in value.split():
236      if v not in allowed_values:
237        raise UserError('Invalid value for %s: %s' % (name, value))
238
239  def converter(value):
240    if value == 'auto': return []
241    if value == 'all':
242      translated = [aliasing[v] for v in allowed_values]
243      return SortListVariable(itertools.chain.from_iterable(translated))
244    # The validator is run later hence the get.
245    translated = [aliasing.get(v, v) for v in value.split(',')]
246    return SortListVariable(itertools.chain.from_iterable(translated))
247
248  return (name, help, default_value, validator, converter)
249
250
251vars = Variables()
252# Define command line build options.
253vars.AddVariables(
254    AliasedListVariable('target', 'Target ISA/Architecture', 'auto',
255                        ['aarch32', 'a32', 't32', 'aarch64', 'a64'],
256                        {'aarch32' : ['a32', 't32'],
257                         'a32' : ['a32'], 't32' : ['t32'],
258                         'aarch64' : ['a64'], 'a64' : ['a64']}),
259    EnumVariable('mode', 'Build mode',
260                 'release', allowed_values=config.build_options_modes),
261    EnumVariable('ubsan', 'Enable undefined behavior checks',
262                 'off', allowed_values=['on', 'off']),
263    EnumVariable('coverage', 'Enable code coverage measurement',
264                 'off', allowed_values=['on', 'off']),
265    EnumVariable('negative_testing',
266                  'Enable negative testing (needs exceptions)',
267                 'off', allowed_values=['on', 'off']),
268    DefaultVariable('symbols', 'Include debugging symbols in the binaries',
269                    ['on', 'off']),
270    DefaultVariable('simulator', 'Simulators to include', ['aarch64', 'none']),
271    DefaultVariable('code_buffer_allocator',
272                    'Configure the allocation mechanism in the CodeBuffer',
273                    ['malloc', 'mmap']),
274    ('std',
275     'C++ standard. The standards tested are: %s.' % \
276     ', '.join(config.tested_cpp_standards),
277     config.tested_cpp_standards[0]),
278    ('compiler_wrapper', 'Command to prefix to the C and C++ compiler (e.g ccache)', '')
279    )
280
281# We use 'variant directories' to avoid recompiling multiple times when build
282# options are changed, different build paths are used depending on the options
283# set. These are the options that should be reflected in the build directory
284# path.
285options_influencing_build_path = [
286  'target', 'mode', 'symbols', 'compiler', 'std', 'simulator', 'negative_testing',
287  'code_buffer_allocator'
288]
289
290
291
292# Build helpers ----------------------------------------------------------------
293
294def RetrieveEnvironmentVariables(env):
295  for key in ['CC', 'CXX', 'AR', 'RANLIB', 'LD']:
296    if os.getenv(key): env[key] = os.getenv(key)
297  if os.getenv('LD_LIBRARY_PATH'): env['LIBPATH'] = os.getenv('LD_LIBRARY_PATH')
298  if os.getenv('CCFLAGS'):
299    env.Append(CCFLAGS = os.getenv('CCFLAGS').split())
300  if os.getenv('CXXFLAGS'):
301    env.Append(CXXFLAGS = os.getenv('CXXFLAGS').split())
302  if os.getenv('LINKFLAGS'):
303    env.Append(LINKFLAGS = os.getenv('LINKFLAGS').split())
304
305# The architecture targeted by default will depend on the compiler being
306# used. 'host_arch' is extracted from the compiler while 'target' can be
307# set by the user.
308# By default, we target both AArch32 and AArch64 unless the compiler targets a
309# 32-bit architecture. At the moment, we cannot build VIXL's AArch64 support on
310# a 32-bit platform.
311# TODO: Port VIXL to build on a 32-bit platform.
312def target_handler(env):
313  # Auto detect
314  if Is32BitHost(env):
315    # We use list(set(...)) to keep the same order as if it was specify as
316    # an option.
317    env['target'] = SortListVariable(['a32', 't32'])
318  else:
319    env['target'] = SortListVariable(['a64', 'a32', 't32'])
320
321
322def target_validator(env):
323  # TODO: Port VIXL64 to work on a 32-bit platform.
324  if Is32BitHost(env) and CanTargetAArch64(env):
325    raise UserError('Building VIXL for AArch64 in 32-bit is not supported. Set '
326                    '`target` to `aarch32`')
327
328
329# The target option is handled differently from the rest.
330def ProcessTargetOption(env):
331  if env['target'] == []: target_handler(env)
332
333  if 'a32' in env['target']: env['CCFLAGS'] += ['-DVIXL_INCLUDE_TARGET_A32']
334  if 't32' in env['target']: env['CCFLAGS'] += ['-DVIXL_INCLUDE_TARGET_T32']
335  if 'a64' in env['target']: env['CCFLAGS'] += ['-DVIXL_INCLUDE_TARGET_A64']
336
337  target_validator(env)
338
339
340def ProcessBuildOptions(env):
341  # 'all' is unconditionally processed.
342  if 'all' in options:
343    for var in options['all']:
344      if var in env and env[var]:
345        env[var] += options['all'][var]
346      else:
347        env[var] = options['all'][var]
348
349  # The target option *must* be processed before the options defined in
350  # vars_default_handlers.
351  ProcessTargetOption(env)
352
353  # Other build options must match 'option:value'
354  env_dict = env.Dictionary()
355
356  # First apply the default variables handlers in order.
357  for key, value in vars_default_handlers.items():
358    default = value[0]
359    handler = value[1]
360    if env_dict.get(key) == default:
361      handler(env_dict)
362
363  # Second, run the series of validators, to check for errors.
364  for _, value in vars_default_handlers.items():
365    validator = value[2]
366    validator(env)
367
368  for key in env_dict.keys():
369    # Then update the environment according to the value of the variable.
370    key_val_couple = key + ':%s' % env_dict[key]
371    if key_val_couple in options:
372      for var in options[key_val_couple]:
373        env[var] += options[key_val_couple][var]
374
375
376def ConfigureEnvironmentForCompiler(env):
377  compiler = util.CompilerInformation(env)
378  if compiler == 'clang':
379    # These warnings only work for Clang.
380    # -Wimplicit-fallthrough only works when compiling the code base as C++11 or
381    # newer. The compiler does not complain if the option is passed when
382    # compiling earlier C++ standards.
383    env.Append(CPPFLAGS = ['-Wimplicit-fallthrough', '-Wshorten-64-to-32'])
384
385    # The '-Wunreachable-code' flag breaks builds for clang 3.4.
386    if compiler != 'clang-3.4':
387      env.Append(CPPFLAGS = ['-Wunreachable-code'])
388
389    if env['ubsan'] == 'on':
390      env.Append(LINKFLAGS = ['-fuse-ld=lld'])
391
392  # GCC 4.8 has a bug which produces a warning saying that an anonymous Operand
393  # object might be used uninitialized:
394  #   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57045
395  # The bug does not seem to appear in GCC 4.7, or in debug builds with GCC 4.8.
396  if env['mode'] == 'release':
397    if compiler == 'gcc-4.8':
398      env.Append(CPPFLAGS = ['-Wno-maybe-uninitialized'])
399
400  # GCC 6 and higher is able to detect throwing from inside a destructor and
401  # reports a warning. However, if negative testing is enabled then assertions
402  # will throw exceptions.
403  if env['negative_testing'] == 'on' and env['mode'] == 'debug' \
404      and compiler >= 'gcc-6':
405    env.Append(CPPFLAGS = ['-Wno-terminate'])
406
407  # Suggest missing override keywords on methods.
408  if compiler >= 'gcc-5':
409    env.Append(CPPFLAGS = ['-Wsuggest-override'])
410  elif compiler >= 'clang-3.6':
411    env.Append(CPPFLAGS = ['-Winconsistent-missing-override'])
412
413
414def ConfigureEnvironment(env):
415  RetrieveEnvironmentVariables(env)
416  env['compiler'] = env['CXX']
417  if env['compiler_wrapper'] != '':
418    env['CXX'] = env['compiler_wrapper'] + ' ' + env['CXX']
419    env['CC'] = env['compiler_wrapper'] + ' ' + env['CC']
420  env['host_arch'] = util.GetHostArch(env)
421  ProcessBuildOptions(env)
422  if 'std' in env:
423    env.Append(CPPFLAGS = ['-std=' + env['std']])
424    std_path = env['std']
425  ConfigureEnvironmentForCompiler(env)
426
427
428def TargetBuildDir(env):
429  # Build-time option values are embedded in the build path to avoid requiring a
430  # full build when an option changes.
431  build_dir = config.dir_build
432  for option in options_influencing_build_path:
433    option_value = ''.join(env[option]) if option in env else ''
434    build_dir = join(build_dir, option + '_'+ option_value)
435  return build_dir
436
437
438def PrepareVariantDir(location, build_dir):
439  location_build_dir = join(build_dir, location)
440  VariantDir(location_build_dir, location)
441  return location_build_dir
442
443
444def VIXLLibraryTarget(env):
445  build_dir = TargetBuildDir(env)
446  # Create a link to the latest build directory.
447  # Use `-r` to avoid failure when `latest` exists and is a directory.
448  subprocess.check_call(["rm", "-rf", config.dir_build_latest])
449  util.ensure_dir(build_dir)
450  subprocess.check_call(["ln", "-s", build_dir, config.dir_build_latest])
451  # Source files are in `src` and in `src/aarch64/`.
452  variant_dir_vixl = PrepareVariantDir(join('src'), build_dir)
453  sources = [Glob(join(variant_dir_vixl, '*.cc'))]
454  if CanTargetAArch32(env):
455    variant_dir_aarch32 = PrepareVariantDir(join('src', 'aarch32'), build_dir)
456    sources.append(Glob(join(variant_dir_aarch32, '*.cc')))
457  if CanTargetAArch64(env):
458    variant_dir_aarch64 = PrepareVariantDir(join('src', 'aarch64'), build_dir)
459    sources.append(Glob(join(variant_dir_aarch64, '*.cc')))
460  return env.Library(join(build_dir, 'vixl'), sources)
461
462
463
464# Build ------------------------------------------------------------------------
465
466# The VIXL library, built by default.
467env = Environment(variables = vars,
468                  BUILDERS = {
469                      'Markdown': Builder(action = 'markdown $SOURCE > $TARGET',
470                                          suffix = '.html')
471                  }, ENV = os.environ)
472# Abort the build if any command line option is unknown or invalid.
473unknown_build_options = vars.UnknownVariables()
474if unknown_build_options:
475  print('Unknown build options: ' + str(unknown_build_options.keys()))
476  Exit(1)
477
478if env['negative_testing'] == 'on' and env['mode'] != 'debug':
479  print('negative_testing only works in debug mode')
480  Exit(1)
481
482ConfigureEnvironment(env)
483Help(vars.GenerateHelpText(env))
484libvixl = VIXLLibraryTarget(env)
485Default(libvixl)
486env.Alias('libvixl', libvixl)
487top_level_targets.Add('', 'Build the VIXL library.')
488
489
490# Common test code.
491test_build_dir = PrepareVariantDir('test', TargetBuildDir(env))
492test_objects = [env.Object(Glob(join(test_build_dir, '*.cc'), exclude=join(test_build_dir, 'test-donkey.cc')))]
493
494# AArch32 support
495if CanTargetAArch32(env):
496  # The examples.
497  aarch32_example_names = util.ListCCFilesWithoutExt(config.dir_aarch32_examples)
498  aarch32_examples_build_dir = PrepareVariantDir('examples/aarch32', TargetBuildDir(env))
499  aarch32_example_targets = []
500  for example in aarch32_example_names:
501    prog = env.Program(join(aarch32_examples_build_dir, example),
502                       join(aarch32_examples_build_dir, example + '.cc'),
503                       LIBS=[libvixl])
504    aarch32_example_targets.append(prog)
505  env.Alias('aarch32_examples', aarch32_example_targets)
506  top_level_targets.Add('aarch32_examples', 'Build the examples for AArch32.')
507
508  # The benchmarks
509  aarch32_benchmark_names = util.ListCCFilesWithoutExt(config.dir_aarch32_benchmarks)
510  aarch32_benchmarks_build_dir = PrepareVariantDir('benchmarks/aarch32', TargetBuildDir(env))
511  aarch32_benchmark_targets = []
512  for bench in aarch32_benchmark_names:
513    prog = env.Program(join(aarch32_benchmarks_build_dir, bench),
514                       join(aarch32_benchmarks_build_dir, bench + '.cc'),
515                       LIBS=[libvixl])
516    aarch32_benchmark_targets.append(prog)
517  env.Alias('aarch32_benchmarks', aarch32_benchmark_targets)
518  top_level_targets.Add('aarch32_benchmarks', 'Build the benchmarks for AArch32.')
519
520  # The tests.
521  test_aarch32_build_dir = PrepareVariantDir(join('test', 'aarch32'), TargetBuildDir(env))
522  test_objects.append(env.Object(
523      Glob(join(test_aarch32_build_dir, '*.cc')),
524      CPPPATH = env['CPPPATH'] + [config.dir_tests],
525      CCFLAGS = [flag for flag in env['CCFLAGS'] if flag != '-O3']))
526
527# AArch64 support
528if CanTargetAArch64(env):
529  # The benchmarks.
530  aarch64_benchmark_names = util.ListCCFilesWithoutExt(config.dir_aarch64_benchmarks)
531  aarch64_benchmarks_build_dir = PrepareVariantDir('benchmarks/aarch64', TargetBuildDir(env))
532  aarch64_benchmark_targets = []
533  bench_utils = env.Object(join(aarch64_benchmarks_build_dir, 'bench-utils.o'),
534                           join(aarch64_benchmarks_build_dir, 'bench-utils.cc'))
535  for bench in aarch64_benchmark_names:
536    if bench != 'bench-utils':
537      prog = env.Program(join(aarch64_benchmarks_build_dir, bench),
538                         [join(aarch64_benchmarks_build_dir, bench + '.cc'), bench_utils],
539                         LIBS=[libvixl])
540      aarch64_benchmark_targets.append(prog)
541  env.Alias('aarch64_benchmarks', aarch64_benchmark_targets)
542  top_level_targets.Add('aarch64_benchmarks', 'Build the benchmarks for AArch64.')
543
544  # The examples.
545  aarch64_example_names = util.ListCCFilesWithoutExt(config.dir_aarch64_examples)
546  aarch64_examples_build_dir = PrepareVariantDir('examples/aarch64', TargetBuildDir(env))
547  aarch64_example_targets = []
548  for example in aarch64_example_names:
549    prog = env.Program(join(aarch64_examples_build_dir, example),
550                       join(aarch64_examples_build_dir, example + '.cc'),
551                       LIBS=[libvixl])
552    aarch64_example_targets.append(prog)
553  env.Alias('aarch64_examples', aarch64_example_targets)
554  top_level_targets.Add('aarch64_examples', 'Build the examples for AArch64.')
555
556  # The tests.
557  test_aarch64_build_dir = PrepareVariantDir(join('test', 'aarch64'), TargetBuildDir(env))
558  test_objects.append(env.Object(
559      Glob(join(test_aarch64_build_dir, '*.cc')),
560      CPPPATH = env['CPPPATH'] + [config.dir_tests],
561      CCFLAGS = [flag for flag in env['CCFLAGS'] if flag != '-O3']))
562
563  # The test requires building the example files with specific options, so we
564  # create a separate variant dir for the example objects built this way.
565  test_aarch64_examples_vdir = join(TargetBuildDir(env), 'test', 'aarch64', 'test_examples')
566  VariantDir(test_aarch64_examples_vdir, '.')
567  test_aarch64_examples_obj = env.Object(
568      [Glob(join(test_aarch64_examples_vdir, join('test', 'aarch64', 'examples', '*.cc'))),
569       Glob(join(test_aarch64_examples_vdir, join('examples/aarch64', '*.cc')))],
570      CCFLAGS = env['CCFLAGS'] + ['-DTEST_EXAMPLES'],
571      CPPPATH = env['CPPPATH'] + [config.dir_aarch64_examples] + [config.dir_tests])
572  test_objects.append(test_aarch64_examples_obj)
573
574  # The simulator test generator.
575  donkey_objects = []
576  donkey_objects.append(env.Object(
577      [join(test_build_dir, 'test-donkey.cc'), join(test_aarch64_build_dir, 'test-utils-aarch64.cc')],
578      CPPPATH = env['CPPPATH'] + [config.dir_tests],
579      CCFLAGS = [flag for flag in env['CCFLAGS'] if flag != '-O3']))
580  donkey = env.Program(join(test_build_dir, 'test-donkey'), donkey_objects, LIBS=[libvixl])
581  env.Alias('tests', donkey)
582
583test = env.Program(join(test_build_dir, 'test-runner'), test_objects,
584                   LIBS=[libvixl])
585env.Alias('tests', test)
586top_level_targets.Add('tests', 'Build the tests.')
587
588
589env.Alias('all', top_level_targets.targets)
590top_level_targets.Add('all', 'Build all the targets above.')
591
592Help('\n\nAvailable top level targets:\n' + top_level_targets.Help())
593
594extra_targets = VIXLTargets()
595
596# Build documentation
597doc = [
598    env.Markdown('README.md'),
599    env.Markdown('doc/changelog.md'),
600    env.Markdown('doc/aarch32/getting-started-aarch32.md'),
601    env.Markdown('doc/aarch32/design/code-generation-aarch32.md'),
602    env.Markdown('doc/aarch32/design/literal-pool-aarch32.md'),
603    env.Markdown('doc/aarch64/supported-instructions-aarch64.md'),
604    env.Markdown('doc/aarch64/getting-started-aarch64.md'),
605    env.Markdown('doc/aarch64/topics/ycm.md'),
606    env.Markdown('doc/aarch64/topics/extending-the-disassembler.md'),
607    env.Markdown('doc/aarch64/topics/index.md'),
608]
609env.Alias('doc', doc)
610extra_targets.Add('doc', 'Convert documentation to HTML (requires the '
611                         '`markdown` program).')
612
613Help('\nAvailable extra targets:\n' + extra_targets.Help())
614