gecko-dev/build/moz.configure/android-ndk.configure
Jim Chen b3c3de5de5 Bug 1428182 - 1. Support unified headers for Android builds; r=nalexander
NDK headers are grouped into a "sysroot" directory, which doesn't
contain architecture-specific bits, and a "system" directory, which
contains only the architecture-specific bits. Previously, both
directories are the same, under platforms/android-*/arch-*/. However,
with unified headers in NDK r16, the two are different, so we need to
support that in the Android build scripts.

Unified headers also rely on the build system defining the
__ANDROID_API__ macro, so we add support for that as well.

MozReview-Commit-ID: 9zBNQC3BRFl

--HG--
extra : rebase_source : 9ded282343df64d9cc4abcf7d7c6b03ac3423ff0
2018-01-30 14:08:22 -05:00

403 lines
13 KiB
Python

# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
js_option('--with-android-ndk', nargs=1,
help='location where the Android NDK can be found')
js_option('--with-android-toolchain', nargs=1,
help='location of the Android toolchain')
option('--with-android-googlevr-sdk', nargs=1,
help='location of the Android GoogleVR SDK')
@depends(target)
def min_android_version(target):
if target.cpu in ['aarch64', 'x86_64', 'mips64']:
# 64-bit support was added in API 21.
return '21'
return '9'
js_option('--with-android-version',
nargs=1,
help='android platform version',
default=min_android_version)
@depends('--with-android-version', min_android_version, '--help')
@imports(_from='__builtin__', _import='ValueError')
def android_version(value, min_version, _):
if not value:
# Someone has passed --without-android-version.
die('--with-android-version cannot be disabled.')
try:
version = int(value[0])
except ValueError:
die('--with-android-version expects an integer value')
if version < int(min_version):
die('--with-android-version must be at least %s (got %s)',
min_version, value[0])
return version
add_old_configure_assignment('android_version', android_version)
@depends('--with-android-ndk', build_project, '--help')
def ndk(value, build_project, help):
if help:
return
if build_project == 'mobile/android' and not value:
die('You must specify --with-android-ndk=/path/to/ndk when '
'building mobile/android')
if value:
return value[0]
set_config('ANDROID_NDK', ndk)
add_old_configure_assignment('android_ndk', ndk)
@depends(ndk)
@checking('for android ndk version')
@imports(_from='__builtin__', _import='open')
def ndk_version(ndk):
if not ndk:
# Building 'js/src' for non-Android.
return
with open(os.path.join(ndk, 'source.properties'), 'r') as f:
for line in f:
if not line.startswith('Pkg.Revision'):
continue
(_, version) = line.split('=')
if version:
return version.strip()
die('Unexpected Pkg.Revision line in source.properties')
die('Cannot determine NDK version from source.properties')
@depends(ndk_version)
def ndk_major_version(ndk_version):
if not ndk_version:
# Building 'js/src' for non-Android.
return
(major, minor, revision) = ndk_version.split('.')
if major:
return major
die('Unexpected NDK version string: ' + ndk_version)
set_config('ANDROID_NDK_MAJOR_VERSION', ndk_major_version)
@depends(ndk_version)
def ndk_minor_version(ndk_version):
if not ndk_version:
# Building 'js/src' for non-Android.
return
(major, minor, revision) = ndk_version.split('.')
if minor:
return minor
die('Unexpected NDK version string: ' + ndk_version)
set_config('ANDROID_NDK_MINOR_VERSION', ndk_minor_version)
@depends(target, android_version, ndk, '--help')
@checking('for android platform directory')
@imports(_from='os.path', _import='isdir')
def android_platform(target, android_version, ndk, _):
if target.os != 'Android':
return
if 'mips' in target.cpu:
target_dir_name = 'mips'
elif 'aarch64' == target.cpu:
target_dir_name = 'arm64'
else:
target_dir_name = target.cpu
# Not all Android releases have their own platform release. We use
# the next lower platform version in these cases.
if android_version in (11, 10):
platform_version = 9
elif android_version in (20, 22):
platform_version = android_version - 1
else:
platform_version = android_version
platform_dir = os.path.join(ndk,
'platforms',
'android-%s' % platform_version,
'arch-%s' % target_dir_name)
if not isdir(platform_dir):
die("Android platform directory not found. With the current "
"configuration, it should be in %s" % platform_dir)
return platform_dir
add_old_configure_assignment('android_platform', android_platform)
@depends(android_platform, ndk, target, '--help')
@checking('for android sysroot directory')
@imports(_from='os.path', _import='isdir')
def android_sysroot(android_platform, ndk, target, _):
if target.os != 'Android':
return
# NDK r15 has both unified and non-unified headers, but we only support
# non-unified for that NDK, so look for that first.
search_dirs = [
# (<if this directory exists>, <return this directory>)
(os.path.join(android_platform, 'usr', 'include'), android_platform),
(os.path.join(ndk, 'sysroot'), os.path.join(ndk, 'sysroot')),
]
for test_dir, sysroot_dir in search_dirs:
if isdir(test_dir):
return sysroot_dir
die("Android sysroot directory not found in %s." %
str([sysroot_dir for test_dir, sysroot_dir in search_dirs]))
add_old_configure_assignment('android_sysroot', android_sysroot)
@depends(android_platform, ndk, target, '--help')
@checking('for android system directory')
@imports(_from='os.path', _import='isdir')
def android_system(android_platform, ndk, target, _):
if target.os != 'Android':
return
# NDK r15 has both unified and non-unified headers, but we only support
# non-unified for that NDK, so look for that first.
search_dirs = [
os.path.join(android_platform, 'usr', 'include'),
os.path.join(ndk, 'sysroot', 'usr', 'include', target.toolchain),
]
for system_dir in search_dirs:
if isdir(system_dir):
return system_dir
die("Android system directory not found in %s." % str(search_dirs))
add_old_configure_assignment('android_system', android_system)
@depends(target, host, ndk, '--with-android-toolchain', '--help')
@checking('for the Android toolchain directory', lambda x: x or 'not found')
@imports(_from='os.path', _import='isdir')
@imports(_from='mozbuild.shellutil', _import='quote')
def android_toolchain(target, host, ndk, toolchain, _):
if not ndk:
return
if toolchain:
return toolchain[0]
else:
if target.cpu == 'arm' and target.endianness == 'little':
target_base = 'arm-linux-androideabi'
elif target.cpu == 'x86':
target_base = 'x86'
elif target.cpu == 'mips32' and target.endianness == 'little':
target_base = 'mipsel-linux-android'
elif target.cpu == 'aarch64' and target.endianness == 'little':
target_base = 'aarch64-linux-android'
else:
die('Target cpu is not supported.')
toolchain_format = '%s/toolchains/%s-4.9/prebuilt/%s-%s'
toolchain = toolchain_format % (ndk, target_base,
host.kernel.lower(), host.cpu)
log.debug('Trying %s' % quote(toolchain))
if not isdir(toolchain) and host.cpu == 'x86_64':
toolchain = toolchain_format % (ndk, target_base, version,
host.kernel.lower(), 'x86')
log.debug('Trying %s' % quote(toolchain))
if isdir(toolchain):
return toolchain
die('You have to specify --with-android-toolchain='
'/path/to/ndk/toolchain.')
set_config('ANDROID_TOOLCHAIN', android_toolchain)
@depends(target)
def android_toolchain_prefix_base(target):
if target.cpu == 'x86':
# Ideally, the --target should just have the right x86 variant
# in the first place.
return 'i686-linux-android'
return target.toolchain
option(env='STLPORT_CPPFLAGS',
nargs=1,
help='Options compiler should pass for standard C++ library')
@depends('STLPORT_CPPFLAGS', ndk, '--help')
@imports(_from='os.path', _import='isdir')
def stlport_cppflags(value, ndk, _):
if value and len(value):
return value.split()
if not ndk:
return
ndk_base = os.path.join(ndk, 'sources', 'cxx-stl')
cxx_base = os.path.join(ndk_base, 'llvm-libc++')
cxx_include = os.path.join(cxx_base, 'libcxx', 'include')
cxxabi_base = os.path.join(ndk_base, 'llvm-libc++abi')
cxxabi_include = os.path.join(cxxabi_base, 'libcxxabi', 'include')
if not isdir(cxx_include):
# NDK r13 removes the inner "libcxx" directory.
cxx_include = os.path.join(cxx_base, 'include')
if not isdir(cxx_include):
die("Couldn't find path to libc++ includes in the android ndk")
if not isdir(cxxabi_include):
# NDK r13 removes the inner "libcxxabi" directory.
cxxabi_include = os.path.join(cxxabi_base, 'include')
if not isdir(cxxabi_include):
die("Couldn't find path to libc++abi includes in the android ndk")
# Add android/support/include/ for prototyping long double math
# functions, locale-specific C library functions, multibyte support,
# etc.
return [
'-I%s' % cxx_include,
'-I%s' % os.path.join(ndk, 'sources', 'android', 'support', 'include'),
'-I%s' % cxxabi_include]
add_old_configure_assignment('stlport_cppflags', stlport_cppflags)
@depends(android_system, android_sysroot, android_toolchain, android_version,
stlport_cppflags)
def extra_toolchain_flags(android_system, android_sysroot, toolchain_dir,
android_version, stlport_cppflags):
if not android_sysroot:
return []
flags = ['-isystem',
android_system,
'-isystem',
os.path.join(android_sysroot, 'usr', 'include'),
'-gcc-toolchain',
toolchain_dir,
'-D__ANDROID_API__=%d' % android_version]
flags.extend(stlport_cppflags if stlport_cppflags else [])
return flags
@depends(android_toolchain_prefix_base, android_toolchain)
def android_toolchain_prefix(prefix_base, toolchain):
if toolchain:
return '%s/bin/%s-' % (toolchain, prefix_base)
imply_option('--with-toolchain-prefix', android_toolchain_prefix,
reason='--with-android-ndk')
@depends(extra_toolchain_flags, android_toolchain,
android_toolchain_prefix_base, '--help')
@imports(_from='os.path', _import='isdir')
def bindgen_cflags_defaults(toolchain_flags, toolchain, toolchain_prefix, _):
if not toolchain_flags:
return
gcc_include = os.path.join(
toolchain, 'lib', 'gcc', toolchain_prefix, '4.9.x')
if not isdir(gcc_include):
gcc_include = os.path.join(
toolchain, 'lib', 'gcc', toolchain_prefix, '4.9')
cflags_format = "%s -I%s -I%s"
return cflags_format % (' '.join(toolchain_flags),
os.path.join(gcc_include, 'include'),
os.path.join(gcc_include, 'include-fixed'))
@depends(host, ndk)
@imports(_from='os.path', _import='exists')
@imports(_from='os.path', _import='isdir')
def android_clang_compiler(host, ndk):
if not ndk:
return
llvm_path = '%s/toolchains/llvm/prebuilt/%s-%s/bin' % (ndk,
host.kernel.lower(),
host.cpu)
if not isdir(llvm_path) and host.cpu == 'x86_64':
llvm_path = toolchain_format % (ndk, host.kernel.lower(), 'x86')
if not isdir(llvm_path):
die("Couldn't find path to LLVM toolchain at %s" % llvm_path)
clang = '%s/clang' % llvm_path
if not exists(clang):
die("Couln't find clang in LLVM toolchain at %s" % clang)
return clang
@depends('--with-android-googlevr-sdk', target)
@checking('for GoogleVR SDK', lambda x: x.result)
@imports(_from='os.path', _import='exists')
@imports(_from='os.path', _import='abspath')
def googlevr_sdk(value, target):
if not value:
return namespace(
result='Not specified'
)
path = abspath(value[0])
if not exists(path):
die('Could not find GoogleVR SDK %s', path)
include = '%s/libraries/headers/' % path
if 'arm' == target.cpu:
arch = 'armeabi-v7a'
elif 'aarch64' == target.cpu:
arch = 'arm64-v8a'
elif 'x86' == target.cpu:
arch = 'x86'
else:
die('Unsupported GoogleVR cpu architecture %s' % target.cpu)
libs = '{0}/libraries/jni/{1}/'.format(path, arch)
if not exists(libs):
die('Could not find GoogleVR NDK at %s. Did you try running '
'\'./gradlew :extractNdk\' in %s?', libs, path)
return namespace(
result=path,
include=include,
libs=libs,
enabled=True,
)
set_define('MOZ_ANDROID_GOOGLE_VR', googlevr_sdk.enabled)
set_config('MOZ_ANDROID_GOOGLE_VR', googlevr_sdk.enabled)
set_config('MOZ_ANDROID_GOOGLE_VR_INCLUDE', googlevr_sdk.include)
set_config('MOZ_ANDROID_GOOGLE_VR_LIBS', googlevr_sdk.libs)