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