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   # GCC 6 and higher is able to detect throwing from inside a destructor and
    376   # reports a warning. However, if negative testing is enabled then assertions
    377   # will throw exceptions.
    378   if env['negative_testing'] == 'on' and env['mode'] == 'debug' \
    379       and compiler >= 'gcc-6':
    380     env.Append(CPPFLAGS = ['-Wno-terminate'])
    381     # The C++11 compatibility warning will also be triggered for this case, as
    382     # the behavior of throwing from desctructors has changed.
    383     if 'std' in env and env['std'] == 'c++98':
    384       env.Append(CPPFLAGS = ['-Wno-c++11-compat'])
    385 
    386   # When compiling with c++98 (the default), allow long long constants.
    387   if 'std' not in env or env['std'] == 'c++98':
    388     env.Append(CPPFLAGS = ['-Wno-long-long'])
    389   # When compiling with c++11, suggest missing override keywords on methods.
    390   if 'std' in env and env['std'] in ['c++11', 'c++14']:
    391     if compiler >= 'gcc-5':
    392       env.Append(CPPFLAGS = ['-Wsuggest-override'])
    393     elif compiler >= 'clang-3.6':
    394       env.Append(CPPFLAGS = ['-Winconsistent-missing-override'])
    395 
    396 
    397 def ConfigureEnvironment(env):
    398   RetrieveEnvironmentVariables(env)
    399   env['host_arch'] = util.GetHostArch(env)
    400   ProcessBuildOptions(env)
    401   if 'std' in env:
    402     env.Append(CPPFLAGS = ['-std=' + env['std']])
    403     std_path = env['std']
    404   ConfigureEnvironmentForCompiler(env)
    405 
    406 
    407 def TargetBuildDir(env):
    408   # Build-time option values are embedded in the build path to avoid requiring a
    409   # full build when an option changes.
    410   build_dir = config.dir_build
    411   for option in options_influencing_build_path:
    412     option_value = ''.join(env[option]) if option in env else ''
    413     build_dir = join(build_dir, option + '_'+ option_value)
    414   return build_dir
    415 
    416 
    417 def PrepareVariantDir(location, build_dir):
    418   location_build_dir = join(build_dir, location)
    419   VariantDir(location_build_dir, location)
    420   return location_build_dir
    421 
    422 
    423 def VIXLLibraryTarget(env):
    424   build_dir = TargetBuildDir(env)
    425   # Create a link to the latest build directory.
    426   # Use `-r` to avoid failure when `latest` exists and is a directory.
    427   subprocess.check_call(["rm", "-rf", config.dir_build_latest])
    428   util.ensure_dir(build_dir)
    429   subprocess.check_call(["ln", "-s", build_dir, config.dir_build_latest])
    430   # Source files are in `src` and in `src/aarch64/`.
    431   variant_dir_vixl = PrepareVariantDir(join('src'), build_dir)
    432   sources = [Glob(join(variant_dir_vixl, '*.cc'))]
    433   if CanTargetAArch32(env):
    434     variant_dir_aarch32 = PrepareVariantDir(join('src', 'aarch32'), build_dir)
    435     sources.append(Glob(join(variant_dir_aarch32, '*.cc')))
    436   if CanTargetAArch64(env):
    437     variant_dir_aarch64 = PrepareVariantDir(join('src', 'aarch64'), build_dir)
    438     sources.append(Glob(join(variant_dir_aarch64, '*.cc')))
    439   return env.Library(join(build_dir, 'vixl'), sources)
    440 
    441 
    442 
    443 # Build ------------------------------------------------------------------------
    444 
    445 # The VIXL library, built by default.
    446 env = Environment(variables = vars,
    447                   BUILDERS = {
    448                       'Markdown': Builder(action = 'markdown $SOURCE > $TARGET',
    449                                           suffix = '.html')
    450                   })
    451 # Abort the build if any command line option is unknown or invalid.
    452 unknown_build_options = vars.UnknownVariables()
    453 if unknown_build_options:
    454   print 'Unknown build options:',  unknown_build_options.keys()
    455   Exit(1)
    456 
    457 ConfigureEnvironment(env)
    458 Help(vars.GenerateHelpText(env))
    459 libvixl = VIXLLibraryTarget(env)
    460 Default(libvixl)
    461 env.Alias('libvixl', libvixl)
    462 top_level_targets.Add('', 'Build the VIXL library.')
    463 
    464 
    465 # Common test code.
    466 test_build_dir = PrepareVariantDir('test', TargetBuildDir(env))
    467 test_objects = [env.Object(Glob(join(test_build_dir, '*.cc')))]
    468 
    469 # AArch32 support
    470 if CanTargetAArch32(env):
    471   # The examples.
    472   aarch32_example_names = util.ListCCFilesWithoutExt(config.dir_aarch32_examples)
    473   aarch32_examples_build_dir = PrepareVariantDir('examples/aarch32', TargetBuildDir(env))
    474   aarch32_example_targets = []
    475   for example in aarch32_example_names:
    476     prog = env.Program(join(aarch32_examples_build_dir, example),
    477                        join(aarch32_examples_build_dir, example + '.cc'),
    478                        LIBS=[libvixl])
    479     aarch32_example_targets.append(prog)
    480   env.Alias('aarch32_examples', aarch32_example_targets)
    481   top_level_targets.Add('aarch32_examples', 'Build the examples for AArch32.')
    482 
    483   # The benchmarks
    484   aarch32_benchmark_names = util.ListCCFilesWithoutExt(config.dir_aarch32_benchmarks)
    485   aarch32_benchmarks_build_dir = PrepareVariantDir('benchmarks/aarch32', TargetBuildDir(env))
    486   aarch32_benchmark_targets = []
    487   for bench in aarch32_benchmark_names:
    488     prog = env.Program(join(aarch32_benchmarks_build_dir, bench),
    489                        join(aarch32_benchmarks_build_dir, bench + '.cc'),
    490                        LIBS=[libvixl])
    491     aarch32_benchmark_targets.append(prog)
    492   env.Alias('aarch32_benchmarks', aarch32_benchmark_targets)
    493   top_level_targets.Add('aarch32_benchmarks', 'Build the benchmarks for AArch32.')
    494 
    495   # The tests.
    496   test_aarch32_build_dir = PrepareVariantDir(join('test', 'aarch32'), TargetBuildDir(env))
    497   test_objects.append(env.Object(
    498       Glob(join(test_aarch32_build_dir, '*.cc')),
    499       CPPPATH = env['CPPPATH'] + [config.dir_tests]))
    500 
    501 # AArch64 support
    502 if CanTargetAArch64(env):
    503   # The benchmarks.
    504   aarch64_benchmark_names = util.ListCCFilesWithoutExt(config.dir_aarch64_benchmarks)
    505   aarch64_benchmarks_build_dir = PrepareVariantDir('benchmarks/aarch64', TargetBuildDir(env))
    506   aarch64_benchmark_targets = []
    507   for bench in aarch64_benchmark_names:
    508     prog = env.Program(join(aarch64_benchmarks_build_dir, bench),
    509                        join(aarch64_benchmarks_build_dir, bench + '.cc'),
    510                        LIBS=[libvixl])
    511     aarch64_benchmark_targets.append(prog)
    512   env.Alias('aarch64_benchmarks', aarch64_benchmark_targets)
    513   top_level_targets.Add('aarch64_benchmarks', 'Build the benchmarks for AArch64.')
    514 
    515   # The examples.
    516   aarch64_example_names = util.ListCCFilesWithoutExt(config.dir_aarch64_examples)
    517   aarch64_examples_build_dir = PrepareVariantDir('examples/aarch64', TargetBuildDir(env))
    518   aarch64_example_targets = []
    519   for example in aarch64_example_names:
    520     prog = env.Program(join(aarch64_examples_build_dir, example),
    521                        join(aarch64_examples_build_dir, example + '.cc'),
    522                        LIBS=[libvixl])
    523     aarch64_example_targets.append(prog)
    524   env.Alias('aarch64_examples', aarch64_example_targets)
    525   top_level_targets.Add('aarch64_examples', 'Build the examples for AArch64.')
    526 
    527   # The tests.
    528   test_aarch64_build_dir = PrepareVariantDir(join('test', 'aarch64'), TargetBuildDir(env))
    529   test_objects.append(env.Object(
    530       Glob(join(test_aarch64_build_dir, '*.cc')),
    531       CPPPATH = env['CPPPATH'] + [config.dir_tests]))
    532 
    533   # The test requires building the example files with specific options, so we
    534   # create a separate variant dir for the example objects built this way.
    535   test_aarch64_examples_vdir = join(TargetBuildDir(env), 'test', 'aarch64', 'test_examples')
    536   VariantDir(test_aarch64_examples_vdir, '.')
    537   test_aarch64_examples_obj = env.Object(
    538       [Glob(join(test_aarch64_examples_vdir, join('test', 'aarch64', 'examples/aarch64', '*.cc'))),
    539        Glob(join(test_aarch64_examples_vdir, join('examples/aarch64', '*.cc')))],
    540       CCFLAGS = env['CCFLAGS'] + ['-DTEST_EXAMPLES'],
    541       CPPPATH = env['CPPPATH'] + [config.dir_aarch64_examples] + [config.dir_tests])
    542   test_objects.append(test_aarch64_examples_obj)
    543 
    544 test = env.Program(join(test_build_dir, 'test-runner'), test_objects,
    545                    LIBS=[libvixl])
    546 env.Alias('tests', test)
    547 top_level_targets.Add('tests', 'Build the tests.')
    548 
    549 
    550 env.Alias('all', top_level_targets.targets)
    551 top_level_targets.Add('all', 'Build all the targets above.')
    552 
    553 Help('\n\nAvailable top level targets:\n' + top_level_targets.Help())
    554 
    555 extra_targets = VIXLTargets()
    556 
    557 # Build documentation
    558 doc = [
    559     env.Markdown('README.md'),
    560     env.Markdown('doc/changelog.md'),
    561     env.Markdown('doc/aarch32/getting-started-aarch32.md'),
    562     env.Markdown('doc/aarch32/design/code-generation-aarch32.md'),
    563     env.Markdown('doc/aarch32/design/literal-pool-aarch32.md'),
    564     env.Markdown('doc/aarch64/supported-instructions-aarch64.md'),
    565     env.Markdown('doc/aarch64/getting-started-aarch64.md'),
    566     env.Markdown('doc/aarch64/topics/ycm.md'),
    567     env.Markdown('doc/aarch64/topics/extending-the-disassembler.md'),
    568     env.Markdown('doc/aarch64/topics/index.md'),
    569 ]
    570 env.Alias('doc', doc)
    571 extra_targets.Add('doc', 'Convert documentation to HTML (requires the '
    572                          '`markdown` program).')
    573 
    574 Help('\nAvailable extra targets:\n' + extra_targets.Help())
    575