diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-01-21 01:47:31 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2023-01-21 01:47:31 +0000 |
commit | e52b1c3b7b38a89aa1643631e8e4fb407f9d8757 (patch) | |
tree | 10f966b91a8e84e59186406e652b6af89d8a5cdc | |
parent | 22826f79b23aa59c6bd9286d890de0a93e3ac7a3 (diff) | |
parent | f088e1a97715f0bb1df5f9f2bd5199de567c0c74 (diff) | |
download | ndk-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.cmake | 25 | ||||
-rw-r--r-- | build/cmake/flags.cmake | 3 | ||||
-rw-r--r-- | build/core/default-build-commands.mk | 6 | ||||
-rw-r--r-- | docs/changelogs/Changelog-r25.md | 27 | ||||
-rwxr-xr-x | ndk/checkbuild.py | 11 | ||||
-rw-r--r-- | ndk/config.py | 2 | ||||
-rw-r--r-- | ndk/pythonenv.py | 4 | ||||
-rw-r--r-- | ndk/test/builder.py | 4 | ||||
-rw-r--r-- | ndk/test/buildtest/case.py | 84 | ||||
-rw-r--r-- | ndk/test/config.py | 23 | ||||
-rw-r--r-- | ndk/test/spec.py | 7 | ||||
-rw-r--r-- | ndk/testing/flag_verifier.py | 33 | ||||
-rw-r--r-- | ndk/toolchains.py | 2 | ||||
-rw-r--r-- | tests/build/cmake_default_flags/test.py | 6 | ||||
-rw-r--r-- | tests/build/gc_sections/test.py | 40 | ||||
-rw-r--r-- | tests/build/gc_sections/test_config.py | 8 | ||||
-rw-r--r-- | tests/device/static-executable-exceptions/jni/Application.mk | 2 | ||||
-rw-r--r-- | tests/device/static-executable-exceptions/test_config.py | 18 | ||||
-rw-r--r-- | tests/device/static-executable/jni/Application.mk | 1 | ||||
-rw-r--r-- | tests/device/static-executable/test_config.py | 18 |
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) |