aboutsummaryrefslogtreecommitdiffstats
path: root/python/servo
diff options
context:
space:
mode:
authorMartin Robinson <mrobinson@igalia.com>2023-07-03 12:03:26 +0200
committerMartin Robinson <mrobinson@igalia.com>2023-07-05 07:47:00 +0200
commit1eb3e85d69cbdb443cd5287d3654b6a045202463 (patch)
tree46284627d87090f2231c2bc2846708bda6285ca3 /python/servo
parentd931cf49aa4525d6f3d210e3966b503fec494934 (diff)
downloadservo-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.py257
-rw-r--r--python/servo/command_base.py236
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")