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