Bug 1820947 - Use "new style" sysroot on Android. r=firefox-build-system-reviewers,andi

For a few NDK releases now, the situation has been simplified wrt
headers and libraries, and while we're currently still using things here
and there because we never changed our ways, we can simplify things a
lot by using the new simplified things. This involves:
- Using a --target that contains the Android version, making clang set
  __ANDROID_API__ itself, and makes it look in $sysroot/usr/lib/$target/$ver
  when linking.
- Using the sysroot that is under toolchains/llvm/prebuilt/*.
- Removing the hacks around libstdc++/libc++.

This ends up emptying stlport compiler flags, which allows to remove a
bunch of things.

Differential Revision: https://phabricator.services.mozilla.com/D172039
This commit is contained in:
Mike Hommey 2023-03-15 20:44:02 +00:00
parent 63bff39aa5
commit eaca1f3dd4
7 changed files with 89 additions and 179 deletions

View File

@ -11,7 +11,7 @@ case "$target" in
LDFLAGS="$extra_android_flags $LDFLAGS"
CPPFLAGS="$extra_android_flags $CPPFLAGS"
CFLAGS="-fno-short-enums $CFLAGS"
CXXFLAGS="-fno-short-enums $CXXFLAGS $stlport_cppflags"
CXXFLAGS="-fno-short-enums $CXXFLAGS"
ASFLAGS="$extra_android_flags -DANDROID $ASFLAGS"
;;
esac

View File

@ -121,84 +121,50 @@ 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
@imports(_from="mozbuild.shellutil", _import="quote")
def host_dir(host, base_dir):
dir_format = "%s/%s-%s"
host_kernel = "windows" if host.kernel == "WINNT" else host.kernel.lower()
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
dir = dir_format % (base_dir, host_kernel, host.cpu)
log.debug("Trying %s" % quote(dir))
if not isdir(dir) and host.cpu == "x86_64":
dir = dir_format % (base_dir, host_kernel, "x86")
log.debug("Trying %s" % quote(dir))
if not isdir(dir) and host.kernel == "Darwin" and host.cpu == "aarch64":
dir = dir_format % (base_dir, host_kernel, "x86_64")
log.debug("Trying %s" % quote(dir))
if isdir(dir):
return dir
@depends(ndk, target)
@depends(ndk, target, host)
@checking("for android sysroot directory")
@imports(_from="os.path", _import="isdir")
def android_sysroot(ndk, target):
def android_sysroot(ndk, target, host):
if target.os != "Android":
return
search_dirs = [
# (<if this directory exists>, <return this directory>)
(os.path.join(ndk, "sysroot"), os.path.join(ndk, "sysroot")),
os.path.join(
host_dir(host, os.path.join(ndk, "toolchains", "llvm", "prebuilt")),
"sysroot",
),
]
for test_dir, sysroot_dir in search_dirs:
if isdir(test_dir):
for sysroot_dir in search_dirs:
if isdir(sysroot_dir):
return sysroot_dir
die(
"Android sysroot directory not found in %s."
% str([sysroot_dir for test_dir, sysroot_dir in search_dirs])
% str([sysroot_dir for sysroot_dir in search_dirs])
)
@depends(ndk, target)
@checking("for android system directory")
@imports(_from="os.path", _import="isdir")
def android_system(ndk, target):
if target.os != "Android":
return
search_dirs = [
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))
@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
@ -216,18 +182,8 @@ def android_toolchain(target, host, ndk, toolchain):
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):
toolchain = host_dir(host, "%s/toolchains/%s-4.9/prebuilt" % (ndk, target_base))
if toolchain:
return toolchain
die("You have to specify --with-android-toolchain=" "/path/to/ndk/toolchain.")
@ -281,58 +237,6 @@ def android_lldb_server(target, host, ndk, lldb):
set_config("ANDROID_LLDB_SERVER", android_lldb_server)
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)
option(
env="STLPORT_LIBS",
nargs=1,
@ -340,48 +244,27 @@ option(
)
@depends("STLPORT_LIBS", ndk, android_cpu_arch)
@depends("STLPORT_LIBS", ndk)
@imports(_from="os.path", _import="isfile")
def stlport_libs(value, ndk, android_cpu_arch):
def stlport_libs(value, ndk):
if value and len(value):
return value.split()
if not ndk:
return
cxx_libs = os.path.join(
ndk, "sources", "cxx-stl", "llvm-libc++", "libs", android_cpu_arch
)
if not isfile(os.path.join(cxx_libs, "libc++_static.a")):
die("Couldn't find path to llvm-libc++ in the android ndk")
libs = [
"-L%s" % cxx_libs,
"-lc++_static",
]
for lib in ("c++abi", "unwind", "android_support"):
if isfile(os.path.join(cxx_libs, "lib%s.a" % lib)):
libs.append("-l%s" % lib)
return libs
return ["-static-libstdc++"]
set_config("STLPORT_LIBS", stlport_libs)
@depends(android_system, android_sysroot, android_toolchain, android_version)
def extra_toolchain_flags(
android_system, android_sysroot, toolchain_dir, android_version
):
@depends(android_sysroot, android_toolchain)
def extra_toolchain_flags(android_sysroot, toolchain_dir):
if not android_sysroot:
return []
flags = [
"-isystem",
android_system,
"-isystem",
os.path.join(android_sysroot, "usr", "include"),
"--sysroot={}".format(android_sysroot),
"--gcc-toolchain={}".format(toolchain_dir),
"-D__ANDROID_API__=%d" % android_version,
]
return flags
@ -389,12 +272,9 @@ def extra_toolchain_flags(
add_old_configure_assignment("extra_android_flags", extra_toolchain_flags)
@depends(extra_toolchain_flags, stlport_cppflags)
def bindgen_cflags_android(toolchain_flags, stlport_flags):
if not toolchain_flags:
return
return toolchain_flags + stlport_flags
@depends(extra_toolchain_flags)
def bindgen_cflags_android(toolchain_flags):
return toolchain_flags
@depends("--with-android-googlevr-sdk", target)

View File

@ -123,6 +123,7 @@ option(
clang_search_path,
target,
target_sysroot.path,
android_version,
)
@checking("for clang for bindgen", lambda x: x.path if x else "not found")
def bindgen_clang_compiler(
@ -133,6 +134,7 @@ def bindgen_clang_compiler(
clang_search_path,
target,
sysroot_path,
android_version,
):
# When the target compiler is clang, use that, including flags.
if cxx_compiler.type == "clang":
@ -172,14 +174,18 @@ def bindgen_clang_compiler(
flags = []
if sysroot_path:
flags.extend(("--sysroot", sysroot_path))
info = check_compiler(configure_cache, [clang_path] + flags, "C++", target)
info = check_compiler(
configure_cache, [clang_path] + flags, "C++", target, android_version
)
# Usually, one check_compiler pass would be enough, but when cross-compiling
# and the host and target don't use the same default C++ standard, we don't
# get the --std flag, so try again. This is the same thing as valid_compiler()
# does in toolchain.configure.
if info.flags:
flags += info.flags
info = check_compiler(configure_cache, [clang_path] + flags, "C++", target)
info = check_compiler(
configure_cache, [clang_path] + flags, "C++", target, android_version
)
return namespace(
path=clang_path,
flags=flags + info.flags,

View File

@ -105,7 +105,6 @@ def compiler_class(compiler, host_or_target):
self,
dependable(flags),
extra_toolchain_flags,
stlport_cppflags,
dependable(header),
onerror,
configure_cache,
@ -116,7 +115,6 @@ def compiler_class(compiler, host_or_target):
compiler,
flags,
extra_flags,
stlport_flags,
header,
onerror,
configure_cache,
@ -124,8 +122,6 @@ def compiler_class(compiler, host_or_target):
flags = list(flags or [])
if is_target:
flags += extra_flags or []
if compiler.language == "C++":
flags += stlport_flags or []
header = header or ""
if isinstance(header, (list, tuple)):
header = "\n".join(header)

View File

@ -410,7 +410,7 @@ def same_arch_different_bits():
@imports(_from="mozbuild.shellutil", _import="quote")
@imports(_from="mozbuild.configure.constants", _import="OS_preprocessor_checks")
def check_compiler(configure_cache, compiler, language, target):
def check_compiler(configure_cache, compiler, language, target, android_version):
info = get_compiler_info(configure_cache, compiler, language)
flags = []
@ -445,6 +445,13 @@ def check_compiler(configure_cache, compiler, language, target):
# Check compiler target
# --------------------------------------------------------------------
has_target = False
if target.os == "Android" and android_version:
# This makes clang define __ANDROID_API__ and use versioned library
# directories from the NDK.
toolchain = "%s%d" % (target.toolchain, android_version)
else:
toolchain = target.toolchain
if info.type == "clang":
# Add the target explicitly when the target is aarch64 macosx, because
# the Xcode clang target is named differently, and we need to work around
@ -463,7 +470,7 @@ def check_compiler(configure_cache, compiler, language, target):
or not info.endianness
or info.endianness != target.endianness
):
flags.append("--target=%s" % target.toolchain)
flags.append("--target=%s" % toolchain)
has_target = True
# Add target flag when there is an OS mismatch (e.g. building for Android on
@ -472,7 +479,7 @@ def check_compiler(configure_cache, compiler, language, target):
elif target.os in OS_preprocessor_checks and (
not info.os or info.os != target.os
):
flags.append("--target=%s" % target.toolchain)
flags.append("--target=%s" % toolchain)
has_target = True
if not has_target and (not info.cpu or info.cpu != target.cpu):
@ -482,9 +489,9 @@ def check_compiler(configure_cache, compiler, language, target):
elif (info.cpu, target.cpu) in same_arch:
flags.append("-m64")
elif info.type == "clang-cl" and target.cpu == "aarch64":
flags.append("--target=%s" % target.toolchain)
flags.append("--target=%s" % toolchain)
elif info.type == "clang":
flags.append("--target=%s" % target.toolchain)
flags.append("--target=%s" % toolchain)
return namespace(
type=info.type,
@ -1199,6 +1206,7 @@ def compiler(
host_or_target,
sysroot,
macos_target,
android_version,
multiarch_dir,
winsysroot,
host,
@ -1214,6 +1222,7 @@ def compiler(
host_or_target,
sysroot,
macos_target,
android_version,
multiarch_dir,
winsysroot,
host,
@ -1235,7 +1244,11 @@ def compiler(
flags.extend(provided_compiler.flags)
info = check_compiler(
configure_cache, wrapper + [compiler] + flags, language, host_or_target
configure_cache,
wrapper + [compiler] + flags,
language,
host_or_target,
android_version,
)
if info.type == "clang" and language == "C++" and host_or_target.os == "OSX":
@ -1258,6 +1271,7 @@ def compiler(
wrapper + [compiler] + flags,
language,
host_or_target,
android_version,
)
except FatalCheckError:
pass
@ -1383,6 +1397,15 @@ def compiler(
% (host_or_target.alias, info.version)
)
if host_or_target.os == "Android":
# Need at least clang 8 for support for __ANDROID_API__ and versioned
# library directories from the NDK.
if info.type == "clang" and info.version < "8.0":
raise FatalCheckError(
"Only clang/llvm 8.0 or newer is supported for %s (found version %s)."
% (host_or_target.alias, info.version)
)
if info.flags:
raise FatalCheckError("Unknown compiler or compiler not supported.")
@ -1815,7 +1838,8 @@ def linker_ldflags_tmpl(host_or_target):
target,
target_sysroot,
target_multiarch_dir,
android_platform,
android_sysroot,
android_version,
c_compiler,
developer_options,
)
@ -1826,6 +1850,7 @@ def linker_ldflags_tmpl(host_or_target):
host_sysroot,
host_multiarch_dir,
dependable(None),
dependable(None),
host_c_compiler,
developer_options,
)
@ -1837,7 +1862,8 @@ def linker_ldflags_tmpl(host_or_target):
target,
sysroot,
multiarch_dir,
android_platform,
android_sysroot,
android_version,
c_compiler,
developer_options,
):
@ -1863,11 +1889,17 @@ def linker_ldflags_tmpl(host_or_target):
sysroot.path, multiarch_dir, sysroot.stdcxx_version
)
)
if android_platform:
flags.append("-L{}/usr/lib".format(android_platform))
flags.append("-Wl,--rpath-link={}/usr/lib".format(android_platform))
flags.append("--sysroot")
flags.append(android_platform)
if android_sysroot:
# BFD/gold linkers need a manual --rpath-link for indirect
# dependencies.
flags += [
"-Wl,--rpath-link={}/usr/lib/{}".format(
android_sysroot, target.toolchain
),
"-Wl,--rpath-link={}/usr/lib/{}/{}".format(
android_sysroot, target.toolchain, android_version
),
]
if (
developer_options
and linker

View File

@ -29,7 +29,7 @@ for v in ("OS_CPPFLAGS", "OS_CFLAGS", "DEBUG", "CLANG_PLUGIN", "OPTIMIZE", "FRAM
for flag in COMPILE_FLAGS[v]:
if flag == "-isystem":
flags.append("".join(COMPILE_FLAGS[v][idx : idx + 2]))
elif flag.startswith(("-m", "-I", "-isystem")) or flag == "-fPIC":
elif flag.startswith(("-m", "-I", "-isystem", "--sysroot=")) or flag == "-fPIC":
flags.append(flag)
idx += 1
COMPILE_FLAGS[v] = flags

View File

@ -56,10 +56,6 @@ class BaseCompileChecks(unittest.TestCase):
def extra_toolchain_flags():
return []
@depends(when=True)
def stlport_cppflags():
return []
@depends(when=True)
def linker_ldflags():
return []