diff options
author | Martin Robinson <mrobinson@igalia.com> | 2023-07-03 12:03:26 +0200 |
---|---|---|
committer | Martin Robinson <mrobinson@igalia.com> | 2023-07-05 07:47:00 +0200 |
commit | 1eb3e85d69cbdb443cd5287d3654b6a045202463 (patch) | |
tree | 46284627d87090f2231c2bc2846708bda6285ca3 /python/servo | |
parent | d931cf49aa4525d6f3d210e3966b503fec494934 (diff) | |
download | servo-1eb3e85d69cbdb443cd5287d3654b6a045202463.tar.gz servo-1eb3e85d69cbdb443cd5287d3654b6a045202463.zip |
Collect android build setup into two methods
This is small refactor which tries to isolate all of the Android setup
into a couple methods, so that it is easier to reason about in the
scripts. This doesn't change any behavior but does fix a few small
linting errors in the existing code.
Note: The Android build is currently broken and this change doesn't fix
it. It shouldn't break it any more though.
Diffstat (limited to 'python/servo')
-rw-r--r-- | python/servo/build_commands.py | 257 | ||||
-rw-r--r-- | python/servo/command_base.py | 236 |
2 files changed, 251 insertions, 242 deletions
diff --git a/python/servo/build_commands.py b/python/servo/build_commands.py index 48563efee94..19e449af960 100644 --- a/python/servo/build_commands.py +++ b/python/servo/build_commands.py @@ -13,19 +13,17 @@ import datetime import locale import os import os.path as path -import platform import shutil import stat import subprocess import sys import urllib -import zipfile from time import time +from typing import Dict +import zipfile import notifypy -import servo.platform -import servo.util from mach.decorators import ( CommandArgument, @@ -34,8 +32,10 @@ from mach.decorators import ( ) from mach.registrar import Registrar -from mach_bootstrap import _get_exec_path -from servo.command_base import CommandBase, cd, call, check_call +import servo.platform +import servo.util + +from servo.command_base import CommandBase, call, check_call from servo.gstreamer import windows_dlls, windows_plugins, macos_plugins @@ -70,14 +70,8 @@ class MachCommands(CommandBase): opts = params or [] has_media_stack = "media-gstreamer" in self.features - target_path = base_path = servo.util.get_target_dir() - if self.is_android_build: - assert self.cross_compile_target - target_path = path.join(target_path, "android") - base_path = path.join(target_path, self.cross_compile_target) - - release_path = path.join(base_path, "release", "servo") - dev_path = path.join(base_path, "debug", "servo") + release_path = path.join(self.target_path, "release", "servo") + dev_path = path.join(self.target_path, "debug", "servo") release_exists = path.exists(release_path) dev_exists = path.exists(dev_path) @@ -202,196 +196,6 @@ class MachCommands(CommandBase): print(stderr.decode(encoding)) exit(1) - if self.is_android_build: - if "ANDROID_NDK" not in env: - print("Please set the ANDROID_NDK environment variable.") - sys.exit(1) - if "ANDROID_SDK" not in env: - print("Please set the ANDROID_SDK environment variable.") - sys.exit(1) - - android_platform = self.config["android"]["platform"] - android_toolchain_name = self.config["android"]["toolchain_name"] - android_toolchain_prefix = self.config["android"]["toolchain_prefix"] - android_lib = self.config["android"]["lib"] - android_arch = self.config["android"]["arch"] - - # Build OpenSSL for android - env["OPENSSL_VERSION"] = "1.1.1d" - make_cmd = ["make"] - if jobs is not None: - make_cmd += ["-j" + jobs] - openssl_dir = path.join(target_path, self.cross_compile_target, "native", "openssl") - if not path.exists(openssl_dir): - os.makedirs(openssl_dir) - shutil.copy(path.join(self.android_support_dir(), "openssl.makefile"), openssl_dir) - shutil.copy(path.join(self.android_support_dir(), "openssl.sh"), openssl_dir) - - # Check if the NDK version is 15 - if not os.path.isfile(path.join(env["ANDROID_NDK"], 'source.properties')): - print("ANDROID_NDK should have file `source.properties`.") - print("The environment variable ANDROID_NDK may be set at a wrong path.") - sys.exit(1) - with open(path.join(env["ANDROID_NDK"], 'source.properties')) as ndk_properties: - lines = ndk_properties.readlines() - if lines[1].split(' = ')[1].split('.')[0] != '15': - print("Currently only support NDK 15. Please re-run `./mach bootstrap-android`.") - sys.exit(1) - - env["RUST_TARGET"] = self.cross_compile_target - with cd(openssl_dir): - status = call( - make_cmd + ["-f", "openssl.makefile"], - env=env, - verbose=verbose) - if status: - return status - openssl_dir = path.join(openssl_dir, "openssl-{}".format(env["OPENSSL_VERSION"])) - env['OPENSSL_LIB_DIR'] = openssl_dir - env['OPENSSL_INCLUDE_DIR'] = path.join(openssl_dir, "include") - env['OPENSSL_STATIC'] = 'TRUE' - # Android builds also require having the gcc bits on the PATH and various INCLUDE - # path munging if you do not want to install a standalone NDK. See: - # https://dxr.mozilla.org/mozilla-central/source/build/autoconf/android.m4#139-161 - os_type = platform.system().lower() - if os_type not in ["linux", "darwin"]: - raise Exception("Android cross builds are only supported on Linux and macOS.") - cpu_type = platform.machine().lower() - host_suffix = "unknown" - if cpu_type in ["i386", "i486", "i686", "i768", "x86"]: - host_suffix = "x86" - elif cpu_type in ["x86_64", "x86-64", "x64", "amd64"]: - host_suffix = "x86_64" - host = os_type + "-" + host_suffix - - host_cc = env.get('HOST_CC') or _get_exec_path(["clang"]) or _get_exec_path(["gcc"]) - host_cxx = env.get('HOST_CXX') or _get_exec_path(["clang++"]) or _get_exec_path(["g++"]) - - llvm_toolchain = path.join(env['ANDROID_NDK'], "toolchains", "llvm", "prebuilt", host) - gcc_toolchain = path.join(env['ANDROID_NDK'], "toolchains", - android_toolchain_prefix + "-4.9", "prebuilt", host) - gcc_libs = path.join(gcc_toolchain, "lib", "gcc", android_toolchain_name, "4.9.x") - - env['PATH'] = (path.join(llvm_toolchain, "bin") + ':' + env['PATH']) - env['ANDROID_SYSROOT'] = path.join(env['ANDROID_NDK'], "sysroot") - support_include = path.join(env['ANDROID_NDK'], "sources", "android", "support", "include") - cpufeatures_include = path.join(env['ANDROID_NDK'], "sources", "android", "cpufeatures") - cxx_include = path.join(env['ANDROID_NDK'], "sources", "cxx-stl", - "llvm-libc++", "include") - clang_include = path.join(llvm_toolchain, "lib64", "clang", "3.8", "include") - cxxabi_include = path.join(env['ANDROID_NDK'], "sources", "cxx-stl", - "llvm-libc++abi", "include") - sysroot_include = path.join(env['ANDROID_SYSROOT'], "usr", "include") - arch_include = path.join(sysroot_include, android_toolchain_name) - android_platform_dir = path.join(env['ANDROID_NDK'], "platforms", android_platform, "arch-" + android_arch) - arch_libs = path.join(android_platform_dir, "usr", "lib") - clang_include = path.join(llvm_toolchain, "lib64", "clang", "5.0", "include") - android_api = android_platform.replace('android-', '') - env['HOST_CC'] = host_cc - env['HOST_CXX'] = host_cxx - env['HOST_CFLAGS'] = '' - env['HOST_CXXFLAGS'] = '' - env['CC'] = path.join(llvm_toolchain, "bin", "clang") - env['CPP'] = path.join(llvm_toolchain, "bin", "clang") + " -E" - env['CXX'] = path.join(llvm_toolchain, "bin", "clang++") - env['ANDROID_TOOLCHAIN'] = gcc_toolchain - env['ANDROID_TOOLCHAIN_DIR'] = gcc_toolchain - env['ANDROID_VERSION'] = android_api - env['ANDROID_PLATFORM_DIR'] = android_platform_dir - env['GCC_TOOLCHAIN'] = gcc_toolchain - gcc_toolchain_bin = path.join(gcc_toolchain, android_toolchain_name, "bin") - env['AR'] = path.join(gcc_toolchain_bin, "ar") - env['RANLIB'] = path.join(gcc_toolchain_bin, "ranlib") - env['OBJCOPY'] = path.join(gcc_toolchain_bin, "objcopy") - env['YASM'] = path.join(env['ANDROID_NDK'], 'prebuilt', host, 'bin', 'yasm') - # A cheat-sheet for some of the build errors caused by getting the search path wrong... - # - # fatal error: 'limits' file not found - # -- add -I cxx_include - # unknown type name '__locale_t' (when running bindgen in mozjs_sys) - # -- add -isystem sysroot_include - # error: use of undeclared identifier 'UINTMAX_C' - # -- add -D__STDC_CONSTANT_MACROS - # - # Also worth remembering: autoconf uses C for its configuration, - # even for C++ builds, so the C flags need to line up with the C++ flags. - env['CFLAGS'] = ' '.join([ - "--target=" + self.cross_compile_target, - "--sysroot=" + env['ANDROID_SYSROOT'], - "--gcc-toolchain=" + gcc_toolchain, - "-isystem", sysroot_include, - "-I" + arch_include, - "-B" + arch_libs, - "-L" + arch_libs, - "-D__ANDROID_API__=" + android_api, - ]) - env['CXXFLAGS'] = ' '.join([ - "--target=" + self.cross_compile_target, - "--sysroot=" + env['ANDROID_SYSROOT'], - "--gcc-toolchain=" + gcc_toolchain, - "-I" + cpufeatures_include, - "-I" + cxx_include, - "-I" + clang_include, - "-isystem", sysroot_include, - "-I" + cxxabi_include, - "-I" + clang_include, - "-I" + arch_include, - "-I" + support_include, - "-L" + gcc_libs, - "-B" + arch_libs, - "-L" + arch_libs, - "-D__ANDROID_API__=" + android_api, - "-D__STDC_CONSTANT_MACROS", - "-D__NDK_FPABI__=", - ]) - env['CPPFLAGS'] = ' '.join([ - "--target=" + self.cross_compile_target, - "--sysroot=" + env['ANDROID_SYSROOT'], - "-I" + arch_include, - ]) - env["NDK_ANDROID_VERSION"] = android_api - env["ANDROID_ABI"] = android_lib - env["ANDROID_PLATFORM"] = android_platform - env["NDK_CMAKE_TOOLCHAIN_FILE"] = path.join(env['ANDROID_NDK'], "build", "cmake", "android.toolchain.cmake") - env["CMAKE_TOOLCHAIN_FILE"] = path.join(self.android_support_dir(), "toolchain.cmake") - # Set output dir for gradle aar files - aar_out_dir = self.android_aar_dir() - if not os.path.exists(aar_out_dir): - os.makedirs(aar_out_dir) - env["AAR_OUT_DIR"] = aar_out_dir - # GStreamer and its dependencies use pkg-config and this flag is required - # to make it work in a cross-compilation context. - env["PKG_CONFIG_ALLOW_CROSS"] = '1' - # Build the name of the package containing all GStreamer dependencies - # according to the build target. - gst_lib = "gst-build-{}".format(self.config["android"]["lib"]) - gst_lib_zip = "gstreamer-{}-1.16.0-20190517-095630.zip".format(self.config["android"]["lib"]) - gst_dir = os.path.join(target_path, "gstreamer") - gst_lib_path = os.path.join(gst_dir, gst_lib) - pkg_config_path = os.path.join(gst_lib_path, "pkgconfig") - env["PKG_CONFIG_PATH"] = pkg_config_path - if not os.path.exists(gst_lib_path): - # Download GStreamer dependencies if they have not already been downloaded - # This bundle is generated with `libgstreamer_android_gen` - # Follow these instructions to build and deploy new binaries - # https://github.com/servo/libgstreamer_android_gen#build - print("Downloading GStreamer dependencies") - gst_url = "https://servo-deps-2.s3.amazonaws.com/gstreamer/%s" % gst_lib_zip - print(gst_url) - urllib.request.urlretrieve(gst_url, gst_lib_zip) - zip_ref = zipfile.ZipFile(gst_lib_zip, "r") - zip_ref.extractall(gst_dir) - os.remove(gst_lib_zip) - - # Change pkgconfig info to make all GStreamer dependencies point - # to the libgstreamer_android.so bundle. - for each in os.listdir(pkg_config_path): - if each.endswith('.pc'): - print("Setting pkgconfig info for %s" % each) - pc = os.path.join(pkg_config_path, each) - expr = "s#libdir=.*#libdir=%s#g" % gst_lib_path - subprocess.call(["perl", "-i", "-pe", expr, pc]) - # Gather Cargo build timings (https://doc.rust-lang.org/cargo/reference/timings.html). opts = ["--timings"] + opts @@ -400,6 +204,7 @@ class MachCommands(CommandBase): for key in env: print((key, env[key])) + self.download_and_build_android_dependencies_if_needed(env) status = self.run_cargo_build_like_command( "build", opts, env=env, verbose=verbose, libsimpleservo=libsimpleservo, **kwargs @@ -506,6 +311,50 @@ class MachCommands(CommandBase): return status + def download_and_build_android_dependencies_if_needed(self, env: Dict[str, str]): + if not self.is_android_build: + return + + openssl_dir = os.path.join(self.target_path, "native", "openssl") + if not os.path.exists(openssl_dir): + os.makedirs(openssl_dir) + shutil.copy(os.path.join(self.android_support_dir(), "openssl.makefile"), openssl_dir) + shutil.copy(os.path.join(self.android_support_dir(), "openssl.sh"), openssl_dir) + + status = call(["make", "-f", "openssl.makefile"], env=env, cwd=openssl_dir) + if status: + return status + + # Build the name of the package containing all GStreamer dependencies + # according to the build target. + android_lib = self.config["android"]["lib"] + gst_lib = f"gst-build-{android_lib}" + gst_lib_zip = f"gstreamer-{android_lib}-1.16.0-20190517-095630.zip" + gst_lib_path = os.path.join(self.target_path, "gstreamer", gst_lib) + pkg_config_path = os.path.join(gst_lib_path, "pkgconfig") + env["PKG_CONFIG_PATH"] = pkg_config_path + if not os.path.exists(gst_lib_path): + # Download GStreamer dependencies if they have not already been downloaded + # This bundle is generated with `libgstreamer_android_gen` + # Follow these instructions to build and deploy new binaries + # https://github.com/servo/libgstreamer_android_gen#build + gst_url = f"https://servo-deps-2.s3.amazonaws.com/gstreamer/{gst_lib_zip}" + print(f"Downloading GStreamer dependencies ({gst_url})") + + urllib.request.urlretrieve(gst_url, gst_lib_zip) + zip_ref = zipfile.ZipFile(gst_lib_zip, "r") + zip_ref.extractall(os.path.join(self.target_path, "gstreamer")) + os.remove(gst_lib_zip) + + # Change pkgconfig info to make all GStreamer dependencies point + # to the libgstreamer_android.so bundle. + for each in os.listdir(pkg_config_path): + if each.endswith('.pc'): + print(f"Setting pkgconfig info for {each}") + target_path = os.path.join(pkg_config_path, each) + expr = f"s#libdir=.*#libdir={gst_lib_path}#g" + subprocess.call(["perl", "-i", "-pe", expr, target_path]) + @Command('clean', description='Clean the target/ and python/_virtualenv[version]/ and support/hololens/ directories', category='build') diff --git a/python/servo/command_base.py b/python/servo/command_base.py index 58f8197d6a2..e2f67e94922 100644 --- a/python/servo/command_base.py +++ b/python/servo/command_base.py @@ -10,7 +10,7 @@ from __future__ import print_function import contextlib -from typing import List, Optional +from typing import Dict, List, Optional import functools import gzip import itertools @@ -20,7 +20,6 @@ import os import platform import re import shutil -import six import subprocess import sys import tarfile @@ -31,16 +30,19 @@ from errno import ENOENT as NO_SUCH_FILE_OR_DIRECTORY from glob import glob from os import path from subprocess import PIPE +from xml.etree.ElementTree import XML +import six import toml -import servo.platform -import servo.util as util -from xml.etree.ElementTree import XML -from servo.util import download_file, get_default_cache_dir +from mach_bootstrap import _get_exec_path from mach.decorators import CommandArgument, CommandArgumentGroup from mach.registrar import Registrar +import servo.platform +import servo.util as util +from servo.util import download_file, get_default_cache_dir + BIN_SUFFIX = ".exe" if sys.platform == "win32" else "" NIGHTLY_REPOSITORY_URL = "https://servo-builds2.s3.amazonaws.com/" @@ -207,6 +209,7 @@ class CommandBase(object): self.cross_compile_target = None self.is_uwp_build = False self.is_android_build = False + self.target_path = util.get_target_dir() def get_env_bool(var, default): # Contents of env vars are strings by default. This returns the @@ -564,38 +567,6 @@ class CommandBase(object): elif self.config["build"]["incremental"] is not None: env["CARGO_INCREMENTAL"] = "0" - # Paths to Android build tools: - if self.config["android"]["sdk"]: - env["ANDROID_SDK"] = self.config["android"]["sdk"] - if self.config["android"]["ndk"]: - env["ANDROID_NDK"] = self.config["android"]["ndk"] - if self.config["android"]["toolchain"]: - env["ANDROID_TOOLCHAIN"] = self.config["android"]["toolchain"] - if self.config["android"]["platform"]: - env["ANDROID_PLATFORM"] = self.config["android"]["platform"] - - toolchains = path.join(self.context.topdir, "android-toolchains") - for kind in ["sdk", "ndk"]: - default = os.path.join(toolchains, kind) - if os.path.isdir(default): - env.setdefault("ANDROID_" + kind.upper(), default) - - tools = os.path.join(toolchains, "sdk", "platform-tools") - if os.path.isdir(tools): - env["PATH"] = "%s%s%s" % (tools, os.pathsep, env["PATH"]) - - # These are set because they are the variable names that build-apk - # expects. However, other submodules have makefiles that reference - # the env var names above. Once winit is enabled and set as the - # default, we could modify the subproject makefiles to use the names - # below and remove the vars above, to avoid duplication. - if "ANDROID_SDK" in env: - env["ANDROID_HOME"] = env["ANDROID_SDK"] - if "ANDROID_NDK" in env: - env["NDK_HOME"] = env["ANDROID_NDK"] - if "ANDROID_TOOLCHAIN" in env: - env["NDK_STANDALONE"] = env["ANDROID_TOOLCHAIN"] - if self.config["build"]["rustflags"]: env['RUSTFLAGS'] = env.get('RUSTFLAGS', "") + " " + self.config["build"]["rustflags"] @@ -657,8 +628,193 @@ class CommandBase(object): # Argument-less str.split normalizes leading, trailing, and double spaces env['RUSTFLAGS'] = " ".join(env['RUSTFLAGS'].split()) + self.build_android_env_if_needed(env) + return env + def build_android_env_if_needed(self, env: Dict[str, str]): + if not self.is_android_build: + return + + # Paths to Android build tools: + if self.config["android"]["sdk"]: + env["ANDROID_SDK"] = self.config["android"]["sdk"] + if self.config["android"]["ndk"]: + env["ANDROID_NDK"] = self.config["android"]["ndk"] + if self.config["android"]["toolchain"]: + env["ANDROID_TOOLCHAIN"] = self.config["android"]["toolchain"] + if self.config["android"]["platform"]: + env["ANDROID_PLATFORM"] = self.config["android"]["platform"] + + # These are set because they are the variable names that build-apk + # expects. However, other submodules have makefiles that reference + # the env var names above. Once winit is enabled and set as the + # default, we could modify the subproject makefiles to use the names + # below and remove the vars above, to avoid duplication. + if "ANDROID_SDK" in env: + env["ANDROID_HOME"] = env["ANDROID_SDK"] + if "ANDROID_NDK" in env: + env["NDK_HOME"] = env["ANDROID_NDK"] + if "ANDROID_TOOLCHAIN" in env: + env["NDK_STANDALONE"] = env["ANDROID_TOOLCHAIN"] + + toolchains = path.join(self.context.topdir, "android-toolchains") + for kind in ["sdk", "ndk"]: + default = os.path.join(toolchains, kind) + if os.path.isdir(default): + env.setdefault("ANDROID_" + kind.upper(), default) + + tools = os.path.join(toolchains, "sdk", "platform-tools") + if os.path.isdir(tools): + env["PATH"] = "%s%s%s" % (tools, os.pathsep, env["PATH"]) + + if "ANDROID_NDK" not in env: + print("Please set the ANDROID_NDK environment variable.") + sys.exit(1) + if "ANDROID_SDK" not in env: + print("Please set the ANDROID_SDK environment variable.") + sys.exit(1) + + android_platform = self.config["android"]["platform"] + android_toolchain_name = self.config["android"]["toolchain_name"] + android_toolchain_prefix = self.config["android"]["toolchain_prefix"] + android_lib = self.config["android"]["lib"] + android_arch = self.config["android"]["arch"] + + # Build OpenSSL for android + env["OPENSSL_VERSION"] = "1.1.1d" + + # Check if the NDK version is 15 + if not os.path.isfile(path.join(env["ANDROID_NDK"], 'source.properties')): + print("ANDROID_NDK should have file `source.properties`.") + print("The environment variable ANDROID_NDK may be set at a wrong path.") + sys.exit(1) + with open(path.join(env["ANDROID_NDK"], 'source.properties'), encoding="utf8") as ndk_properties: + lines = ndk_properties.readlines() + if lines[1].split(' = ')[1].split('.')[0] != '15': + print("Currently only support NDK 15. Please re-run `./mach bootstrap-android`.") + sys.exit(1) + + openssl_dir = path.join( + self.target_path, "native", "openssl", "openssl-{}".format(env["OPENSSL_VERSION"])) + env['OPENSSL_LIB_DIR'] = openssl_dir + env['OPENSSL_INCLUDE_DIR'] = path.join(openssl_dir, "include") + env['OPENSSL_STATIC'] = 'TRUE' + # Android builds also require having the gcc bits on the PATH and various INCLUDE + # path munging if you do not want to install a standalone NDK. See: + # https://dxr.mozilla.org/mozilla-central/source/build/autoconf/android.m4#139-161 + os_type = platform.system().lower() + if os_type not in ["linux", "darwin"]: + raise Exception("Android cross builds are only supported on Linux and macOS.") + + cpu_type = platform.machine().lower() + host_suffix = "unknown" + if cpu_type in ["i386", "i486", "i686", "i768", "x86"]: + host_suffix = "x86" + elif cpu_type in ["x86_64", "x86-64", "x64", "amd64"]: + host_suffix = "x86_64" + host = os_type + "-" + host_suffix + + host_cc = env.get('HOST_CC') or _get_exec_path(["clang"]) or _get_exec_path(["gcc"]) + host_cxx = env.get('HOST_CXX') or _get_exec_path(["clang++"]) or _get_exec_path(["g++"]) + + llvm_toolchain = path.join(env['ANDROID_NDK'], "toolchains", "llvm", "prebuilt", host) + gcc_toolchain = path.join(env['ANDROID_NDK'], "toolchains", + android_toolchain_prefix + "-4.9", "prebuilt", host) + gcc_libs = path.join(gcc_toolchain, "lib", "gcc", android_toolchain_name, "4.9.x") + + env['PATH'] = (path.join(llvm_toolchain, "bin") + ':' + env['PATH']) + env['ANDROID_SYSROOT'] = path.join(env['ANDROID_NDK'], "sysroot") + support_include = path.join(env['ANDROID_NDK'], "sources", "android", "support", "include") + cpufeatures_include = path.join(env['ANDROID_NDK'], "sources", "android", "cpufeatures") + cxx_include = path.join(env['ANDROID_NDK'], "sources", "cxx-stl", + "llvm-libc++", "include") + clang_include = path.join(llvm_toolchain, "lib64", "clang", "3.8", "include") + cxxabi_include = path.join(env['ANDROID_NDK'], "sources", "cxx-stl", + "llvm-libc++abi", "include") + sysroot_include = path.join(env['ANDROID_SYSROOT'], "usr", "include") + arch_include = path.join(sysroot_include, android_toolchain_name) + android_platform_dir = path.join(env['ANDROID_NDK'], "platforms", android_platform, "arch-" + android_arch) + arch_libs = path.join(android_platform_dir, "usr", "lib") + clang_include = path.join(llvm_toolchain, "lib64", "clang", "5.0", "include") + android_api = android_platform.replace('android-', '') + + env["RUST_TARGET"] = self.cross_compile_target + env['HOST_CC'] = host_cc + env['HOST_CXX'] = host_cxx + env['HOST_CFLAGS'] = '' + env['HOST_CXXFLAGS'] = '' + env['CC'] = path.join(llvm_toolchain, "bin", "clang") + env['CPP'] = path.join(llvm_toolchain, "bin", "clang") + " -E" + env['CXX'] = path.join(llvm_toolchain, "bin", "clang++") + env['ANDROID_TOOLCHAIN'] = gcc_toolchain + env['ANDROID_TOOLCHAIN_DIR'] = gcc_toolchain + env['ANDROID_VERSION'] = android_api + env['ANDROID_PLATFORM_DIR'] = android_platform_dir + env['GCC_TOOLCHAIN'] = gcc_toolchain + gcc_toolchain_bin = path.join(gcc_toolchain, android_toolchain_name, "bin") + env['AR'] = path.join(gcc_toolchain_bin, "ar") + env['RANLIB'] = path.join(gcc_toolchain_bin, "ranlib") + env['OBJCOPY'] = path.join(gcc_toolchain_bin, "objcopy") + env['YASM'] = path.join(env['ANDROID_NDK'], 'prebuilt', host, 'bin', 'yasm') + # A cheat-sheet for some of the build errors caused by getting the search path wrong... + # + # fatal error: 'limits' file not found + # -- add -I cxx_include + # unknown type name '__locale_t' (when running bindgen in mozjs_sys) + # -- add -isystem sysroot_include + # error: use of undeclared identifier 'UINTMAX_C' + # -- add -D__STDC_CONSTANT_MACROS + # + # Also worth remembering: autoconf uses C for its configuration, + # even for C++ builds, so the C flags need to line up with the C++ flags. + env['CFLAGS'] = ' '.join([ + "--target=" + self.cross_compile_target, + "--sysroot=" + env['ANDROID_SYSROOT'], + "--gcc-toolchain=" + gcc_toolchain, + "-isystem", sysroot_include, + "-I" + arch_include, + "-B" + arch_libs, + "-L" + arch_libs, + "-D__ANDROID_API__=" + android_api, + ]) + env['CXXFLAGS'] = ' '.join([ + "--target=" + self.cross_compile_target, + "--sysroot=" + env['ANDROID_SYSROOT'], + "--gcc-toolchain=" + gcc_toolchain, + "-I" + cpufeatures_include, + "-I" + cxx_include, + "-I" + clang_include, + "-isystem", sysroot_include, + "-I" + cxxabi_include, + "-I" + clang_include, + "-I" + arch_include, + "-I" + support_include, + "-L" + gcc_libs, + "-B" + arch_libs, + "-L" + arch_libs, + "-D__ANDROID_API__=" + android_api, + "-D__STDC_CONSTANT_MACROS", + "-D__NDK_FPABI__=", + ]) + env['CPPFLAGS'] = ' '.join([ + "--target=" + self.cross_compile_target, + "--sysroot=" + env['ANDROID_SYSROOT'], + "-I" + arch_include, + ]) + env["NDK_ANDROID_VERSION"] = android_api + env["ANDROID_ABI"] = android_lib + env["ANDROID_PLATFORM"] = android_platform + env["NDK_CMAKE_TOOLCHAIN_FILE"] = path.join(env['ANDROID_NDK'], "build", "cmake", "android.toolchain.cmake") + env["CMAKE_TOOLCHAIN_FILE"] = path.join(self.android_support_dir(), "toolchain.cmake") + + # Set output dir for gradle aar files + env["AAR_OUT_DIR"] = self.android_aar_dir() + if not os.path.exists(env['AAR_OUT_DIR']): + os.makedirs(env['AAR_OUT_DIR']) + + env['PKG_CONFIG_ALLOW_CROSS'] = "1" + @staticmethod def build_like_command_arguments(original_function): decorators = [ @@ -767,6 +923,10 @@ class CommandBase(object): self.cross_compile_target = cross_compile_target self.is_uwp_build = uwp or (cross_compile_target and "uwp" in cross_compile_target) self.is_android_build = (cross_compile_target and "android" in cross_compile_target) + self.target_path = servo.util.get_target_dir() + if self.is_android_build: + assert self.cross_compile_target + self.target_path = path.join(self.target_path, "android", self.cross_compile_target) if self.cross_compile_target: print(f"Targeting '{self.cross_compile_target}' for cross-compilation") |