1#!/usr/bin/env python 2# 3# Copyright (C) 2015 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16# 17"""Builds the Android Clang toolchain.""" 18import argparse 19import glob 20import logging 21import multiprocessing 22import os 23import pprint 24import subprocess 25import sys 26 27import version 28 29 30# Disable all the "too many/few methods/parameters" warnings and the like. 31# pylint: disable=design 32 33# Disable lint warnings for todo comments and the like. 34# pylint: disable=fixme 35 36# TODO: Add docstrings? 37# pylint: disable=missing-docstring 38 39 40THIS_DIR = os.path.realpath(os.path.dirname(__file__)) 41ORIG_ENV = dict(os.environ) 42 43 44class Config(object): 45 """Container for global configuration options.""" 46 47 # Set True to skip all actions (log only). Controlled by --dry-run. 48 dry_run = False 49 50 51def logger(): 52 """Returns the default logger for the module.""" 53 return logging.getLogger(__name__) 54 55 56def android_path(*args): 57 return os.path.realpath(os.path.join(THIS_DIR, '../..', *args)) 58 59 60def build_path(*args): 61 # Our multistage build directories will be placed under OUT_DIR if it is in 62 # the environment. By default they will be placed under 63 # $ANDROID_BUILD_TOP/out. 64 top_out = ORIG_ENV.get('OUT_DIR', 'out') 65 return os.path.join(top_out, *args) 66 67 68def short_version(): 69 return '.'.join([version.major, version.minor]) 70 71 72def long_version(): 73 return '.'.join([version.major, version.minor, version.patch]) 74 75 76def check_call(cmd, *args, **kwargs): 77 """Proxy for subprocess.check_call with logging and dry-run support.""" 78 import subprocess 79 logger().info('check_call: %s', ' '.join(cmd)) 80 if 'env' in kwargs: 81 # Rather than dump the whole environment to the terminal every time, 82 # just print the difference between this call and our environment. 83 # Note that this will not include environment that was *removed* from 84 # os.environ. 85 extra_env = dict(set(kwargs['env'].items()) - set(os.environ.items())) 86 if len(extra_env) > 0: 87 logger().info('check_call additional env:\n%s', 88 pprint.pformat(extra_env)) 89 if not Config.dry_run: 90 subprocess.check_call(cmd, *args, **kwargs) 91 92 93def install_file(src, dst): 94 """Proxy for shutil.copy2 with logging and dry-run support.""" 95 import shutil 96 logger().info('copy %s %s', src, dst) 97 if not Config.dry_run: 98 shutil.copy2(src, dst) 99 100 101def install_directory(src, dst): 102 """Proxy for shutil.copytree with logging and dry-run support.""" 103 import shutil 104 logger().info('copytree %s %s', src, dst) 105 if not Config.dry_run: 106 shutil.copytree(src, dst) 107 108 109def rmtree(path): 110 """Proxy for shutil.rmtree with logging and dry-run support.""" 111 import shutil 112 logger().info('rmtree %s', path) 113 if not Config.dry_run: 114 shutil.rmtree(path) 115 116 117def rename(src, dst): 118 """Proxy for os.rename with logging and dry-run support.""" 119 logger().info('rename %s %s', src, dst) 120 if not Config.dry_run: 121 os.rename(src, dst) 122 123 124def makedirs(path): 125 """Proxy for os.makedirs with logging and dry-run support.""" 126 logger().info('makedirs %s', path) 127 if not Config.dry_run: 128 os.makedirs(path) 129 130 131def symlink(src, dst): 132 """Proxy for os.symlink with logging and dry-run support.""" 133 logger().info('symlink %s %s', src, dst) 134 if not Config.dry_run: 135 os.symlink(src, dst) 136 137 138def build(out_dir, prebuilts_path=None, prebuilts_version=None, 139 build_all_clang_tools=None, build_all_llvm_tools=None, 140 debug_clang=None, max_jobs=multiprocessing.cpu_count()): 141 products = ( 142 'aosp_arm', 143 'aosp_arm64', 144 'aosp_mips', 145 'aosp_mips64', 146 'aosp_x86', 147 'aosp_x86_64', 148 ) 149 for product in products: 150 build_product(out_dir, product, prebuilts_path, prebuilts_version, 151 build_all_clang_tools, build_all_llvm_tools, debug_clang, 152 max_jobs) 153 154 155def build_product(out_dir, product, prebuilts_path, prebuilts_version, 156 build_all_clang_tools, build_all_llvm_tools, debug_clang, 157 max_jobs): 158 env = dict(ORIG_ENV) 159 env['DISABLE_LLVM_DEVICE_BUILDS'] = 'true' 160 env['DISABLE_RELOCATION_PACKER'] = 'true' 161 env['FORCE_BUILD_LLVM_COMPONENTS'] = 'true' 162 env['FORCE_BUILD_SANITIZER_SHARED_OBJECTS'] = 'true' 163 env['OUT_DIR'] = out_dir 164 env['SKIP_LLVM_TESTS'] = 'true' 165 env['SOONG_ALLOW_MISSING_DEPENDENCIES'] = 'true' 166 env['TARGET_BUILD_VARIANT'] = 'userdebug' 167 env['TARGET_PRODUCT'] = product 168 169 if debug_clang: 170 env['FORCE_BUILD_LLVM_DEBUG'] = 'true' 171 env['FORCE_BUILD_LLVM_DISABLE_NDEBUG'] = 'true' 172 173 overrides = [] 174 if prebuilts_path is not None: 175 overrides.append('LLVM_PREBUILTS_BASE={}'.format(prebuilts_path)) 176 if prebuilts_version is not None: 177 overrides.append('LLVM_PREBUILTS_VERSION={}'.format(prebuilts_version)) 178 179 # Use at least 1 and at most all available CPUs (sanitize the user input). 180 jobs_arg = '-j{}'.format( 181 max(1, min(max_jobs, multiprocessing.cpu_count()))) 182 183 targets = ['clang-toolchain-minimal'] 184 if build_all_clang_tools: 185 targets += ['clang-toolchain-full'] 186 if build_all_llvm_tools: 187 targets += ['llvm-tools'] 188 check_call(['make', jobs_arg] + overrides + targets, 189 cwd=android_path(), env=env) 190 191 192def package_toolchain(build_dir, build_name, host, dist_dir): 193 package_name = 'clang-' + build_name 194 install_host_dir = build_path('install', host) 195 install_dir = os.path.join(install_host_dir, package_name) 196 197 # Remove any previously installed toolchain so it doesn't pollute the 198 # build. 199 if os.path.exists(install_host_dir): 200 rmtree(install_host_dir) 201 202 install_toolchain(build_dir, install_dir, host, True) 203 204 version_file_path = os.path.join(install_dir, 'AndroidVersion.txt') 205 with open(version_file_path, 'w') as version_file: 206 version_file.write('{}.{}.{}\n'.format( 207 version.major, version.minor, version.patch)) 208 209 tarball_name = package_name + '-' + host 210 package_path = os.path.join(dist_dir, tarball_name) + '.tar.bz2' 211 logger().info('Packaging %s', package_path) 212 args = [ 213 'tar', '-cjC', install_host_dir, '-f', package_path, package_name 214 ] 215 check_call(args) 216 217 218def install_minimal_toolchain(build_dir, install_dir, host, strip): 219 install_built_host_files(build_dir, install_dir, host, strip, minimal=True) 220 install_headers(build_dir, install_dir, host) 221 install_sanitizers(build_dir, install_dir, host) 222 223 224def install_toolchain(build_dir, install_dir, host, strip): 225 install_built_host_files(build_dir, install_dir, host, strip) 226 install_compiler_wrapper(install_dir, host) 227 install_sanitizer_scripts(install_dir) 228 install_scan_scripts(install_dir) 229 install_analyzer_scripts(install_dir) 230 install_headers(build_dir, install_dir, host) 231 install_profile_rt(build_dir, install_dir, host) 232 install_sanitizers(build_dir, install_dir, host) 233 install_sanitizer_tests(build_dir, install_dir, host) 234 install_libomp(build_dir, install_dir, host) 235 install_license_files(install_dir) 236 install_repo_prop(install_dir) 237 238 239def get_built_host_files(host, minimal): 240 is_windows = host.startswith('windows') 241 is_darwin = host.startswith('darwin-x86') 242 bin_ext = '.exe' if is_windows else '' 243 244 if is_windows: 245 lib_ext = '.dll' 246 elif is_darwin: 247 lib_ext = '.dylib' 248 else: 249 lib_ext = '.so' 250 251 built_files = [ 252 'bin/clang' + bin_ext, 253 'bin/clang++' + bin_ext, 254 ] 255 if not is_windows: 256 built_files.extend(['lib64/libc++' + lib_ext]) 257 258 if minimal: 259 return built_files 260 261 built_files.extend([ 262 'bin/clang-format' + bin_ext, 263 'bin/clang-tidy' + bin_ext, 264 ]) 265 266 if is_windows: 267 built_files.extend([ 268 'bin/clang_32' + bin_ext, 269 ]) 270 else: 271 built_files.extend([ 272 'bin/FileCheck' + bin_ext, 273 'bin/llvm-as' + bin_ext, 274 'bin/llvm-dis' + bin_ext, 275 'bin/llvm-link' + bin_ext, 276 'bin/llvm-symbolizer' + bin_ext, 277 'lib64/libLLVM' + lib_ext, 278 'lib64/LLVMgold' + lib_ext, 279 ]) 280 return built_files 281 282 283def install_built_host_files(build_dir, install_dir, host, strip, minimal=None): 284 built_files = get_built_host_files(host, minimal) 285 for built_file in built_files: 286 dirname = os.path.dirname(built_file) 287 install_path = os.path.join(install_dir, dirname) 288 if not os.path.exists(install_path): 289 makedirs(install_path) 290 291 built_path = os.path.join(build_dir, 'host', host, built_file) 292 install_file(built_path, install_path) 293 294 file_name = os.path.basename(built_file) 295 296 # Only strip bin files (not libs) on darwin. 297 is_darwin = host.startswith('darwin-x86') 298 if strip and (not is_darwin or built_file.startswith('bin/')): 299 check_call(['strip', os.path.join(install_path, file_name)]) 300 301 302def install_sanitizer_scripts(install_dir): 303 script_path = android_path( 304 'external/compiler-rt/lib/asan/scripts/asan_device_setup') 305 install_file(script_path, os.path.join(install_dir, 'bin')) 306 307 308def install_analyzer_scripts(install_dir): 309 """Create and install bash scripts for invoking Clang for analysis.""" 310 analyzer_text = ( 311 '#!/bin/bash\n' 312 'if [ "$1" != "-cc1" ]; then\n' 313 ' `dirname $0`/../clang{clang_suffix} -target {target} "$@"\n' 314 'else\n' 315 ' # target/triple already spelled out.\n' 316 ' `dirname $0`/../clang{clang_suffix} "$@"\n' 317 'fi\n' 318 ) 319 320 arch_target_pairs = ( 321 ('arm64-v8a', 'aarch64-none-linux-android'), 322 ('armeabi', 'armv5te-none-linux-androideabi'), 323 ('armeabi-v7a', 'armv7-none-linux-androideabi'), 324 ('armeabi-v7a-hard', 'armv7-none-linux-androideabi'), 325 ('mips', 'mipsel-none-linux-android'), 326 ('mips64', 'mips64el-none-linux-android'), 327 ('x86', 'i686-none-linux-android'), 328 ('x86_64', 'x86_64-none-linux-android'), 329 ) 330 331 for arch, target in arch_target_pairs: 332 arch_path = os.path.join(install_dir, 'bin', arch) 333 makedirs(arch_path) 334 335 analyzer_file_path = os.path.join(arch_path, 'analyzer') 336 logger().info('Creating %s', analyzer_file_path) 337 with open(analyzer_file_path, 'w') as analyzer_file: 338 analyzer_file.write( 339 analyzer_text.format(clang_suffix='', target=target)) 340 subprocess.check_call(['chmod', 'a+x', analyzer_file_path]) 341 342 analyzerpp_file_path = os.path.join(arch_path, 'analyzer++') 343 logger().info('Creating %s', analyzerpp_file_path) 344 with open(analyzerpp_file_path, 'w') as analyzerpp_file: 345 analyzerpp_file.write( 346 analyzer_text.format(clang_suffix='++', target=target)) 347 subprocess.check_call(['chmod', 'a+x', analyzerpp_file_path]) 348 349 350def install_scan_scripts(install_dir): 351 tools_install_dir = os.path.join(install_dir, 'tools') 352 makedirs(tools_install_dir) 353 tools = ('scan-build', 'scan-view') 354 tools_dir = android_path('external/clang/tools') 355 for tool in tools: 356 tool_path = os.path.join(tools_dir, tool) 357 install_path = os.path.join(install_dir, 'tools', tool) 358 install_directory(tool_path, install_path) 359 360 361def install_headers(build_dir, install_dir, host): 362 def should_copy(path): 363 if os.path.basename(path) in ('Makefile', 'CMakeLists.txt'): 364 return False 365 _, ext = os.path.splitext(path) 366 if ext == '.mk': 367 return False 368 return True 369 370 headers_src = android_path('external/clang/lib/Headers') 371 headers_dst = os.path.join( 372 install_dir, 'lib64/clang', short_version(), 'include') 373 makedirs(headers_dst) 374 for header in os.listdir(headers_src): 375 if not should_copy(header): 376 continue 377 install_file(os.path.join(headers_src, header), headers_dst) 378 379 install_file(android_path('bionic/libc/include/stdatomic.h'), headers_dst) 380 381 # arm_neon.h gets produced as part of external/clang/Android.bp. 382 # We must bundle the resulting file as part of the official Clang headers. 383 arm_neon_h = os.path.join( 384 build_dir, 'soong/.intermediates/external/clang/clang-gen-arm-neon/gen/clang/Basic/arm_neon.h') 385 install_file(arm_neon_h, headers_dst) 386 387 symlink(short_version(), 388 os.path.join(install_dir, 'lib64/clang', long_version())) 389 390 391def install_profile_rt(build_dir, install_dir, host): 392 lib_dir = os.path.join( 393 install_dir, 'lib64/clang', short_version(), 'lib/linux') 394 makedirs(lib_dir) 395 396 install_target_profile_rt(build_dir, lib_dir) 397 398 # We only support profiling libs for Linux and Android. 399 if host == 'linux-x86': 400 install_host_profile_rt(build_dir, host, lib_dir) 401 402 403def install_target_profile_rt(build_dir, lib_dir): 404 product_to_arch = { 405 'generic': 'arm', 406 'generic_arm64': 'aarch64', 407 'generic_mips': 'mipsel', 408 'generic_mips64': 'mips64el', 409 'generic_x86': 'i686', 410 'generic_x86_64': 'x86_64', 411 } 412 413 for product, arch in product_to_arch.items(): 414 product_dir = os.path.join(build_dir, 'target/product', product) 415 static_libs = os.path.join(product_dir, 'obj/STATIC_LIBRARIES') 416 built_lib = os.path.join( 417 static_libs, 'libprofile_rt_intermediates/libprofile_rt.a') 418 lib_name = 'libclang_rt.profile-{}-android.a'.format(arch) 419 install_file(built_lib, os.path.join(lib_dir, lib_name)) 420 421 422def install_host_profile_rt(build_dir, host, lib_dir): 423 arch_to_obj_dir = { 424 'i686': 'obj32', 425 'x86_64': 'obj', 426 } 427 428 for arch, obj_dir in arch_to_obj_dir.items(): 429 static_libs = os.path.join( 430 build_dir, 'host', host, obj_dir, 'STATIC_LIBRARIES') 431 built_lib = os.path.join( 432 static_libs, 'libprofile_rt_intermediates/libprofile_rt.a') 433 lib_name = 'libclang_rt.profile-{}.a'.format(arch) 434 install_file(built_lib, os.path.join(lib_dir, lib_name)) 435 436 437def install_libomp(build_dir, install_dir, host): 438 # libomp is not built for Darwin 439 if host == 'darwin-x86': 440 return 441 442 lib_dir = os.path.join( 443 install_dir, 'lib64/clang', short_version(), 'lib/linux') 444 if not os.path.isdir(lib_dir): 445 makedirs(lib_dir) 446 447 product_to_arch = { 448 'generic': 'arm', 449 'generic_arm64': 'arm64', 450 'generic_x86': 'x86', 451 'generic_x86_64': 'x86_64', 452 } 453 454 for product, arch in product_to_arch.items(): 455 module = 'libomp-' + arch 456 product_dir = os.path.join(build_dir, 'target/product', product) 457 shared_libs = os.path.join(product_dir, 'obj/SHARED_LIBRARIES') 458 built_lib = os.path.join( 459 shared_libs, 460 '{}_intermediates/PACKED/{}.so'.format(module, module)) 461 install_file(built_lib, os.path.join(lib_dir, module + '.so')) 462 463 464def install_sanitizers(build_dir, install_dir, host): 465 headers_src = android_path('external/compiler-rt/include/sanitizer') 466 clang_lib = os.path.join(install_dir, 'lib64/clang', short_version()) 467 headers_dst = os.path.join(clang_lib, 'include/sanitizer') 468 lib_dst = os.path.join(clang_lib, 'lib/linux') 469 install_directory(headers_src, headers_dst) 470 471 if not os.path.exists(lib_dst): 472 makedirs(lib_dst) 473 474 if host == 'linux-x86': 475 install_host_sanitizers(build_dir, host, lib_dst) 476 477 # Tuples of (product, arch) 478 product_to_arch = ( 479 ('generic', 'arm'), 480 ('generic_arm64', 'aarch64'), 481 ('generic_x86', 'i686'), 482 ('generic_mips', 'mips'), 483 ('generic_mips64', 'mips64'), 484 ) 485 486 sanitizers = ('asan', 'ubsan_standalone') 487 488 for product, arch in product_to_arch: 489 for sanitizer in sanitizers: 490 module = 'libclang_rt.{}-{}-android'.format(sanitizer, arch) 491 product_dir = os.path.join(build_dir, 'target/product', product) 492 lib_dir = os.path.join(product_dir, 'obj/SHARED_LIBRARIES', 493 '{}_intermediates'.format(module)) 494 lib_name = '{}.so'.format(module) 495 built_lib = os.path.join(lib_dir, 'PACKED', lib_name) 496 install_file(built_lib, lib_dst) 497 498 499# Also install the asan_test binaries. We need to do this because the 500# platform sources for compiler-rt are potentially different from our 501# toolchain sources. The only way to ensure that this test builds 502# correctly is to make it a prebuilt based on our latest toolchain 503# sources. Note that this is only created/compiled by the previous 504# stage (usually stage1) compiler. We are not doing a subsequent 505# compile with our stage2 binaries to construct any further 506# device-targeted objects. 507def install_sanitizer_tests(build_dir, install_dir, host): 508 # Tuples of (product, arch) 509 product_to_arch = ( 510 ('generic', 'arm'), 511 ('generic_arm64', 'aarch64'), 512 ('generic_x86', 'i686'), 513 ('generic_mips', 'mips'), 514 ('generic_mips64', 'mips64'), 515 ) 516 517 for product, arch in product_to_arch: 518 product_dir = os.path.join(build_dir, 'target/product', product) 519 test_module = 'asan_test' 520 test_dir = os.path.join(product_dir, 'obj/EXECUTABLES', 521 '{}_intermediates'.format(test_module)) 522 built_test = os.path.join(test_dir, 'PACKED', test_module) 523 test_dst = os.path.join(install_dir, 'test', arch, 'bin') 524 makedirs(test_dst) 525 install_file(built_test, test_dst) 526 527 528def install_host_sanitizers(build_dir, host, lib_dst): 529 # Tuples of (name, multilib). 530 libs = ( 531 ('asan', True), 532 ('asan_cxx', True), 533 ('ubsan_standalone', True), 534 ('ubsan_standalone_cxx', True), 535 ('tsan', False), 536 ('tsan_cxx', False), 537 ) 538 539 obj32 = os.path.join(build_dir, 'host', host, 'obj32/STATIC_LIBRARIES') 540 obj64 = os.path.join(build_dir, 'host', host, 'obj/STATIC_LIBRARIES') 541 for lib, is_multilib in libs: 542 built_lib_name = 'lib{}.a'.format(lib) 543 544 obj64_dir = os.path.join(obj64, 'lib{}_intermediates'.format(lib)) 545 lib64_name = 'libclang_rt.{}-x86_64.a'.format(lib) 546 built_lib64 = os.path.join(obj64_dir, built_lib_name) 547 install_file(built_lib64, os.path.join(lib_dst, lib64_name)) 548 if is_multilib: 549 obj32_dir = os.path.join(obj32, 'lib{}_intermediates'.format(lib)) 550 lib32_name = 'libclang_rt.{}-i686.a'.format(lib) 551 built_lib32 = os.path.join(obj32_dir, built_lib_name) 552 install_file(built_lib32, os.path.join(lib_dst, lib32_name)) 553 554 555def install_license_files(install_dir): 556 projects = ( 557 'clang', 558 'clang-tools-extra', 559 'compiler-rt', 560 'libcxx', 561 'libcxxabi', 562 'libunwind_llvm', 563 'llvm', 564 'openmp_llvm' 565 ) 566 567 notices = [] 568 for project in projects: 569 project_path = android_path('external', project) 570 license_pattern = os.path.join(project_path, 'MODULE_LICENSE_*') 571 for license_file in glob.glob(license_pattern): 572 install_file(license_file, install_dir) 573 with open(os.path.join(project_path, 'NOTICE')) as notice_file: 574 notices.append(notice_file.read()) 575 with open(os.path.join(install_dir, 'NOTICE'), 'w') as notice_file: 576 notice_file.write('\n'.join(notices)) 577 578 579def install_repo_prop(install_dir): 580 file_name = 'repo.prop' 581 582 dist_dir = os.environ.get('DIST_DIR') 583 if dist_dir is not None: 584 dist_repo_prop = os.path.join(dist_dir, file_name) 585 install_file(dist_repo_prop, install_dir) 586 else: 587 out_file = os.path.join(install_dir, file_name) 588 with open(out_file, 'w') as prop_file: 589 cmd = [ 590 'repo', 'forall', '-c', 591 'echo $REPO_PROJECT $(git rev-parse HEAD)', 592 ] 593 check_call(cmd, stdout=prop_file) 594 595 596def install_compiler_wrapper(install_dir, host): 597 is_windows = host.startswith('windows') 598 bin_ext = '.exe' if is_windows else '' 599 600 built_files = [ 601 'bin/clang' + bin_ext, 602 'bin/clang++' + bin_ext, 603 ] 604 605 if is_windows: 606 built_files.extend([ 607 'bin/clang_32' + bin_ext, 608 ]) 609 610 wrapper_dir = android_path('external/clang') 611 wrapper = os.path.join(wrapper_dir, 'compiler_wrapper') 612 613 for built_file in built_files: 614 old_file = os.path.join(install_dir, built_file) 615 new_file = os.path.join(install_dir, built_file + ".real") 616 rename(old_file, new_file) 617 install_file(wrapper, old_file) 618 619 620def parse_args(): 621 parser = argparse.ArgumentParser() 622 623 parser.add_argument('-j', action='store', dest='jobs', type=int, 624 default=multiprocessing.cpu_count(), 625 help='Specify number of executed jobs') 626 627 parser.add_argument( 628 '--build-name', default='dev', help='Release name for the package.') 629 parser.add_argument( 630 '--dry-run', action='store_true', default=False, 631 help='Skip running commands; just print.') 632 parser.add_argument( 633 '-v', '--verbose', action='store_true', default=False, 634 help='Print debug output.') 635 636 multi_stage_group = parser.add_mutually_exclusive_group() 637 multi_stage_group.add_argument( 638 '--multi-stage', action='store_true', default=True, 639 help='Perform multi-stage build (enabled by default).') 640 multi_stage_group.add_argument( 641 '--no-multi-stage', action='store_false', dest='multi_stage', 642 help='Do not perform multi-stage build.') 643 644 build_all_llvm_tools_group = parser.add_mutually_exclusive_group() 645 build_all_llvm_tools_group.add_argument( 646 '--build-all-llvm-tools', action='store_true', default=True, 647 help='Build all the LLVM tools/utilities.') 648 build_all_llvm_tools_group.add_argument( 649 '--no-build-all-llvm-tools', action='store_false', 650 dest='build_all_llvm_tools', 651 help='Do not build all the LLVM tools/utilities.') 652 653 build_debug_clang_group = parser.add_mutually_exclusive_group() 654 build_debug_clang_group.add_argument( 655 '--debug-clang', action='store_true', default=True, 656 help='Also generate a debug version of clang (enabled by default).') 657 build_debug_clang_group.add_argument( 658 '--no-debug-clang', action='store_false', 659 dest='debug_clang', 660 help='Skip generating a debug version of clang.') 661 662 return parser.parse_args() 663 664 665def main(): 666 args = parse_args() 667 log_level = logging.INFO 668 if args.verbose: 669 log_level = logging.DEBUG 670 logging.basicConfig(level=log_level) 671 672 logger().info('chdir %s', android_path()) 673 os.chdir(android_path()) 674 675 Config.dry_run = args.dry_run 676 677 if sys.platform.startswith('linux'): 678 hosts = ['linux-x86', 'windows-x86'] 679 elif sys.platform == 'darwin': 680 hosts = ['darwin-x86'] 681 else: 682 raise RuntimeError('Unsupported host: {}'.format(sys.platform)) 683 684 stage_1_out_dir = build_path('stage1') 685 686 # For a multi-stage build, build a minimum clang for the first stage that is 687 # just enough to build the second stage. 688 is_stage1_final = not args.multi_stage 689 build(out_dir=stage_1_out_dir, 690 build_all_clang_tools=is_stage1_final, 691 build_all_llvm_tools=(is_stage1_final and args.build_all_llvm_tools), 692 max_jobs=args.jobs) 693 final_out_dir = stage_1_out_dir 694 if args.multi_stage: 695 stage_1_install_dir = build_path('stage1-install') 696 for host in hosts: 697 package_name = 'clang-' + args.build_name 698 install_host_dir = os.path.join(stage_1_install_dir, host) 699 install_dir = os.path.join(install_host_dir, package_name) 700 701 # Remove any previously installed toolchain so it doesn't pollute 702 # the build. 703 if os.path.exists(install_host_dir): 704 rmtree(install_host_dir) 705 706 install_minimal_toolchain(stage_1_out_dir, install_dir, host, True) 707 708 stage_2_out_dir = build_path('stage2') 709 build(out_dir=stage_2_out_dir, prebuilts_path=stage_1_install_dir, 710 prebuilts_version=package_name, 711 build_all_clang_tools=True, 712 build_all_llvm_tools=args.build_all_llvm_tools, 713 max_jobs=args.jobs) 714 final_out_dir = stage_2_out_dir 715 716 if args.debug_clang: 717 debug_clang_out_dir = build_path('debug') 718 build(out_dir=debug_clang_out_dir, 719 prebuilts_path=stage_1_install_dir, 720 prebuilts_version=package_name, 721 build_all_clang_tools=True, 722 build_all_llvm_tools=args.build_all_llvm_tools, 723 debug_clang=args.debug_clang, 724 max_jobs=args.jobs) 725 # Install the actual debug toolchain somewhere, so it is easier to 726 # use. 727 debug_package_name = 'clang-debug' 728 base_debug_install_dir = build_path('debug-install') 729 for host in hosts: 730 debug_install_host_dir = os.path.join( 731 base_debug_install_dir, host) 732 debug_install_dir = os.path.join( 733 debug_install_host_dir, debug_package_name) 734 if os.path.exists(debug_install_host_dir): 735 rmtree(debug_install_host_dir) 736 install_toolchain( 737 debug_clang_out_dir, debug_install_dir, host, False) 738 739 dist_dir = ORIG_ENV.get('DIST_DIR', final_out_dir) 740 for host in hosts: 741 package_toolchain(final_out_dir, args.build_name, host, dist_dir) 742 743 744if __name__ == '__main__': 745 print 'This script and llvm branch are deprecated and unmaintained.' 746 print 'Use the llvm-toolchain branch (repo init ... -b llvm-toolchain).' 747 print 'https://android.googlesource.com/toolchain/llvm_android/+/master' 748 sys.exit(0) 749