update gyp_crashpad_android.py

This patch updates gyp_crashpad_android.py to function with NDK r20,
removes the requirement to generate a standalone toolchain, and updates
documentation on building for Android.

Also some gyp build fixes.

Change-Id: Ide338417ab2a21eca7a4bf42c1fb834e5639c186
Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1798746
Reviewed-by: Mark Mentovai <mark@chromium.org>
Commit-Queue: Joshua Peraza <jperaza@chromium.org>
This commit is contained in:
Joshua Peraza 2019-09-11 11:30:22 -07:00 committed by Commit Bot
parent 06fdbdecdc
commit e97cf7b29c
5 changed files with 44 additions and 107 deletions

View File

@ -28,82 +28,45 @@ 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('--arch', required=True, help='Target architecture')
parser.add_argument('--api-level', required=True, help='Target API level')
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)
ndk_bin_dir = os.path.join(parsed.ndk,
'toolchains',
'llvm',
'prebuilt',
'linux-x86_64',
'bin')
if not os.path.exists(ndk_bin_dir):
parser.error("missing toolchain")
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',
ARCH_TO_ARCH_TRIPLET = {
'arm': 'armv7a-linux-androideabi',
'arm64': 'aarch64-linux-android',
'ia32': 'i686-linux-android',
'x64': 'x86_64-linux-android',
}
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_prefix = ARCH_TO_ARCH_TRIPLET[parsed.arch] + parsed.api_level
os.environ['CC_target'] = os.path.join(ndk_bin_dir, clang_prefix + '-clang')
os.environ['CXX_target'] = os.path.join(ndk_bin_dir, clang_prefix + '-clang++')
clang_path = os.path.join(ndk_bin_dir, 'clang')
extra_args = []
extra_args = ['-D', 'android_api_level=' + parsed.api_level]
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__
# isnt 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 wont mention __ANDROID_API__, but the standalone toolchains
# <android/api-level.h> will #define it for both Clang and GCC.
#
# android_api_level is extracted in this manner even when compiling with Clang
# so that its available for use in GYP conditions that need to test the API
# level, but beware that itll 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')
# ARM only includes 'v7a' in the tool prefix for clang
tool_prefix = ('arm-linux-androideabi' if parsed.arch == 'arm'
else ARCH_TO_ARCH_TRIPLET[parsed.arch])
for tool in ('ar', 'nm', 'readelf'):
os.environ['%s_target' % tool.upper()] = (
os.path.join(ndk_bin_dir, '%s-%s' % (arch_triplet, tool)))
os.path.join(ndk_bin_dir, '%s-%s' % (tool_prefix, tool)))
return gyp_crashpad.main(
['-D', 'OS=android',
'-D', 'target_arch=%s' % arch,
'-D', 'clang=%d' % (1 if parsed.compiler == 'clang' else 0),
'-D', 'target_arch=%s' % parsed.arch,
'-D', 'clang=1',
'-f', 'ninja-android'] +
extra_args +
extra_command_line_args)

View File

@ -135,66 +135,38 @@ target_sysroot = "//third_party/linux/sysroot"
### Android
Crashpads Android port is in its early stages. This build relies on
cross-compilation. Its possible to develop Crashpad for Android on any platform
that the [Android NDK (Native Development
Kit)](https://developer.android.com/ndk/) runs on.
This build relies on cross-compilation. Its possible to develop Crashpad for
Android on any platform that the [Android NDK (Native Development Kit)]
(https://developer.android.com/ndk/) runs on.
If its not already present on your system, [download the NDK package for your
system](https://developer.android.com/ndk/downloads/) and expand it to a
suitable location. These instructions assume that its been expanded to
`~/android-ndk-r16`.
To build Crashpad, portions of the NDK must be reassembled into a [standalone
toolchain](https://developer.android.com/ndk/guides/standalone_toolchain.html).
This is a repackaged subset of the NDK suitable for cross-compiling for a single
Android architecture (such as `arm`, `arm64`, `x86`, and `x86_64`) targeting a
specific [Android API
level](https://source.android.com/source/build-numbers.html). The standalone
toolchain only needs to be built from the NDK one time for each set of options
desired. To build a standalone toolchain targeting 64-bit ARM and API level 21
(Android 5.0 “Lollipop”), run:
```
$ cd ~
$ python android-ndk-r16/build/tools/make_standalone_toolchain.py \
--arch=arm64 --api=21 --install-dir=android-ndk-r16_arm64_api21
```
`~/android-ndk-r20`.
Note that Chrome uses Android API level 21 for 64-bit platforms and 16 for
32-bit platforms. See Chromes
[`build/config/android/config.gni`](https://chromium.googlesource.com/chromium/src/+/master/build/config/android/config.gni)
which sets `_android_api_level` and `_android64_api_level`.
To configure a Crashpad build for Android using the standalone toolchain
assembled above, use `gyp_crashpad_android.py`. This script is a wrapper for
`gyp_crashpad.py` that sets several environment variables directing the build to
the standalone toolchain, and several GYP options to identify an Android build.
This must be done after any `gclient sync`, or instead of any `gclient runhooks`
operation.
To configure a Crashpad build for Android use `gyp_crashpad_android.py`. This
script is a wrapper for `gyp_crashpad.py` that sets several environment
variables directing the build to the toolchain, and several GYP options to
identify an Android build. This must be done after any `gclient sync`, or
instead of any `gclient runhooks` operation.
```
$ cd ~/crashpad/crashpad
$ python build/gyp_crashpad_android.py \
--ndk ~/android-ndk-r16_arm64_api21 \
--generator-output out/android_arm64_api21
python build/gyp_crashpad_android.py \
--ndk ~/usr/lib/android-ndk-r20 --arch arm64 --api-level 21 \
--generator-output=out/android_arm64_api21 \
```
`gyp_crashpad_android.py` detects the build type based on the characteristics of
the standalone toolchain given in its `--ndk` argument.
`gyp_crashpad_android.py` sets the build up to use Clang by default. Its also
possible to use GCC by providing the `--compiler=gcc` argument to
`gyp_crashpad_android.py`.
The Android port is incomplete, but targets known to be working include
`crashpad_test`, `crashpad_util`, and their tests. This list will grow over
time. To build, direct `ninja` to the specific `out` directory chosen by the
To build, direct `ninja` to the specific `out` directory chosen by the
`--generator-output` argument to `gyp_crashpad_android.py`.
```
$ ninja -C out/android_arm64_api21/out/Debug \
crashpad_test_test crashpad_util_test
$ ninja -C out/android_arm64_api21/out/Debug all
```
## Testing

View File

@ -39,6 +39,8 @@
'crash_report_upload_thread.h',
'handler_main.cc',
'handler_main.h',
'linux/capture_snapshot.cc',
'linux/capture_snapshot.h',
'linux/crash_report_exception_handler.cc',
'linux/crash_report_exception_handler.h',
'linux/exception_handler_server.cc',

View File

@ -395,8 +395,8 @@
['OS=="linux" or OS=="android"', {
'sources': [
'net/http_transport_socket.cc',
'util/process_memory_sanitized.cc',
'util/process_memory_sanitized.h',
'process/process_memory_sanitized.cc',
'process/process_memory_sanitized.h',
],
}, { # else: OS!="linux"
'sources!': [

View File

@ -156,7 +156,7 @@
}],
['OS=="linux" or OS=="android"', {
'sources': [
'util/process_memory_sanitized_test.cc',
'process/process_memory_sanitized_test.cc',
],
}],
['OS!="linux" and OS!="android"', {