| #!/usr/bin/env python |
| # |
| # Copyright (C) 2015 The Android Open Source Project |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| # |
| """Verifies that the build is sane. |
| |
| Cleans old build artifacts, configures the required environment, determines |
| build goals, and invokes the build scripts. |
| """ |
| from __future__ import absolute_import |
| from __future__ import print_function |
| |
| import argparse |
| import collections |
| import inspect |
| import multiprocessing |
| import os |
| import shutil |
| import site |
| import subprocess |
| import sys |
| import tempfile |
| import textwrap |
| import traceback |
| |
| import config |
| import build.lib.build_support as build_support |
| import ndk.workqueue |
| |
| |
| ALL_MODULES = { |
| 'clang', |
| 'cpufeatures', |
| 'gabi++', |
| 'gcc', |
| 'gdbserver', |
| 'gnustl', |
| 'gtest', |
| 'host-tools', |
| 'libandroid_support', |
| 'libc++', |
| 'libc++abi', |
| 'libshaderc', |
| 'native_app_glue', |
| 'ndk-build', |
| 'ndk_helper', |
| 'platforms', |
| 'python-packages', |
| 'shader_tools', |
| 'simpleperf', |
| 'stlport', |
| 'system-stl', |
| 'vulkan', |
| } |
| |
| |
| class ArgParser(argparse.ArgumentParser): |
| def __init__(self): |
| super(ArgParser, self).__init__( |
| description=inspect.getdoc(sys.modules[__name__])) |
| |
| self.add_argument( |
| '--arch', |
| choices=('arm', 'arm64', 'mips', 'mips64', 'x86', 'x86_64'), |
| help='Build for the given architecture. Build all by default.') |
| self.add_argument( |
| '-j', '--jobs', type=int, default=multiprocessing.cpu_count(), |
| help=('Number of parallel builds to run. Note that this will not ' |
| 'affect the -j used for make; this just parallelizes ' |
| 'checkbuild.py. Defaults to the number of CPUs available.')) |
| |
| package_group = self.add_mutually_exclusive_group() |
| package_group.add_argument( |
| '--package', action='store_true', dest='package', default=True, |
| help='Package the NDK when done building (default).') |
| package_group.add_argument( |
| '--no-package', action='store_false', dest='package', |
| help='Do not package the NDK when done building.') |
| package_group.add_argument( |
| '--force-package', action='store_true', dest='force_package', |
| help='Force a package even if only building a subset of modules.') |
| |
| test_group = self.add_mutually_exclusive_group() |
| test_group.add_argument( |
| '--test', action='store_true', dest='test', default=True, |
| help=textwrap.dedent("""\ |
| Run host tests when finished. --package is required. Not supported |
| when targeting Windows. |
| """)) |
| test_group.add_argument( |
| '--no-test', action='store_false', dest='test', |
| help='Do not run host tests when finished.') |
| |
| self.add_argument( |
| '--build-number', help='Build number for use in version files.') |
| self.add_argument( |
| '--release', help='Ignored. Temporarily compatibility.') |
| |
| self.add_argument( |
| '--system', choices=('darwin', 'linux', 'windows', 'windows64'), |
| default=build_support.get_default_host(), |
| help='Build for the given OS.') |
| |
| module_group = self.add_mutually_exclusive_group() |
| |
| module_group.add_argument( |
| '--module', choices=sorted(ALL_MODULES), |
| help='NDK modules to build.') |
| |
| module_group.add_argument( |
| '--host-only', action='store_true', |
| help='Skip building target components.') |
| |
| |
| def _invoke_build(script, args): |
| if args is None: |
| args = [] |
| subprocess.check_call([build_support.android_path(script)] + args) |
| |
| |
| def invoke_build(script, args=None): |
| script_path = os.path.join('build/tools', script) |
| _invoke_build(build_support.ndk_path(script_path), args) |
| |
| |
| def invoke_external_build(script, args=None): |
| _invoke_build(build_support.android_path(script), args) |
| |
| |
| def package_ndk(out_dir, dist_dir, args): |
| package_args = common_build_args(out_dir, dist_dir, args) |
| package_args.append(dist_dir) |
| |
| if args.build_number is not None: |
| package_args.append('--build-number={}'.format(args.build_number)) |
| |
| if args.arch is not None: |
| package_args.append('--arch={}'.format(args.arch)) |
| |
| invoke_build('package.py', package_args) |
| |
| |
| def group_by_test(details): |
| """Arranges per-ABI test results into failures by name. |
| |
| Args: |
| details: dict of {abi: {suite_name: [results]}}. |
| |
| Returns: |
| Dict of {test_name: (abi, result)}. |
| """ |
| by_test = {} |
| for abi, suites in details.iteritems(): |
| for suite, test_results in suites.iteritems(): |
| for test in test_results: |
| if test.failed(): |
| name = '.'.join([suite, test.test_name]) |
| if name not in by_test: |
| by_test[name] = [] |
| by_test[name].append((abi, test)) |
| return by_test |
| |
| |
| def make_test_report(details, use_color): |
| """Returns a string containing a test failure report. |
| |
| Args: |
| details: dict of {abi: suite_name: [results]}}. |
| use_color: Print results with color if True. |
| |
| Returns: |
| Test failure report as a string. |
| """ |
| grouped_details = group_by_test(details) |
| lines = [] |
| for test_name, test_failures in grouped_details.iteritems(): |
| lines.append('BEGIN TEST RESULT: ' + test_name) |
| lines.append('=' * 80) |
| for abi, result in test_failures: |
| lines.append('FAILED {}'.format(abi)) |
| lines.append(result.to_string(colored=use_color)) |
| return os.linesep.join(lines) |
| |
| |
| def test_ndk(out_dir, dist_dir, args): |
| """Runs the host-only tests on the just built NDK. |
| |
| Only runs the tests for Clang due to resource constraints. |
| |
| Args: |
| out_dir: Build output directory. |
| dist_dir: Preserved artifact directory. |
| args: Parsed command line arguments. |
| |
| Returns: |
| True if all tests pass, else False. |
| """ |
| # The packaging step extracts all the modules to a known directory for |
| # packaging. This directory is not cleaned up after packaging, so we can |
| # reuse that for testing. |
| test_dir = os.path.join(out_dir, 'android-ndk-{}'.format(config.release)) |
| |
| test_env = dict(os.environ) |
| test_env['NDK'] = test_dir |
| |
| abis = build_support.ALL_ABIS |
| if args.arch is not None: |
| abis = build_support.arch_to_abis(args.arch) |
| |
| use_color = sys.stdin.isatty() and os.name != 'nt' |
| results = collections.OrderedDict() |
| |
| site.addsitedir(os.path.join(test_dir, 'python-packages')) |
| import tests.runners |
| import tests.printers |
| |
| details = {} |
| for abi in abis: |
| test_out_dir = os.path.join(out_dir, 'test', abi) |
| results[abi], details[abi] = tests.runners.run_single_configuration( |
| test_dir, test_out_dir, |
| tests.printers.StdoutPrinter(use_color=use_color), |
| abi, 'clang', skip_run=True) |
| |
| all_pass = all(results.values()) |
| if not all_pass: |
| test_report = make_test_report(details, use_color) |
| print(test_report) |
| log_path = os.path.join(dist_dir, 'logs/build_error.log') |
| with open(log_path, 'a') as error_log: |
| error_log.write(test_report) |
| |
| print('Results:') |
| for abi, result in results.iteritems(): |
| print('{}: {}'.format(abi, 'PASS' if result else 'FAIL')) |
| return all_pass |
| |
| |
| def common_build_args(out_dir, dist_dir, args): |
| build_args = ['--out-dir={}'.format(out_dir)] |
| build_args = ['--dist-dir={}'.format(dist_dir)] |
| build_args.append('--host={}'.format(args.system)) |
| return build_args |
| |
| |
| def install_file(file_name, src_dir, dst_dir): |
| src_file = os.path.join(src_dir, file_name) |
| dst_file = os.path.join(dst_dir, file_name) |
| |
| print('Copying {} to {}...'.format(src_file, dst_file)) |
| if os.path.isdir(src_file): |
| _install_dir(src_file, dst_file) |
| elif os.path.islink(src_file): |
| _install_symlink(src_file, dst_file) |
| else: |
| _install_file(src_file, dst_file) |
| |
| |
| def _install_dir(src_dir, dst_dir): |
| parent_dir = os.path.normpath(os.path.join(dst_dir, '..')) |
| if not os.path.exists(parent_dir): |
| os.makedirs(parent_dir) |
| shutil.copytree(src_dir, dst_dir, symlinks=True) |
| |
| |
| def _install_symlink(src_file, dst_file): |
| dirname = os.path.dirname(dst_file) |
| if not os.path.exists(dirname): |
| os.makedirs(dirname) |
| link_target = os.readlink(src_file) |
| os.symlink(link_target, dst_file) |
| |
| |
| def _install_file(src_file, dst_file): |
| dirname = os.path.dirname(dst_file) |
| if not os.path.exists(dirname): |
| os.makedirs(dirname) |
| # copy2 is just copy followed by copystat (preserves file metadata). |
| shutil.copy2(src_file, dst_file) |
| |
| |
| def build_clang(out_dir, dist_dir, args): |
| print('Building Clang...') |
| invoke_build('build-llvm.py', common_build_args(out_dir, dist_dir, args)) |
| |
| |
| def build_gcc(out_dir, dist_dir, args): |
| print('Building GCC...') |
| build_args = common_build_args(out_dir, dist_dir, args) |
| if args.arch is not None: |
| build_args.append('--arch={}'.format(args.arch)) |
| invoke_build('build-gcc.py', build_args) |
| |
| |
| def build_shader_tools(out_dir, dist_dir, args): |
| print('Building shader tools...') |
| build_args = common_build_args(out_dir, dist_dir, args) |
| invoke_build('build-shader-tools.py', build_args) |
| |
| |
| def build_host_tools(out_dir, dist_dir, args): |
| build_args = common_build_args(out_dir, dist_dir, args) |
| |
| print('Building ndk-stack...') |
| invoke_external_build( |
| 'ndk/sources/host-tools/ndk-stack/build.py', build_args) |
| |
| print('Building ndk-depends...') |
| invoke_external_build( |
| 'ndk/sources/host-tools/ndk-depends/build.py', build_args) |
| |
| print('Building awk...') |
| invoke_external_build( |
| 'ndk/sources/host-tools/nawk-20071023/build.py', build_args) |
| |
| print('Building make...') |
| invoke_external_build( |
| 'ndk/sources/host-tools/make-3.81/build.py', build_args) |
| |
| if args.system in ('windows', 'windows64'): |
| print('Building toolbox...') |
| invoke_external_build( |
| 'ndk/sources/host-tools/toolbox/build.py', build_args) |
| |
| print('Building Python...') |
| invoke_external_build('toolchain/python/build.py', build_args) |
| |
| print('Building GDB...') |
| invoke_external_build('toolchain/gdb/build.py', build_args) |
| |
| print('Building YASM...') |
| invoke_external_build('toolchain/yasm/build.py', build_args) |
| |
| package_host_tools(out_dir, dist_dir, args.system) |
| |
| |
| def package_host_tools(out_dir, dist_dir, host): |
| packages = [ |
| 'gdb-multiarch-7.11', |
| 'ndk-awk', |
| 'ndk-depends', |
| 'ndk-make', |
| 'ndk-python', |
| 'ndk-stack', |
| 'ndk-yasm', |
| ] |
| |
| files = [ |
| 'ndk-gdb', |
| 'ndk-gdb.py', |
| 'ndk-which', |
| ] |
| |
| if host in ('windows', 'windows64'): |
| packages.append('toolbox') |
| files.append('ndk-gdb.cmd') |
| |
| host_tag = build_support.host_to_tag(host) |
| |
| package_names = [p + '-' + host_tag + '.tar.bz2' for p in packages] |
| for package_name in package_names: |
| package_path = os.path.join(out_dir, package_name) |
| subprocess.check_call(['tar', 'xf', package_path, '-C', out_dir]) |
| |
| for f in files: |
| shutil.copy2(f, os.path.join(out_dir, 'host-tools/bin')) |
| |
| build_support.merge_license_files( |
| os.path.join(out_dir, 'host-tools/NOTICE'), [ |
| build_support.android_path('toolchain/gdb/gdb-7.11/COPYING'), |
| build_support.ndk_path('sources/host-tools/nawk-20071023/NOTICE'), |
| build_support.ndk_path('sources/host-tools/ndk-depends/NOTICE'), |
| build_support.ndk_path('sources/host-tools/make-3.81/COPYING'), |
| build_support.android_path( |
| 'toolchain/python/Python-2.7.5/LICENSE'), |
| build_support.ndk_path('sources/host-tools/ndk-stack/NOTICE'), |
| build_support.ndk_path('sources/host-tools/toolbox/NOTICE'), |
| build_support.android_path('toolchain/yasm/COPYING'), |
| build_support.android_path('toolchain/yasm/BSD.txt'), |
| build_support.android_path('toolchain/yasm/Artistic.txt'), |
| build_support.android_path('toolchain/yasm/GNU_GPL-2.0'), |
| build_support.android_path('toolchain/yasm/GNU_LGPL-2.0'), |
| ]) |
| |
| package_name = 'host-tools-' + host_tag |
| path = os.path.join(out_dir, 'host-tools') |
| build_support.make_package(package_name, path, dist_dir) |
| |
| |
| def build_gdbserver(out_dir, dist_dir, args): |
| print('Building gdbserver...') |
| build_args = common_build_args(out_dir, dist_dir, args) |
| if args.arch is not None: |
| build_args.append('--arch={}'.format(args.arch)) |
| invoke_build('build-gdbserver.py', build_args) |
| |
| |
| def _build_stl(out_dir, dist_dir, args, stl): |
| build_args = common_build_args(out_dir, dist_dir, args) |
| if args.arch is not None: |
| build_args.append('--arch={}'.format(args.arch)) |
| script = 'ndk/sources/cxx-stl/{}/build.py'.format(stl) |
| invoke_external_build(script, build_args) |
| |
| |
| def build_gnustl(out_dir, dist_dir, args): |
| print('Building gnustl...') |
| _build_stl(out_dir, dist_dir, args, 'gnu-libstdc++') |
| |
| |
| def build_libcxx(out_dir, dist_dir, args): |
| print('Building libc++...') |
| _build_stl(out_dir, dist_dir, args, 'llvm-libc++') |
| |
| |
| def build_stlport(out_dir, dist_dir, args): |
| print('Building stlport...') |
| _build_stl(out_dir, dist_dir, args, 'stlport') |
| |
| |
| def build_platforms(out_dir, dist_dir, args): |
| print('Building platforms...') |
| build_args = common_build_args(out_dir, dist_dir, args) |
| invoke_build('build-platforms.py', build_args) |
| |
| |
| def build_libshaderc(_, dist_dir, __): |
| print('Building libshaderc...') |
| shaderc_root_dir = build_support.android_path('external/shaderc') |
| |
| copies = [ |
| { |
| 'source_dir': os.path.join(shaderc_root_dir, 'shaderc'), |
| 'dest_dir': 'shaderc', |
| 'files': [ |
| 'Android.mk', 'libshaderc/Android.mk', |
| 'libshaderc_util/Android.mk', |
| 'third_party/Android.mk', |
| 'utils/update_build_version.py', |
| 'CHANGES', |
| ], |
| 'dirs': [ |
| 'libshaderc/include', 'libshaderc/src', |
| 'libshaderc_util/include', 'libshaderc_util/src', |
| ], |
| }, |
| { |
| 'source_dir': os.path.join(shaderc_root_dir, 'spirv-tools'), |
| 'dest_dir': 'shaderc/third_party/spirv-tools', |
| 'files': [ |
| 'utils/generate_grammar_tables.py', |
| 'utils/update_build_version.py', |
| 'CHANGES', |
| ], |
| 'dirs': ['include', 'source'], |
| }, |
| { |
| 'source_dir': os.path.join(shaderc_root_dir, 'spirv-headers'), |
| 'dest_dir': |
| 'shaderc/third_party/spirv-tools/external/spirv-headers', |
| 'dirs': ['include'], |
| 'files': [ |
| 'include/spirv/1.0/spirv.py', |
| 'include/spirv/1.1/spirv.py' |
| ], |
| }, |
| { |
| 'source_dir': os.path.join(shaderc_root_dir, 'glslang'), |
| 'dest_dir': 'shaderc/third_party/glslang', |
| 'files': ['glslang/OSDependent/osinclude.h'], |
| 'dirs': [ |
| 'SPIRV', |
| 'OGLCompilersDLL', |
| 'glslang/GenericCodeGen', |
| 'hlsl', |
| 'glslang/Include', |
| 'glslang/MachineIndependent', |
| 'glslang/OSDependent/Unix', |
| 'glslang/Public', |
| ], |
| }, |
| ] |
| |
| default_ignore_patterns = shutil.ignore_patterns( |
| "*CMakeLists.txt", |
| "*.py", |
| "*test.h", |
| "*test.cc") |
| |
| temp_dir = tempfile.mkdtemp() |
| shaderc_path = os.path.join(temp_dir, 'shaderc') |
| try: |
| for properties in copies: |
| source_dir = properties['source_dir'] |
| dest_dir = os.path.join(temp_dir, properties['dest_dir']) |
| for d in properties['dirs']: |
| src = os.path.join(source_dir, d) |
| dst = os.path.join(dest_dir, d) |
| print(src, " -> ", dst) |
| shutil.copytree(src, dst, |
| ignore=default_ignore_patterns) |
| for f in properties['files']: |
| print(source_dir, ':', dest_dir, ":", f) |
| # Only copy if the source file exists. That way |
| # we can update this script in anticipation of |
| # source files yet-to-come. |
| if os.path.exists(os.path.join(source_dir, f)): |
| install_file(f, source_dir, dest_dir) |
| else: |
| print(source_dir, ':', dest_dir, ":", f, "SKIPPED") |
| |
| shaderc_shaderc_dir = os.path.join(shaderc_root_dir, 'shaderc') |
| build_support.merge_license_files( |
| os.path.join(shaderc_path, 'NOTICE'), [ |
| os.path.join(shaderc_shaderc_dir, 'LICENSE'), |
| os.path.join(shaderc_shaderc_dir, |
| 'third_party', |
| 'LICENSE.spirv-tools'), |
| os.path.join(shaderc_shaderc_dir, |
| 'third_party', |
| 'LICENSE.glslang')]) |
| build_support.make_package('shaderc', shaderc_path, dist_dir) |
| finally: |
| shutil.rmtree(temp_dir) |
| |
| |
| def build_cpufeatures(_, dist_dir, __): |
| path = build_support.ndk_path('sources/android/cpufeatures') |
| build_support.make_package('cpufeatures', path, dist_dir) |
| |
| |
| def build_native_app_glue(_, dist_dir, __): |
| path = build_support.ndk_path('sources/android/native_app_glue') |
| build_support.make_package('native_app_glue', path, dist_dir) |
| |
| |
| def build_ndk_helper(_, dist_dir, __): |
| path = build_support.ndk_path('sources/android/ndk_helper') |
| build_support.make_package('ndk_helper', path, dist_dir) |
| |
| |
| def build_gtest(_, dist_dir, __): |
| path = build_support.ndk_path('sources/third_party/googletest') |
| build_support.make_package('gtest', path, dist_dir) |
| |
| |
| def build_vulkan(out_dir, dist_dir, args): |
| print('Constructing Vulkan validation layer source...') |
| vulkan_root_dir = build_support.android_path( |
| 'external/vulkan-validation-layers') |
| |
| copies = [ |
| { |
| 'source_dir': vulkan_root_dir, |
| 'dest_dir': 'vulkan/src', |
| 'files': [ |
| 'vk-generate.py', |
| 'vk_helper.py', |
| 'vk-layer-generate.py', |
| 'generator.py', |
| 'genvk.py', |
| 'reg.py', |
| 'source_line_info.py', |
| 'vulkan.py', |
| 'vk.xml' |
| ], |
| 'dirs': [ |
| 'layers', 'include', 'tests', 'common', 'libs' |
| ], |
| }, |
| { |
| 'source_dir': vulkan_root_dir + '/loader', |
| 'dest_dir': 'vulkan/src/loader', |
| 'files': [ |
| 'vk_loader_platform.h', |
| 'vk_loader_layer.h' |
| ], |
| 'dirs': [], |
| } |
| ] |
| |
| default_ignore_patterns = shutil.ignore_patterns( |
| "*CMakeLists.txt", |
| "*test.cc", |
| "linux", |
| "windows") |
| |
| vulkan_path = os.path.join(out_dir, 'vulkan/src') |
| for properties in copies: |
| source_dir = properties['source_dir'] |
| dest_dir = os.path.join(out_dir, properties['dest_dir']) |
| for d in properties['dirs']: |
| src = os.path.join(source_dir, d) |
| dst = os.path.join(dest_dir, d) |
| shutil.rmtree(dst, True) |
| shutil.copytree(src, dst, |
| ignore=default_ignore_patterns) |
| for f in properties['files']: |
| install_file(f, source_dir, dest_dir) |
| |
| # Copy Android build components |
| print('Copying Vulkan build components...') |
| src = os.path.join(vulkan_root_dir, 'build-android') |
| dst = os.path.join(vulkan_path, 'build-android') |
| shutil.rmtree(dst, True) |
| shutil.copytree(src, dst, ignore=default_ignore_patterns) |
| print('Copying finished') |
| |
| # Copy binary validation layer libraries |
| print('Copying Vulkan binary validation layers...') |
| src = build_support.android_path('prebuilts/ndk/vulkan-validation-layers') |
| dst = os.path.join(vulkan_path, 'build-android/jniLibs') |
| shutil.rmtree(dst, True) |
| shutil.copytree(src, dst, ignore=default_ignore_patterns) |
| print('Copying finished') |
| |
| build_support.merge_license_files( |
| os.path.join(vulkan_path, 'NOTICE'), |
| [os.path.join(vulkan_root_dir, 'LICENSE.txt')]) |
| |
| build_cmd = [ |
| 'bash', vulkan_path + '/build-android/android-generate.sh' |
| ] |
| print('Generating generated layers...') |
| subprocess.check_call(build_cmd) |
| print('Generation finished') |
| |
| build_args = common_build_args(out_dir, dist_dir, args) |
| if args.arch is not None: |
| build_args.append('--arch={}'.format(args.arch)) |
| build_args.append('--no-symbols') |
| |
| # TODO: Verify source packaged properly |
| print('Packaging Vulkan source...') |
| src = os.path.join(out_dir, 'vulkan') |
| build_support.make_package('vulkan', src, dist_dir) |
| print('Packaging Vulkan source finished') |
| |
| |
| def build_ndk_build(_, dist_dir, __): |
| path = build_support.ndk_path('build') |
| build_support.make_package('ndk-build', path, dist_dir) |
| |
| |
| def build_python_packages(_, dist_dir, __): |
| # Stage the files in a temporary directory to make things easier. |
| temp_dir = tempfile.mkdtemp() |
| try: |
| path = os.path.join(temp_dir, 'python-packages') |
| shutil.copytree( |
| build_support.android_path('development/python-packages'), path) |
| build_support.make_package('python-packages', path, dist_dir) |
| finally: |
| shutil.rmtree(temp_dir) |
| |
| |
| def build_gabixx(_out_dir, dist_dir, _args): |
| print('Building gabi++...') |
| path = build_support.ndk_path('sources/cxx-stl/gabi++') |
| build_support.make_package('gabixx', path, dist_dir) |
| |
| |
| def build_system_stl(_out_dir, dist_dir, _args): |
| print('Building system-stl...') |
| path = build_support.ndk_path('sources/cxx-stl/system') |
| build_support.make_package('system-stl', path, dist_dir) |
| |
| |
| def build_libandroid_support(_out_dir, dist_dir, _args): |
| print('Building libandroid_support...') |
| path = build_support.ndk_path('sources/android/support') |
| build_support.make_package('libandroid_support', path, dist_dir) |
| |
| |
| def build_libcxxabi(_out_dir, dist_dir, _args): |
| print('Building libc++abi...') |
| path = build_support.android_path('external/libcxxabi') |
| build_support.make_package('libcxxabi', path, dist_dir) |
| |
| |
| def build_simpleperf(out_dir, dist_dir, _args): |
| print('Building simpleperf...') |
| install_dir = os.path.join(out_dir, 'simpleperf') |
| if os.path.exists(install_dir): |
| shutil.rmtree(install_dir) |
| os.makedirs(install_dir) |
| |
| simpleperf_path = build_support.android_path('prebuilts/simpleperf') |
| shutil.copytree(os.path.join(simpleperf_path, 'android'), |
| os.path.join(install_dir, 'android')) |
| |
| shutil.copy2( |
| os.path.join(simpleperf_path, 'simpleperf_report.py'), install_dir) |
| shutil.copy2(os.path.join(simpleperf_path, 'README.md'), install_dir) |
| shutil.copy2(os.path.join(simpleperf_path, 'NOTICE'), install_dir) |
| |
| build_support.make_package('simpleperf', install_dir, dist_dir) |
| |
| |
| def launch_build(build_name, build_func, out_dir, dist_dir, args, log_dir): |
| log_path = os.path.join(log_dir, build_name) + '.log' |
| tee = subprocess.Popen(["tee", log_path], stdin=subprocess.PIPE) |
| try: |
| os.dup2(tee.stdin.fileno(), sys.stdout.fileno()) |
| os.dup2(tee.stdin.fileno(), sys.stderr.fileno()) |
| |
| try: |
| build_func(out_dir, dist_dir, args) |
| return build_name, True, log_path |
| except Exception: # pylint: disable=broad-except |
| traceback.print_exc() |
| return build_name, False, log_path |
| finally: |
| tee.terminate() |
| tee.wait() |
| |
| |
| def main(): |
| total_timer = build_support.Timer() |
| total_timer.start() |
| |
| # It seems the build servers run us in our own session, in which case we |
| # get EPERM from `setpgrp`. No need to call this in that case because we |
| # will already be the process group leader. |
| if os.getpid() != os.getsid(os.getpid()): |
| os.setpgrp() |
| |
| parser = ArgParser() |
| args = parser.parse_args() |
| |
| if args.module is None: |
| modules = ALL_MODULES |
| else: |
| modules = {args.module} |
| |
| if args.host_only: |
| modules = { |
| 'clang', |
| 'gcc', |
| 'host-tools', |
| 'ndk-build', |
| 'python-packages', |
| 'shader_tools', |
| 'simpleperf', |
| } |
| |
| required_package_modules = ALL_MODULES |
| have_required_modules = required_package_modules <= modules |
| if (args.package and have_required_modules) or args.force_package: |
| do_package = True |
| else: |
| do_package = False |
| |
| # TODO(danalbert): wine? |
| # We're building the Windows packages from Linux, so we can't actually run |
| # any of the tests from here. |
| if args.system.startswith('windows') or not do_package: |
| args.test = False |
| |
| # Disable buffering on stdout so the build output doesn't hide all of our |
| # "Building..." messages. |
| sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0) |
| |
| os.chdir(os.path.dirname(os.path.realpath(__file__))) |
| |
| # Set ANDROID_BUILD_TOP. |
| if 'ANDROID_BUILD_TOP' not in os.environ: |
| os.environ['ANDROID_BUILD_TOP'] = os.path.realpath('..') |
| |
| out_dir = build_support.get_out_dir() |
| dist_dir = build_support.get_dist_dir(out_dir) |
| tmp_dir = os.path.join(out_dir, 'build') |
| if os.path.exists(tmp_dir): |
| shutil.rmtree(tmp_dir) |
| os.mkdir(tmp_dir) |
| |
| os.environ['TMPDIR'] = tmp_dir |
| |
| print('Cleaning up...') |
| invoke_build('dev-cleanup.sh') |
| |
| module_builds = collections.OrderedDict([ |
| ('clang', build_clang), |
| ('cpufeatures', build_cpufeatures), |
| ('gabi++', build_gabixx), |
| ('gcc', build_gcc), |
| ('gdbserver', build_gdbserver), |
| ('gnustl', build_gnustl), |
| ('gtest', build_gtest), |
| ('host-tools', build_host_tools), |
| ('libandroid_support', build_libandroid_support), |
| ('libc++', build_libcxx), |
| ('libc++abi', build_libcxxabi), |
| ('libshaderc', build_libshaderc), |
| ('native_app_glue', build_native_app_glue), |
| ('ndk-build', build_ndk_build), |
| ('ndk_helper', build_ndk_helper), |
| ('platforms', build_platforms), |
| ('python-packages', build_python_packages), |
| ('shader_tools', build_shader_tools), |
| ('simpleperf', build_simpleperf), |
| ('stlport', build_stlport), |
| ('system-stl', build_system_stl), |
| ('vulkan', build_vulkan), |
| ]) |
| |
| print('Building modules: {}'.format(' '.join(modules))) |
| print('Machine has {} CPUs'.format(multiprocessing.cpu_count())) |
| |
| log_dir = os.path.join(dist_dir, 'logs') |
| if not os.path.exists(log_dir): |
| os.makedirs(log_dir) |
| |
| build_timer = build_support.Timer() |
| with build_timer: |
| workqueue = ndk.workqueue.WorkQueue(args.jobs) |
| try: |
| for name, build_func in module_builds.iteritems(): |
| if name in modules: |
| workqueue.add_task( |
| launch_build, name, build_func, out_dir, dist_dir, |
| args, log_dir) |
| |
| while not workqueue.finished(): |
| build_name, result, log_path = workqueue.get_result() |
| if result: |
| print('BUILD SUCCESSFUL: ' + build_name) |
| else: |
| # Kill all the children so the error we print appears last. |
| workqueue.terminate() |
| workqueue.join() |
| |
| print('BUILD FAILED: ' + build_name) |
| with open(log_path, 'r') as log_file: |
| contents = log_file.read() |
| print(contents) |
| |
| # The build server has a build_error.log file that is |
| # supposed to be the short log of the failure that |
| # stopped the build. Append our failing log to that. |
| build_error_log = os.path.join( |
| dist_dir, 'logs/build_error.log') |
| with open(build_error_log, 'a') as error_log: |
| error_log.write('\n') |
| error_log.write(contents) |
| sys.exit(1) |
| finally: |
| workqueue.terminate() |
| workqueue.join() |
| |
| package_timer = build_support.Timer() |
| with package_timer: |
| if do_package: |
| package_ndk(out_dir, dist_dir, args) |
| |
| good = True |
| test_timer = build_support.Timer() |
| with test_timer: |
| if args.test: |
| good = test_ndk(out_dir, dist_dir, args) |
| print() # Blank line between test results and timing data. |
| |
| total_timer.finish() |
| |
| print('Finished {}'.format('successfully' if good else 'unsuccessfully')) |
| print('Build: {}'.format(build_timer.duration)) |
| print('Packaging: {}'.format(package_timer.duration)) |
| print('Testing: {}'.format(test_timer.duration)) |
| print('Total: {}'.format(total_timer.duration)) |
| |
| sys.exit(not good) |
| |
| |
| if __name__ == '__main__': |
| main() |