# -*- 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/. @depends(toolchains_base_dir, "--help") @imports(_from="os.path", _import="isdir") @imports(_from="mozboot.android", _import="NDK_VERSION") def default_android_ndk_root(toolchains_base_dir, _): for ndk in ("android-ndk-%s" % NDK_VERSION, "android-ndk"): path = os.path.join(toolchains_base_dir, ndk) if isdir(path): return path option( "--with-android-ndk", nargs=1, default=default_android_ndk_root, help="location where the Android NDK can be found{|}", ) option("--with-android-toolchain", nargs=1, help="location of the Android toolchain") option( "--with-android-lldb-server", nargs=1, help="location of the Android LLDB server" ) 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"]: # 64-bit support was added in API 21. return "21" return "16" option( "--with-android-version", nargs=1, help="android platform version{|}", default=min_android_version, ) @depends("--with-android-version", min_android_version) @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") @imports(_from="os.path", _import="isdir") def ndk(value): if value: if not isdir(value[0]): die( "The path you specified with --with-android-ndk (%s) is not " "a directory" % value[0] ) return value[0] die( "You must specify --with-android-ndk=/path/to/ndk when targeting Android, " "or try |mach bootstrap|." ) set_config("ANDROID_NDK", ndk) add_old_configure_assignment("android_ndk", ndk) @depends(ndk) @checking("for android ndk version") @imports(_from="__builtin__", _import="open") @imports(_from="mozboot.android", _import="NDK_VERSION") @imports(_from="mozboot.android", _import="get_ndk_version") @imports(_from="mozboot.android", _import="GetNdkVersionError") def ndk_version(ndk): if not ndk: # Building 'js/src' for non-Android. return try: major, minor, human = get_ndk_version(ndk) except GetNdkVersionError as e: die(str(e)) if NDK_VERSION != human: die( "The only supported version of the NDK is %s (have %s)\n" "Please run |mach bootstrap| " "to install the correct NDK." % (NDK_VERSION, human) ) return namespace( major=major, minor=minor, ) set_config("ANDROID_NDK_MAJOR_VERSION", ndk_version.major) set_config("ANDROID_NDK_MINOR_VERSION", ndk_version.minor) @depends(target, android_version, ndk) @checking("for android platform directory") @imports(_from="os.path", _import="isdir") def android_platform(target, android_version, ndk): if target.os != "Android": return if "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 set_config("ANDROID_PLATFORM", android_platform) @depends(android_platform, ndk, target) @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) @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") @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 == "x86_64": target_base = "x86_64" 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" host_kernel = "windows" if host.kernel == "WINNT" else host.kernel.lower() toolchain = toolchain_format % (ndk, target_base, host_kernel, host.cpu) log.debug("Trying %s" % quote(toolchain)) if not isdir(toolchain) and host.cpu == "x86_64": toolchain = toolchain_format % (ndk, target_base, host_kernel, "x86") log.debug("Trying %s" % quote(toolchain)) if not isdir(toolchain) and host.kernel == "Darwin" and host.cpu == "aarch64": toolchain = toolchain_format % (ndk, target_base, host_kernel, "x86_64") 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, host, ndk, "--with-android-lldb-server") @checking("for the Android LLDB server", lambda x: x or "not found") @imports(_from="os", _import="listdir") @imports(_from="os.path", _import="isdir") @imports(_from="os.path", _import="isfile") @imports(_from="mozbuild.shellutil", _import="quote") def android_lldb_server(target, host, ndk, lldb): if not ndk: return if lldb: return lldb[0] else: clang_format = "toolchains/llvm/prebuilt/%s-%s/lib64/clang" llvm_lib = "lib/linux" host_kernel = "windows" if host.kernel == "WINNT" else host.kernel.lower() clang_path = os.path.join(ndk, clang_format % (host_kernel, host.cpu)) if not isdir(clang_path) and host.kernel == "Darwin" and host.cpu == "aarch64": clang_path = os.path.join(ndk, clang_format % (host_kernel, "x86_64")) log.debug("Listing subdirectories of %s" % quote(clang_path)) clang_subdirs = [ x for x in listdir(clang_path) if isdir(os.path.join(clang_path, x)) ] log.debug("Got %r" % clang_subdirs) if len(clang_subdirs) != 1: die( "Could not resolve lldb-server in %s. Please specify --with-android-lldb-server=/path/to/android/lldb-server" % quote(clang_path) ) log.debug("Found version %s" % quote(clang_subdirs[0])) if target.cpu == "x86": target_cpu = "i386" else: target_cpu = target.cpu full_path = os.path.join( clang_path, clang_subdirs[0], llvm_lib, target_cpu, "lldb-server" ) log.debug("Trying %s" % quote(full_path)) if isfile(full_path): return full_path die("Please specify --with-android-lldb-server=/path/to/android/lldb-server") set_config("ANDROID_LLDB_SERVER", android_lldb_server) @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) @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 [ # You'd think we'd want to use -stdlib=libc++, but this doesn't work # (cf. https://bugzilla.mozilla.org/show_bug.cgi?id=1510897#c2) # Using -stdlib=libc++ and removing some of the -I below also doesn't # work because not everything that is in cxx_include comes in the C++ # header directory that comes with clang. "-stdlib=libstdc++", "-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) def extra_toolchain_flags( android_system, android_sysroot, toolchain_dir, android_version ): if not android_sysroot: return [] flags = [ "-isystem", android_system, "-isystem", os.path.join(android_sysroot, "usr", "include"), "--gcc-toolchain={}".format(toolchain_dir), "-D__ANDROID_API__=%d" % android_version, ] 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, stlport_cppflags, android_toolchain, android_toolchain_prefix_base, ) @imports(_from="os.path", _import="isdir") def bindgen_cflags_android(toolchain_flags, stlport_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") return ( toolchain_flags + stlport_flags + [ "-I%s" % os.path.join(gcc_include, "include"), "-I%s" % os.path.join(gcc_include, "include-fixed"), ] ) @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)