# -*- 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 = [ # (, ) (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)