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