aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-01-21 01:47:31 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2023-01-21 01:47:31 +0000
commite52b1c3b7b38a89aa1643631e8e4fb407f9d8757 (patch)
tree10f966b91a8e84e59186406e652b6af89d8a5cdc
parent22826f79b23aa59c6bd9286d890de0a93e3ac7a3 (diff)
parentf088e1a97715f0bb1df5f9f2bd5199de567c0c74 (diff)
downloadndk-r25-release.tar.gz
Merge "Merge cherrypicks of ['aosp/2188718', 'aosp/2200318', 'aosp/2213723', 'aosp/2255356', 'aosp/2388575', 'aosp/2396162', 'aosp/2392413', 'aosp/2392414', 'aosp/2392415', 'aosp/2392416', 'aosp/2396222', 'aosp/2397738', 'aosp/2395932'] into ndk-r25-release." into ndk-r25-releasendk-r25cndk-r25-release
-rw-r--r--build/cmake/android-legacy.toolchain.cmake25
-rw-r--r--build/cmake/flags.cmake3
-rw-r--r--build/core/default-build-commands.mk6
-rw-r--r--docs/changelogs/Changelog-r25.md27
-rwxr-xr-xndk/checkbuild.py11
-rw-r--r--ndk/config.py2
-rw-r--r--ndk/pythonenv.py4
-rw-r--r--ndk/test/builder.py4
-rw-r--r--ndk/test/buildtest/case.py84
-rw-r--r--ndk/test/config.py23
-rw-r--r--ndk/test/spec.py7
-rw-r--r--ndk/testing/flag_verifier.py33
-rw-r--r--ndk/toolchains.py2
-rw-r--r--tests/build/cmake_default_flags/test.py6
-rw-r--r--tests/build/gc_sections/test.py40
-rw-r--r--tests/build/gc_sections/test_config.py8
-rw-r--r--tests/device/static-executable-exceptions/jni/Application.mk2
-rw-r--r--tests/device/static-executable-exceptions/test_config.py18
-rw-r--r--tests/device/static-executable/jni/Application.mk1
-rw-r--r--tests/device/static-executable/test_config.py18
20 files changed, 245 insertions, 79 deletions
diff --git a/build/cmake/android-legacy.toolchain.cmake b/build/cmake/android-legacy.toolchain.cmake
index 3a0dd7131..b0d875812 100644
--- a/build/cmake/android-legacy.toolchain.cmake
+++ b/build/cmake/android-legacy.toolchain.cmake
@@ -332,6 +332,9 @@ set(ANDROID_COMPILER_FLAGS_DEBUG)
set(ANDROID_COMPILER_FLAGS_RELEASE)
set(ANDROID_LINKER_FLAGS)
set(ANDROID_LINKER_FLAGS_EXE)
+set(ANDROID_LINKER_FLAGS_RELEASE)
+set(ANDROID_LINKER_FLAGS_RELWITHDEBINFO)
+set(ANDROID_LINKER_FLAGS_MINSIZEREL)
# STL.
set(ANDROID_CXX_STANDARD_LIBRARIES)
@@ -350,7 +353,7 @@ elseif(ANDROID_STL STREQUAL none)
list(APPEND ANDROID_COMPILER_FLAGS_CXX "-nostdinc++")
list(APPEND ANDROID_LINKER_FLAGS "-nostdlib++")
else()
- message(FATAL_ERROR "Invalid Android STL: ${ANDROID_STL}.")
+ message(FATAL_ERROR "Invalid STL: ${ANDROID_STL}.")
endif()
if(CMAKE_HOST_SYSTEM_NAME STREQUAL Linux)
@@ -453,8 +456,12 @@ if(ANDROID_PLATFORM_LEVEL LESS 30)
endif()
list(APPEND ANDROID_LINKER_FLAGS -Wl,--fatal-warnings)
-list(APPEND ANDROID_LINKER_FLAGS -Wl,--gc-sections)
-list(APPEND ANDROID_LINKER_FLAGS_EXE -Wl,--gc-sections)
+
+# --gc-sections should not be present for debug builds because that can strip
+# functions that the user may want to evaluate while debugging.
+list(APPEND ANDROID_LINKER_FLAGS_RELEASE -Wl,--gc-sections)
+list(APPEND ANDROID_LINKER_FLAGS_RELWITHDEBINFO -Wl,--gc-sections)
+list(APPEND ANDROID_LINKER_FLAGS_MINSIZEREL -Wl,--gc-sections)
# Debug and release flags.
list(APPEND ANDROID_COMPILER_FLAGS_RELEASE -O3)
@@ -538,6 +545,9 @@ string(REPLACE ";" " " ANDROID_COMPILER_FLAGS_DEBUG "${ANDROID_COMPILER_FLAGS_
string(REPLACE ";" " " ANDROID_COMPILER_FLAGS_RELEASE "${ANDROID_COMPILER_FLAGS_RELEASE}")
string(REPLACE ";" " " ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS}")
string(REPLACE ";" " " ANDROID_LINKER_FLAGS_EXE "${ANDROID_LINKER_FLAGS_EXE}")
+string(REPLACE ";" " " ANDROID_LINKER_FLAGS_RELEASE "${ANDROID_LINKER_FLAGS_RELEASE}")
+string(REPLACE ";" " " ANDROID_LINKER_FLAGS_RELWITHDEBINFO "${ANDROID_LINKER_FLAGS_RELWITHDEBINFO}")
+string(REPLACE ";" " " ANDROID_LINKER_FLAGS_MINSIZEREL "${ANDROID_LINKER_FLAGS_MINSIZEREL}")
if(ANDROID_CCACHE)
set(CMAKE_C_COMPILER_LAUNCHER "${ANDROID_CCACHE}")
@@ -597,6 +607,15 @@ set(CMAKE_ASM_FLAGS_RELEASE "${ANDROID_COMPILER_FLAGS_RELEASE} ${CMAKE_ASM_FLA
set(CMAKE_SHARED_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_SHARED_LINKER_FLAGS}")
set(CMAKE_MODULE_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_MODULE_LINKER_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${ANDROID_LINKER_FLAGS_EXE} ${CMAKE_EXE_LINKER_FLAGS}")
+set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${ANDROID_LINKER_FLAGS_RELEASE} ${CMAKE_SHARED_LINKER_FLAGS_RELEASE}")
+set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "${ANDROID_LINKER_FLAGS_RELEASE} ${CMAKE_MODULE_LINKER_FLAGS_RELEASE}")
+set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${ANDROID_LINKER_FLAGS_RELEASE} ${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
+set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${ANDROID_LINKER_FLAGS_RELWITHDEBINFO} ${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO}")
+set(CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO "${ANDROID_LINKER_FLAGS_RELWITHDEBINFO} ${CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO}")
+set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${ANDROID_LINKER_FLAGS_RELWITHDEBINFO} ${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}")
+set(CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL "${ANDROID_LINKER_FLAGS_MINSIZEREL} ${CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL}")
+set(CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL "${ANDROID_LINKER_FLAGS_MINSIZEREL} ${CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL}")
+set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "${ANDROID_LINKER_FLAGS_MINSIZEREL} ${CMAKE_EXE_LINKER_FLAGS_MINSIZEREL}")
# Compatibility for read-only variables.
# Read-only variables for compatibility with the other toolchain file.
diff --git a/build/cmake/flags.cmake b/build/cmake/flags.cmake
index 387f93eea..6af7e0018 100644
--- a/build/cmake/flags.cmake
+++ b/build/cmake/flags.cmake
@@ -46,6 +46,9 @@ if(CMAKE_SYSTEM_VERSION LESS 30)
endif()
string(APPEND _ANDROID_NDK_INIT_LDFLAGS " -Wl,--fatal-warnings")
+# This should only be set for release modes, but CMake doesn't provide a way for
+# us to be that specific in the new toolchain file.
+# https://github.com/android/ndk/issues/1813
string(APPEND _ANDROID_NDK_INIT_LDFLAGS " -Wl,--gc-sections")
string(APPEND _ANDROID_NDK_INIT_LDFLAGS_EXE " -Wl,--gc-sections")
diff --git a/build/core/default-build-commands.mk b/build/core/default-build-commands.mk
index 98ee438fa..208d78a16 100644
--- a/build/core/default-build-commands.mk
+++ b/build/core/default-build-commands.mk
@@ -43,7 +43,6 @@ TARGET_DISABLE_FORMAT_STRING_CFLAGS := -Wno-error=format-security
define cmd-build-shared-library
$(PRIVATE_CXX) \
- -Wl,--gc-sections \
-Wl,-soname,$(notdir $(LOCAL_BUILT_MODULE)) \
-shared \
$(PRIVATE_LINKER_OBJECTS_AND_LIBRARIES) \
@@ -59,7 +58,6 @@ endef
# this buggy behavior.
define cmd-build-executable
$(PRIVATE_CXX) \
- -Wl,--gc-sections \
-Wl,-rpath-link=$(call host-path,$(PRIVATE_SYSROOT_API_LIB_DIR)) \
-Wl,-rpath-link=$(call host-path,$(TARGET_OUT)) \
$(PRIVATE_LINKER_OBJECTS_AND_LIBRARIES) \
@@ -123,6 +121,10 @@ GLOBAL_LDFLAGS = \
-target $(LLVM_TRIPLE)$(TARGET_PLATFORM_LEVEL) \
-no-canonical-prefixes \
+ifeq ($(APP_OPTIM),release)
+ GLOBAL_LDFLAGS += -Wl,--gc-sections
+endif
+
GLOBAL_CXXFLAGS = $(GLOBAL_CFLAGS) -fno-exceptions -fno-rtti
TARGET_CFLAGS =
diff --git a/docs/changelogs/Changelog-r25.md b/docs/changelogs/Changelog-r25.md
index a83e15e34..1487f9752 100644
--- a/docs/changelogs/Changelog-r25.md
+++ b/docs/changelogs/Changelog-r25.md
@@ -12,6 +12,33 @@ directly, see the [build system maintainers guide].
[build system maintainers guide]: https://android.googlesource.com/platform/ndk/+/master/docs/BuildSystemMaintainers.md
+## Announcements
+
+* Support for KitKat (APIs 19 and 20) is planned to be removed in the next NDK
+ release. The minimum OS supported by the NDK for r26 will be Lollipop (API
+ level 21). See [Issue 1751] for details.
+
+[Issue 1751]: https://github.com/android/ndk/issues/1751
+
+## r25c
+
+* Updated LLVM to clang-r450784d1, based on LLVM 14 development.
+ * [Issue 1797]: Fixed LLDB handling of forward slashes in absolute paths on
+ Windows.
+ * [Issue 1832]: Improvements to aarch64 vector code generation.
+* [Issue 1813]: `-Wl,--gc-sections` is no longer set by default for debug
+ builds. This behavior was removed because it could cause the linker to remove
+ functions that may be useful to evaluate during debugging. The new CMake
+ toolchain file (`-DANDROID_USE_LEGACY_TOOLCHAIN_FILE=OFF`, not the default
+ behavior) does not include this fix because it requires a CMake fix first.
+* [Issue 1757]: Updated simpleperf. Includes fix for signing denial when run on
+ macOS.
+
+[Issue 1757]: https://github.com/android/ndk/issues/1757
+[Issue 1797]: https://github.com/android/ndk/issues/1797
+[Issue 1813]: https://github.com/android/ndk/issues/1813
+[Issue 1832]: https://github.com/android/ndk/issues/1832
+
## r25b
* [Issue 1739]: Fixed C compatibility issue in `amidi/AMidi.h`.
diff --git a/ndk/checkbuild.py b/ndk/checkbuild.py
index 77c5e3a2c..b156fe97f 100755
--- a/ndk/checkbuild.py
+++ b/ndk/checkbuild.py
@@ -1949,10 +1949,11 @@ class SimplePerf(ndk.builds.Module):
simpleperf_path = ndk.paths.android_path("prebuilts/simpleperf")
dirs = [
+ Path("app_api"),
+ Path("bin/android"),
Path("doc"),
Path("inferno"),
- Path("bin/android"),
- Path("app_api"),
+ Path("proto"),
Path("purgatorio"),
]
host_bin_dir = "windows" if self.host.is_windows else self.host.value
@@ -1962,11 +1963,7 @@ class SimplePerf(ndk.builds.Module):
for item in os.listdir(simpleperf_path):
should_copy = False
- if item.endswith(".py") and item not in [
- "update.py",
- "test.py",
- "test_monitor.py",
- ]:
+ if item.endswith(".py") and item != "update.py":
should_copy = True
elif item == "report_html.js":
should_copy = True
diff --git a/ndk/config.py b/ndk/config.py
index 92b44a22d..faa4cef0c 100644
--- a/ndk/config.py
+++ b/ndk/config.py
@@ -2,7 +2,7 @@ from __future__ import print_function
major = 25
-hotfix = 1
+hotfix = 2
hotfix_str = chr(ord("a") + hotfix) if hotfix else ""
beta = 0
beta_str = "-beta{}".format(beta) if beta > 0 else ""
diff --git a/ndk/pythonenv.py b/ndk/pythonenv.py
index 34690fffe..881cebae3 100644
--- a/ndk/pythonenv.py
+++ b/ndk/pythonenv.py
@@ -30,9 +30,9 @@ PYTHON_DOCS = "https://android.googlesource.com/platform/ndk/+/master/docs/Build
def python_path() -> Path:
"""Returns the absolute path to the Python executable for this OS."""
if Host.current() is Host.Linux:
- return ANDROID_DIR / "prebuilts/python/linux-x86/bin/python3.9"
+ return ANDROID_DIR / "prebuilts/python/linux-x86/bin/python3.10"
if Host.current() is Host.Darwin:
- return ANDROID_DIR / "prebuilts/python/darwin-x86/bin/python3.9"
+ return ANDROID_DIR / "prebuilts/python/darwin-x86/bin/python3.10"
return ANDROID_DIR / "prebuilts/python/windows-x86/python.exe"
diff --git a/ndk/test/builder.py b/ndk/test/builder.py
index 44d3b1555..765afa740 100644
--- a/ndk/test/builder.py
+++ b/ndk/test/builder.py
@@ -165,7 +165,9 @@ class TestBuilder:
libcxx_scanner = ndk.test.buildtest.scanner.LibcxxTestScanner(
self.test_options.ndk_path
)
- build_api_level = None # Always use the default.
+ # This is always None for the global config while building. See the comment in
+ # the definition of BuildConfiguration.
+ build_api_level = None
for abi in self.test_spec.abis:
for toolchain_file in ndk.test.spec.CMakeToolchainFile:
config = ndk.test.spec.BuildConfiguration(
diff --git a/ndk/test/buildtest/case.py b/ndk/test/buildtest/case.py
index 05b189bf7..c8d77f668 100644
--- a/ndk/test/buildtest/case.py
+++ b/ndk/test/buildtest/case.py
@@ -15,6 +15,7 @@
#
"""Build test cases."""
+from abc import ABC, abstractmethod
import fnmatch
from importlib.abc import Loader
import importlib.util
@@ -65,7 +66,7 @@ def _prep_build_dir(src_dir: Path, out_dir: Path) -> None:
shutil.copytree(src_dir, out_dir, ignore=shutil.ignore_patterns("__pycache__"))
-class Test:
+class Test(ABC):
def __init__(
self, name: str, test_dir: Path, config: BuildConfiguration, ndk_path: Path
) -> None:
@@ -73,6 +74,11 @@ class Test:
self.test_dir = test_dir
self.config = config
self.ndk_path = ndk_path
+ self.config = self.config.with_api(self.determine_api_level_for_config())
+
+ @abstractmethod
+ def determine_api_level_for_config(self) -> int:
+ ...
def get_test_config(self) -> TestConfig:
return TestConfig.from_test_dir(self.test_dir)
@@ -168,6 +174,9 @@ class BuildTest(Test):
def get_extra_ndk_build_flags(self) -> List[str]:
return self.get_test_config().extra_ndk_build_flags()
+ def get_overridden_runtime_minsdkversion(self) -> int | None:
+ return self.get_test_config().override_runtime_minsdkversion(self)
+
class PythonBuildTest(BuildTest):
"""A test that is implemented by test.py.
@@ -190,8 +199,6 @@ class PythonBuildTest(BuildTest):
def __init__(
self, name: str, test_dir: Path, config: BuildConfiguration, ndk_path: Path
) -> None:
- if config.api is None:
- config = config.with_api(ndk.abis.min_api_for_abi(config.abi))
super().__init__(name, test_dir, config, ndk_path)
if self.abi not in ndk.abis.ALL_ABIS:
@@ -203,6 +210,9 @@ class PythonBuildTest(BuildTest):
except ValueError as ex:
raise ValueError(f"{self.api} is not a valid API number") from ex
+ def determine_api_level_for_config(self) -> int:
+ return ndk.abis.min_api_for_abi(self.config.abi)
+
def get_build_dir(self, out_dir: Path) -> Path:
return out_dir / str(self.config) / "test.py" / self.name
@@ -228,12 +238,8 @@ class PythonBuildTest(BuildTest):
class ShellBuildTest(BuildTest):
- def __init__(
- self, name: str, test_dir: Path, config: BuildConfiguration, ndk_path: Path
- ) -> None:
- if config.api is None:
- config = config.with_api(ndk.abis.min_api_for_abi(config.abi))
- super().__init__(name, test_dir, config, ndk_path)
+ def determine_api_level_for_config(self) -> int:
+ return ndk.abis.min_api_for_abi(self.config.abi)
def get_build_dir(self, out_dir: Path) -> Path:
return out_dir / str(self.config) / "build.sh" / self.name
@@ -317,25 +323,29 @@ def _platform_from_application_mk(test_dir: Path) -> Optional[int]:
def _get_or_infer_app_platform(
- platform_from_user: Optional[int], test_dir: Path, abi: Abi
+ overridden_runtime_minsdkversion: int | None,
+ test_dir: Path,
+ abi: Abi,
) -> int:
"""Determines the platform level to use for a test using ndk-build.
Choose the platform level from, in order of preference:
- 1. Value given as argument.
+ 1. The value forced by the test_config.py using override_runtime_minsdkversion.
2. APP_PLATFORM from jni/Application.mk.
3. Default value for the target ABI.
Args:
- platform_from_user: A user provided platform level or None.
+ overridden_runtime_minsdkversion: The test's forced runtime minSdkVersion. Might
+ differ from the build API level. This is rare (probably only static
+ executables).
test_dir: The directory containing the ndk-build project.
abi: The ABI being targeted.
Returns:
The platform version the test should build against.
"""
- if platform_from_user is not None:
- return platform_from_user
+ if overridden_runtime_minsdkversion is not None:
+ return overridden_runtime_minsdkversion
minimum_version = ndk.abis.min_api_for_abi(abi)
platform_from_application_mk = _platform_from_application_mk(test_dir)
@@ -355,13 +365,16 @@ class NdkBuildTest(BuildTest):
ndk_path: Path,
dist: bool,
) -> None:
- if config.api is None:
- config = config.with_api(
- _get_or_infer_app_platform(config.api, test_dir, config.abi)
- )
super().__init__(name, test_dir, config, ndk_path)
self.dist = dist
+ def determine_api_level_for_config(self) -> int:
+ return _get_or_infer_app_platform(
+ self.get_overridden_runtime_minsdkversion(),
+ self.test_dir,
+ self.config.abi,
+ )
+
def get_dist_dir(self, obj_dir: Path, dist_dir: Path) -> Path:
if self.dist:
return self.get_build_dir(dist_dir)
@@ -384,7 +397,6 @@ class NdkBuildTest(BuildTest):
self.ndk_path,
self.ndk_build_flags,
self.abi,
- self.api,
)
if (failure := self.verify_no_cruft_in_dist(dist_dir, proc.args)) is not None:
return failure, []
@@ -398,13 +410,11 @@ def _run_ndk_build_test(
ndk_path: Path,
ndk_build_flags: List[str],
abi: Abi,
- platform: int,
) -> CompletedProcess[str]:
_prep_build_dir(test_dir, obj_dir)
with ndk.ext.os.cd(obj_dir):
args = [
f"APP_ABI={abi}",
- f"APP_PLATFORM=android-{platform}",
f"NDK_LIBS_OUT={dist_dir}",
] + _get_jobs_args()
return ndk.ndkbuild.build(ndk_path, args + ndk_build_flags)
@@ -419,13 +429,16 @@ class CMakeBuildTest(BuildTest):
ndk_path: Path,
dist: bool,
) -> None:
- if config.api is None:
- config = config.with_api(
- _get_or_infer_app_platform(config.api, test_dir, config.abi)
- )
super().__init__(name, test_dir, config, ndk_path)
self.dist = dist
+ def determine_api_level_for_config(self) -> int:
+ return _get_or_infer_app_platform(
+ self.get_overridden_runtime_minsdkversion(),
+ self.test_dir,
+ self.config.abi,
+ )
+
def get_dist_dir(self, obj_dir: Path, dist_dir: Path) -> Path:
if self.dist:
return self.get_build_dir(dist_dir)
@@ -448,7 +461,6 @@ class CMakeBuildTest(BuildTest):
self.ndk_path,
self.cmake_flags,
self.abi,
- self.api,
self.config.toolchain_file == CMakeToolchainFile.Legacy,
)
if (failure := self.verify_no_cruft_in_dist(dist_dir, proc.args)) is not None:
@@ -463,7 +475,6 @@ def _run_cmake_build_test(
ndk_path: Path,
cmake_flags: List[str],
abi: str,
- platform: int,
use_legacy_toolchain_file: bool,
) -> CompletedProcess[str]:
_prep_build_dir(test_dir, obj_dir)
@@ -484,14 +495,12 @@ def _run_cmake_build_test(
"-GNinja",
f"-DCMAKE_MAKE_PROGRAM={ninja_bin}",
]
- if platform is not None:
- args.append("-DANDROID_PLATFORM=android-{}".format(platform))
if use_legacy_toolchain_file:
args.append("-DANDROID_USE_LEGACY_TOOLCHAIN_FILE=ON")
else:
args.append("-DANDROID_USE_LEGACY_TOOLCHAIN_FILE=OFF")
proc = subprocess.run(
- [str(cmake_bin)] + cmake_flags + args,
+ [str(cmake_bin)] + args + cmake_flags,
check=False,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
@@ -615,12 +624,8 @@ def find_original_libcxx_test(name: str) -> List[str]:
class LibcxxTest(Test):
- def __init__(
- self, name: str, test_dir: Path, config: BuildConfiguration, ndk_path: Path
- ) -> None:
- if config.api is None:
- config = config.with_api(ndk.abis.min_api_for_abi(config.abi))
- super().__init__(name, test_dir, config, ndk_path)
+ def determine_api_level_for_config(self) -> int:
+ return ndk.abis.min_api_for_abi(self.config.abi)
@property
def abi(self) -> Abi:
@@ -814,6 +819,13 @@ class XunitResult(Test):
super().__init__(name, test_dir, config, ndk_path)
self.test_base_dir = test_base_dir
+ def determine_api_level_for_config(self) -> int:
+ # This type of test is the rare one where the API level is already determined
+ # because this test is an odd synthetic test created for the benefit of the UI,
+ # rather than reporting all libc++ test status under a single test report.
+ assert self.config.api is not None
+ return self.config.api
+
@property
def case_name(self) -> str:
return os.path.splitext(os.path.basename(self.name))[0]
diff --git a/ndk/test/config.py b/ndk/test/config.py
index 5a46a91aa..5a1e6de25 100644
--- a/ndk/test/config.py
+++ b/ndk/test/config.py
@@ -116,6 +116,20 @@ class TestConfig:
"""
return False
+ @staticmethod
+ def override_runtime_minsdkversion(test: Test) -> int | None:
+ """Overrides the minSdkVersion that will be used for determining OS compat.
+
+ Static executables have the unusual build requirement that they always be
+ built with the latest API level, but are compatible with old devices. We
+ need to specify `APP_PLATFORM := latest` for those tests, but the test
+ runner needs to run them on old devices. There isn't an easy way to infer
+ this, nor are there many static executable tests, so those tests instead
+ override their minSdkVersion rather than letting the test builder infer it
+ from APP_PLATFORM.
+ """
+ return None
+
# pylint: enable=unused-argument
def __init__(self, test_config_py: Path) -> None:
@@ -166,6 +180,15 @@ class TestConfig:
except AttributeError:
self.is_negative_test = self.NullTestConfig.is_negative_test
+ try:
+ self.override_runtime_minsdkversion: Callable[
+ [Test], int | None
+ ] = self.module.override_runtime_minsdkversion # type: ignore
+ except AttributeError:
+ self.override_runtime_minsdkversion = (
+ self.NullTestConfig.override_runtime_minsdkversion
+ )
+
@classmethod
def from_test_dir(cls, test_dir: Path) -> "TestConfig":
return cls(test_dir / "test_config.py")
diff --git a/ndk/test/spec.py b/ndk/test/spec.py
index c7ade3e88..33a3494c6 100644
--- a/ndk/test/spec.py
+++ b/ndk/test/spec.py
@@ -100,6 +100,13 @@ class BuildConfiguration:
"""
abi: Abi
+ # This is always None for the global config while building. Each test will fill in
+ # the appropriate value for the test (based on `APP_PLATFORM` or similar). It is
+ # still a part of the BuildConfiguration class because we do not have separate
+ # classes for build config *input* (the BuildConfiguration created by
+ # TestBuilder.find_tests) and build config *output* (the result decided and
+ # serialized by the test, which needs to be read when the test is later run by
+ # run_tests.py).
api: Optional[int]
toolchain_file: CMakeToolchainFile
diff --git a/ndk/testing/flag_verifier.py b/ndk/testing/flag_verifier.py
index cb514a26c..97b2caf4d 100644
--- a/ndk/testing/flag_verifier.py
+++ b/ndk/testing/flag_verifier.py
@@ -36,9 +36,15 @@ class FlagVerifierResult:
"""Returns True if verification failed."""
raise NotImplementedError
- def make_test_result_tuple(self) -> tuple[bool, Optional[str]]:
+ def make_test_result_tuple(
+ self, message_prefix: str | None = None
+ ) -> tuple[bool, Optional[str]]:
"""Creates a test result tuple in the format expect by run_test."""
- return not self.failed(), self.error_message
+ if message_prefix is None:
+ message = self.error_message
+ else:
+ message = f"{message_prefix}\n{self.error_message}"
+ return not self.failed(), message
class FlagVerifierSuccess(FlagVerifierResult):
@@ -77,11 +83,23 @@ class FlagVerifier:
self.toolchain_mode = "OFF"
self.expected_flags: list[str] = []
self.not_expected_flags: list[str] = []
+ self.ndk_build_flags: list[str] = []
+ self.cmake_flags: list[str] = []
def with_api(self, api: int) -> FlagVerifier:
self.api = api
return self
+ def with_ndk_build_flag(self, flag: str) -> FlagVerifier:
+ """Appends a flag to the list of arguments that will be passed to ndk-build."""
+ self.ndk_build_flags.append(flag)
+ return self
+
+ def with_cmake_flag(self, flag: str) -> FlagVerifier:
+ """Appends a flag to the list of arguments that will be passed to CMake."""
+ self.cmake_flags.append(flag)
+ return self
+
def expect_flag(self, flag: str) -> None:
"""Verify that the given string is present in the build output.
@@ -169,20 +187,15 @@ class FlagVerifier:
"V=1",
f"APP_ABI={self.abi}",
f"APP_PLATFORM=android-{self.api}",
- ]
+ ] + self.ndk_build_flags
)
- def verify_cmake(
- self, cmake_flags: Optional[list[str]] = None
- ) -> FlagVerifierResult:
+ def verify_cmake(self) -> FlagVerifierResult:
"""Verifies that CMake behaves as specified.
Returns:
A FlagVerifierResult object describing the verification result.
"""
- if cmake_flags is None:
- cmake_flags = []
-
host = Host.current()
if host == Host.Windows64:
tag = "windows-x86"
@@ -211,7 +224,7 @@ class FlagVerifier:
f"-DANDROID_USE_LEGACY_TOOLCHAIN_FILE={self.toolchain_mode}",
"-GNinja",
f"-DCMAKE_MAKE_PROGRAM={ninja}",
- ] + cmake_flags
+ ] + self.cmake_flags
result = subprocess.run(
cmd,
check=False,
diff --git a/ndk/toolchains.py b/ndk/toolchains.py
index 66cd8f5a3..641eb292d 100644
--- a/ndk/toolchains.py
+++ b/ndk/toolchains.py
@@ -22,7 +22,7 @@ from ndk.hosts import Host, get_default_host
import ndk.paths
-CLANG_VERSION = "clang-r450784d"
+CLANG_VERSION = "clang-r450784d1"
HOST_TRIPLE_MAP = {
diff --git a/tests/build/cmake_default_flags/test.py b/tests/build/cmake_default_flags/test.py
index ca367a299..3cab3f289 100644
--- a/tests/build/cmake_default_flags/test.py
+++ b/tests/build/cmake_default_flags/test.py
@@ -28,12 +28,14 @@ def check_configuration(
expected_flags: list[str],
unexpected_flags: list[str],
) -> FlagVerifierResult:
- verifier = FlagVerifier(Path("project"), Path(ndk_path), build_config)
+ verifier = FlagVerifier(
+ Path("project"), Path(ndk_path), build_config
+ ).with_cmake_flag(f"-DCMAKE_BUILD_TYPE={cmake_config}")
for flag in expected_flags:
verifier.expect_flag(flag)
for flag in unexpected_flags:
verifier.expect_not_flag(flag)
- return verifier.verify_cmake([f"-DCMAKE_BUILD_TYPE={cmake_config}"])
+ return verifier.verify_cmake()
def run_test(ndk_path: str, config: BuildConfiguration) -> tuple[bool, Optional[str]]:
diff --git a/tests/build/gc_sections/test.py b/tests/build/gc_sections/test.py
index 419cae12b..8bb436a58 100644
--- a/tests/build/gc_sections/test.py
+++ b/tests/build/gc_sections/test.py
@@ -13,9 +13,13 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-"""Check that -Wl,--gc-sections is used.
+"""Check that -Wl,--gc-sections is used, but only on release builds.
+
+This flag should not be present for debug builds because that can strip functions that
+the user may want to evaluate while debugging.
https://github.com/android/ndk/issues/1717
+https://github.com/android/ndk/issues/1813
"""
from pathlib import Path
from typing import Optional
@@ -27,5 +31,37 @@ from ndk.testing.flag_verifier import FlagVerifier
def run_test(ndk_path: str, config: BuildConfiguration) -> tuple[bool, Optional[str]]:
"""Checks correct --gc-sections use."""
verifier = FlagVerifier(Path("project"), Path(ndk_path), config)
+ verifier.with_cmake_flag("-DCMAKE_BUILD_TYPE=Release")
+ verifier.with_ndk_build_flag("APP_DEBUG=false")
verifier.expect_flag("-Wl,--gc-sections")
- return verifier.verify().make_test_result_tuple()
+ passed, message = verifier.verify().make_test_result_tuple(
+ "With -DCMAKE_BUILD_TYPE=Release and APP_DEBUG=false"
+ )
+ if not passed:
+ return passed, message
+
+ verifier = FlagVerifier(Path("project"), Path(ndk_path), config)
+ verifier.with_cmake_flag("-DCMAKE_BUILD_TYPE=RelWithDebInfo")
+ verifier.expect_flag("-Wl,--gc-sections")
+ passed, message = verifier.verify_cmake().make_test_result_tuple(
+ "With -DCMAKE_BUILD_TYPE=RelWithDebInfo"
+ )
+ if not passed:
+ return passed, message
+
+ verifier = FlagVerifier(Path("project"), Path(ndk_path), config)
+ verifier.with_cmake_flag("-DCMAKE_BUILD_TYPE=MinSizeRel")
+ verifier.expect_flag("-Wl,--gc-sections")
+ passed, message = verifier.verify_cmake().make_test_result_tuple(
+ "With -DCMAKE_BUILD_TYPE=MinSizeRel"
+ )
+ if not passed:
+ return passed, message
+
+ verifier = FlagVerifier(Path("project"), Path(ndk_path), config)
+ verifier.with_cmake_flag("-DCMAKE_BUILD_TYPE=Debug")
+ verifier.with_ndk_build_flag("APP_DEBUG=true")
+ verifier.expect_not_flag("-Wl,--gc-sections")
+ return verifier.verify().make_test_result_tuple(
+ "With -DCMAKE_BUILD_TYPE=Debug and APP_DEBUG=true"
+ )
diff --git a/tests/build/gc_sections/test_config.py b/tests/build/gc_sections/test_config.py
new file mode 100644
index 000000000..869627d3a
--- /dev/null
+++ b/tests/build/gc_sections/test_config.py
@@ -0,0 +1,8 @@
+from ndk.test.buildtest.case import Test
+from ndk.test.spec import CMakeToolchainFile
+
+
+def build_broken(test: Test) -> tuple[str | None, str | None]:
+ if test.config.toolchain_file is CMakeToolchainFile.Default:
+ return "new CMake toolchain", "https://github.com/android/ndk/issues/1813"
+ return None, None
diff --git a/tests/device/static-executable-exceptions/jni/Application.mk b/tests/device/static-executable-exceptions/jni/Application.mk
index 2133d20c6..9ec531a2a 100644
--- a/tests/device/static-executable-exceptions/jni/Application.mk
+++ b/tests/device/static-executable-exceptions/jni/Application.mk
@@ -1 +1 @@
-APP_PLATFORM := android-21
+APP_PLATFORM := latest
diff --git a/tests/device/static-executable-exceptions/test_config.py b/tests/device/static-executable-exceptions/test_config.py
index 9eea1ae14..59c5cabde 100644
--- a/tests/device/static-executable-exceptions/test_config.py
+++ b/tests/device/static-executable-exceptions/test_config.py
@@ -1,7 +1,13 @@
-def build_unsupported(test):
- # Static executables with libc++ require targeting a new enough API level
- # to not need libandroid_support.
- if test.config.api < 21:
- return f"android-{test.config.api}"
+import ndk.abis
+from ndk.test.buildtest.case import Test
- return None
+
+def extra_cmake_flags() -> list[str]:
+ # Required for static executables.
+ return ["-DANDROID_PLATFORM=latest"]
+
+
+def override_runtime_minsdkversion(test: Test) -> int | None:
+ # We build as latest because static executables require that, but static executables
+ # are compatible with old OS versions.
+ return ndk.abis.min_api_for_abi(test.config.abi)
diff --git a/tests/device/static-executable/jni/Application.mk b/tests/device/static-executable/jni/Application.mk
new file mode 100644
index 000000000..9ec531a2a
--- /dev/null
+++ b/tests/device/static-executable/jni/Application.mk
@@ -0,0 +1 @@
+APP_PLATFORM := latest
diff --git a/tests/device/static-executable/test_config.py b/tests/device/static-executable/test_config.py
index 481aecaba..59c5cabde 100644
--- a/tests/device/static-executable/test_config.py
+++ b/tests/device/static-executable/test_config.py
@@ -1,5 +1,13 @@
-def extra_cmake_flags():
- # Match the ndk-build test. Using libc++ here would require us to target a
- # newer API level since static executables and libandroid_support don't
- # mix.
- return ["-DANDROID_STL=system"]
+import ndk.abis
+from ndk.test.buildtest.case import Test
+
+
+def extra_cmake_flags() -> list[str]:
+ # Required for static executables.
+ return ["-DANDROID_PLATFORM=latest"]
+
+
+def override_runtime_minsdkversion(test: Test) -> int | None:
+ # We build as latest because static executables require that, but static executables
+ # are compatible with old OS versions.
+ return ndk.abis.min_api_for_abi(test.config.abi)