#!/usr/bin/env python # coding: utf-8 # Copyright 2017 The Crashpad Authors. All rights reserved. # # 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. import argparse import glob import gyp_crashpad import os import re import subprocess import sys def main(args): parser = argparse.ArgumentParser( description='Set up an Android cross build', epilog='Additional arguments will be passed to gyp_crashpad.py.') parser.add_argument('--ndk', required=True, help='Standalone NDK toolchain') parser.add_argument('--compiler', default='clang', choices=('clang', 'gcc'), help='The compiler to use, clang by default') (parsed, extra_command_line_args) = parser.parse_known_args(args) NDK_ERROR=( 'NDK must be a valid standalone NDK toolchain.\n' + 'See https://developer.android.com/ndk/guides/standalone_toolchain.html') arch_dirs = glob.glob(os.path.join(parsed.ndk, '*-linux-android*')) if len(arch_dirs) != 1: parser.error(NDK_ERROR) arch_triplet = os.path.basename(arch_dirs[0]) ARCH_TRIPLET_TO_ARCH = { 'arm-linux-androideabi': 'arm', 'aarch64-linux-android': 'arm64', 'i686-linux-android': 'ia32', 'x86_64-linux-android': 'x64', 'mipsel-linux-android': 'mips', 'mips64el-linux-android': 'mips64', } if arch_triplet not in ARCH_TRIPLET_TO_ARCH: parser.error(NDK_ERROR) arch = ARCH_TRIPLET_TO_ARCH[arch_triplet] ndk_bin_dir = os.path.join(parsed.ndk, 'bin') clang_path = os.path.join(ndk_bin_dir, 'clang') extra_args = [] if parsed.compiler == 'clang': os.environ['CC_target'] = clang_path os.environ['CXX_target'] = os.path.join(ndk_bin_dir, 'clang++') elif parsed.compiler == 'gcc': os.environ['CC_target'] = os.path.join(ndk_bin_dir, '%s-gcc' % arch_triplet) os.environ['CXX_target'] = os.path.join(ndk_bin_dir, '%s-g++' % arch_triplet) # Unlike the Clang build, when using GCC with unified headers, __ANDROID_API__ # isn’t set automatically and must be pushed in to the build. Fish the correct # value out of the Clang wrapper script. If deprecated headers are in use, the # Clang wrapper won’t mention __ANDROID_API__, but the standalone toolchain’s # will #define it for both Clang and GCC. # # android_api_level is extracted in this manner even when compiling with Clang # so that it’s available for use in GYP conditions that need to test the API # level, but beware that it’ll only be available when unified headers are in # use. # # Unified headers are the way of the future, according to # https://android.googlesource.com/platform/ndk/+/ndk-r14/CHANGELOG.md and # https://android.googlesource.com/platform/ndk/+/master/docs/UnifiedHeaders.md. # Traditional (deprecated) headers have been removed entirely as of NDK r16. # https://android.googlesource.com/platform/ndk/+/ndk-release-r16/CHANGELOG.md. with open(clang_path, 'r') as file: clang_script_contents = file.read() matches = re.finditer(r'\s-D__ANDROID_API__=([\d]+)\s', clang_script_contents) match = next(matches, None) if match: android_api = int(match.group(1)) extra_args.extend(['-D', 'android_api_level=%d' % android_api]) if next(matches, None): raise AssertionError('__ANDROID_API__ defined too many times') for tool in ('ar', 'nm', 'readelf'): os.environ['%s_target' % tool.upper()] = ( os.path.join(ndk_bin_dir, '%s-%s' % (arch_triplet, tool))) return gyp_crashpad.main( ['-D', 'OS=android', '-D', 'target_arch=%s' % arch, '-D', 'clang=%d' % (1 if parsed.compiler == 'clang' else 0), '-f', 'ninja-android'] + extra_args + extra_command_line_args) if __name__ == '__main__': sys.exit(main(sys.argv[1:]))