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