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