Android: Use unified toolchain in NDK r19+

The NDK build system now uses only a single toolchain in

    <ndk>/toolchains/llvm/prebuilt/<host>

Its compilers are always `bin/{clang,clang++}` and its binutils are
always `bin/<triple>-*`.  It is a standalone toolchain:

* The Anrdoid API level is specified at the end of `--target=`.
* The standard library may be specified via `-stdlib=`.
* No need to pass system includes or libraries explicitly.
* No need to pass `--sysroot` or `-gcc-toolchain`.

Teach CMake to recognize NDK versions that have a unified
toolchain with its own sysroot and use the above approach.

Fixes: #18739
This commit is contained in:
Brad King
2019-07-26 12:48:35 -04:00
parent 19f36c5fb2
commit 97bca2f9fa
18 changed files with 106 additions and 18 deletions

View File

@@ -399,8 +399,10 @@ Configure use of an Android NDK with the following variables:
be false unless using a NDK that does not provide unified headers.
:variable:`CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION`
Set to the version of the NDK toolchain to be selected as the compiler.
If not specified, the default will be the latest available GCC toolchain.
On NDK r19 or above, this variable must be unset or set to ``clang``.
On NDK r18 or below, set this to the version of the NDK toolchain to
be selected as the compiler. If not specified, the default will be
the latest available GCC toolchain.
:variable:`CMAKE_ANDROID_STL_TYPE`
Set to specify which C++ standard library to use. If not specified,

View File

@@ -3,7 +3,11 @@ CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION
When :ref:`Cross Compiling for Android with the NDK`, this variable
may be set to specify the version of the toolchain to be used
as the compiler. The variable must be set to one of these forms:
as the compiler.
On NDK r19 or above, this variable must be unset or set to ``clang``.
On NDK r18 or below, this variable must be set to one of these forms:
* ``<major>.<minor>``: GCC of specified version
* ``clang<major>.<minor>``: Clang of specified version

View File

@@ -40,6 +40,9 @@ macro(__android_compiler_clang lang)
endif()
if(NOT CMAKE_${lang}_COMPILER_TARGET)
set(CMAKE_${lang}_COMPILER_TARGET "${_ANDROID_ABI_CLANG_TARGET}")
if(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED)
string(APPEND CMAKE_${lang}_COMPILER_TARGET "${CMAKE_SYSTEM_VERSION}")
endif()
list(APPEND CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND "--target=${CMAKE_${lang}_COMPILER_TARGET}")
endif()
endmacro()

View File

@@ -47,7 +47,41 @@ if(CMAKE_ANDROID_NDK)
endif()
if(CMAKE_ANDROID_STL_TYPE)
if(CMAKE_ANDROID_NDK)
if(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED)
if(CMAKE_ANDROID_STL_TYPE STREQUAL "system")
set(_ANDROID_STL_EXCEPTIONS 0)
set(_ANDROID_STL_RTTI 0)
macro(__android_stl lang)
string(APPEND CMAKE_${lang}_FLAGS_INIT " -stdlib=libstdc++")
endmacro()
elseif(CMAKE_ANDROID_STL_TYPE STREQUAL "c++_static")
set(_ANDROID_STL_EXCEPTIONS 1)
set(_ANDROID_STL_RTTI 1)
macro(__android_stl lang)
string(APPEND CMAKE_${lang}_FLAGS_INIT " -stdlib=libc++")
string(APPEND CMAKE_${lang}_STANDARD_LIBRARIES " -static-libstdc++")
endmacro()
elseif(CMAKE_ANDROID_STL_TYPE STREQUAL "c++_shared")
set(_ANDROID_STL_EXCEPTIONS 1)
set(_ANDROID_STL_RTTI 1)
macro(__android_stl lang)
string(APPEND CMAKE_${lang}_FLAGS_INIT " -stdlib=libc++")
endmacro()
elseif(CMAKE_ANDROID_STL_TYPE STREQUAL "none")
set(_ANDROID_STL_RTTI 0)
set(_ANDROID_STL_EXCEPTIONS 0)
macro(__android_stl lang)
# FIXME: Add a way to add project-wide language-specific compile-only flags.
set(CMAKE_CXX_COMPILE_OBJECT
"<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE> -nostdinc++")
string(APPEND CMAKE_${lang}_STANDARD_LIBRARIES " -nostdlib++")
endmacro()
else()
message(FATAL_ERROR
"Android: STL '${CMAKE_ANDROID_STL_TYPE}' not supported by this NDK."
)
endif()
elseif(CMAKE_ANDROID_NDK)
macro(__android_stl_inc lang dir req)
if(EXISTS "${dir}")
@@ -152,6 +186,10 @@ macro(__android_compiler_common lang)
__android_stl(CXX)
endif()
if(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED)
string(APPEND CMAKE_${lang}_STANDARD_LIBRARIES " -latomic -lm")
endif()
# <ndk>/build/core/definitions.mk appends the sysroot's include directory
# explicitly at the end of the command-line include path so that it
# precedes the toolchain's builtin include directories. This is
@@ -161,7 +199,7 @@ macro(__android_compiler_common lang)
#
# Do not do this for a standalone toolchain because it is already
# tied to a specific API version.
if(CMAKE_ANDROID_NDK)
if(CMAKE_ANDROID_NDK AND NOT CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED)
if(CMAKE_SYSROOT_COMPILE)
set(_cmake_sysroot_compile "${CMAKE_SYSROOT_COMPILE}")
else()

View File

@@ -221,8 +221,15 @@ if(CMAKE_ANDROID_NDK)
else()
message(FATAL_ERROR "Android: Builds hosted on '${CMAKE_HOST_SYSTEM_NAME}' not supported.")
endif()
# Look for a unified toolchain/sysroot provided with the NDK.
set(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED "${CMAKE_ANDROID_NDK}/toolchains/llvm/prebuilt/${CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG}")
if(NOT IS_DIRECTORY "${CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED}/sysroot")
set(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED "")
endif()
else()
set(CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG "")
set(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED "")
endif()
# https://developer.android.com/ndk/guides/abis.html
@@ -370,6 +377,7 @@ if(CMAKE_ANDROID_NDK)
"set(CMAKE_ANDROID_ARCH_TRIPLE \"${CMAKE_ANDROID_ARCH_TRIPLE}\")\n"
"set(CMAKE_ANDROID_NDK_DEPRECATED_HEADERS \"${CMAKE_ANDROID_NDK_DEPRECATED_HEADERS}\")\n"
"set(CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG \"${CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG}\")\n"
"set(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED \"${CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED}\")\n"
)
endif()

View File

@@ -19,6 +19,11 @@ endif()
set(CMAKE_BUILD_TYPE_INIT Debug)
# Skip sysroot selection if the NDK has a unified toolchain.
if(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED)
return()
endif()
if(NOT CMAKE_SYSROOT)
if(CMAKE_ANDROID_NDK)
set(CMAKE_SYSROOT "${CMAKE_ANDROID_NDK}/platforms/android-${CMAKE_SYSTEM_VERSION}/arch-${CMAKE_ANDROID_ARCH}")

View File

@@ -1,6 +1,31 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
# In Android NDK r19 and above there is a single clang toolchain.
if(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED)
if(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION AND NOT CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION STREQUAL "clang")
message(FATAL_ERROR
"Android: The CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION value '${CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION}' "
"is not supported by this NDK. It must be 'clang' or not set at all."
)
endif()
message(STATUS "Android: Selected unified Clang toolchain")
set(_ANDROID_TOOL_NDK_TOOLCHAIN_VERSION "clang")
set(_ANDROID_TOOL_C_COMPILER "${CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED}/bin/clang${_ANDROID_HOST_EXT}")
set(_ANDROID_TOOL_C_TOOLCHAIN_MACHINE "${CMAKE_ANDROID_ARCH_TRIPLE}")
set(_ANDROID_TOOL_C_TOOLCHAIN_VERSION "")
set(_ANDROID_TOOL_C_COMPILER_EXTERNAL_TOOLCHAIN "")
set(_ANDROID_TOOL_C_TOOLCHAIN_PREFIX "${CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED}/bin/${CMAKE_ANDROID_ARCH_TRIPLE}-")
set(_ANDROID_TOOL_C_TOOLCHAIN_SUFFIX "${_ANDROID_HOST_EXT}")
set(_ANDROID_TOOL_CXX_COMPILER "${CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED}/bin/clang++${_ANDROID_HOST_EXT}")
set(_ANDROID_TOOL_CXX_TOOLCHAIN_MACHINE "${CMAKE_ANDROID_ARCH_TRIPLE}")
set(_ANDROID_TOOL_CXX_TOOLCHAIN_VERSION "")
set(_ANDROID_TOOL_CXX_COMPILER_EXTERNAL_TOOLCHAIN "")
set(_ANDROID_TOOL_CXX_TOOLCHAIN_PREFIX "${CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED}/bin/${CMAKE_ANDROID_ARCH_TRIPLE}-")
set(_ANDROID_TOOL_CXX_TOOLCHAIN_SUFFIX "${_ANDROID_HOST_EXT}")
return()
endif()
# In Android NDK releases there is build system toolchain selection logic in
# these files:
#

View File

@@ -3,7 +3,7 @@ string(APPEND _ANDROID_ABI_INIT_CFLAGS
" -no-canonical-prefixes"
)
if(CMAKE_ANDROID_NDK AND NOT CMAKE_ANDROID_NDK_DEPRECATED_HEADERS)
if(CMAKE_ANDROID_NDK AND NOT CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED AND NOT CMAKE_ANDROID_NDK_DEPRECATED_HEADERS)
string(APPEND _ANDROID_ABI_INIT_CFLAGS " -D__ANDROID_API__=${CMAKE_SYSTEM_VERSION}")
endif()

View File

@@ -1,2 +1,2 @@
-- Android: Targeting API '[0-9]+' with architecture 'arm64', ABI 'arm64-v8a', and processor 'aarch64'
-- Android: Selected (Clang toolchain '[^']+' with )?GCC toolchain '[^']+'
-- Android: Selected (unified Clang toolchain|(Clang toolchain '[^']+' with )?GCC toolchain '[^']+')

View File

@@ -1,3 +1,3 @@
-- Android: Targeting API '[0-9]+' with architecture 'arm', ABI 'armeabi', and processor 'armv5te'
-- Android: Selected (Clang toolchain '[^']+' with )?GCC toolchain '[^']+'
-- Android: Selected (unified Clang toolchain|(Clang toolchain '[^']+' with )?GCC toolchain '[^']+')
.*-- CMAKE_ANDROID_ARM_MODE=1

View File

@@ -1,3 +1,3 @@
-- Android: Targeting API '[0-9]+' with architecture 'arm', ABI 'armeabi-v7a', and processor 'armv7-a'
-- Android: Selected (Clang toolchain '[^']+' with )?GCC toolchain '[^']+'
-- Android: Selected (unified Clang toolchain|(Clang toolchain '[^']+' with )?GCC toolchain '[^']+')
.*-- CMAKE_ANDROID_ARM_NEON=1

View File

@@ -1,3 +1,3 @@
-- Android: Targeting API '[0-9]+' with architecture 'arm', ABI 'armeabi-v7a', and processor 'armv7-a'
-- Android: Selected (Clang toolchain '[^']+' with )?GCC toolchain '[^']+'
-- Android: Selected (unified Clang toolchain|(Clang toolchain '[^']+' with )?GCC toolchain '[^']+')
.*-- CMAKE_ANDROID_ARM_NEON=0

View File

@@ -1,11 +1,12 @@
^CMake Error at .*/Modules/Platform/Android/Determine-Compiler-NDK.cmake:[0-9]+ \(message\):
Android: The CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION value 'badver' is not one
Android: The CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION value 'badver' is not(
supported by this NDK. It must be 'clang' or not set at all\.| one
of the allowed forms:
<major>.<minor> = GCC of specified version
clang<major>.<minor> = Clang of specified version
clang = Clang of most recent available version
)
Call Stack \(most recent call first\):
.*
ndk-badver.cmake:1 \(enable_language\)

View File

@@ -1,4 +1,6 @@
^CMake Error at .*/Modules/Platform/Android/Determine-Compiler-NDK.cmake:[0-9]+ \(message\):
^CMake Error at .*/Modules/Platform/Android/Determine-Compiler-NDK.cmake:[0-9]+ \(message\):(
Android: The CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION value '1.0' is not
supported by this NDK. It must be 'clang' or not set at all.|
Android: No toolchain for ABI 'armeabi(-v7a)?' found in the NDK:
.*
@@ -6,7 +8,7 @@
of the version specified by CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION:
1\.0
)
Call Stack \(most recent call first\):
.*
ndk-badvernum.cmake:1 \(enable_language\)

View File

@@ -1,2 +1,2 @@
-- Android: Targeting API '[0-9]+' with architecture 'mips', ABI 'mips', and processor 'mips'
-- Android: Selected (Clang toolchain '[^']+' with )?GCC toolchain '[^']+'
-- Android: Selected (unified Clang toolchain|(Clang toolchain '[^']+' with )?GCC toolchain '[^']+')

View File

@@ -1,2 +1,2 @@
-- Android: Targeting API '[0-9]+' with architecture 'mips64', ABI 'mips64', and processor 'mips64'
-- Android: Selected (Clang toolchain '[^']+' with )?GCC toolchain '[^']+'
-- Android: Selected (unified Clang toolchain|(Clang toolchain '[^']+' with )?GCC toolchain '[^']+')

View File

@@ -1,2 +1,2 @@
-- Android: Targeting API '[0-9]+' with architecture 'x86', ABI 'x86', and processor 'i686'
-- Android: Selected (Clang toolchain '[^']+' with )?GCC toolchain '[^']+'
-- Android: Selected (unified Clang toolchain|(Clang toolchain '[^']+' with )?GCC toolchain '[^']+')

View File

@@ -1,2 +1,2 @@
-- Android: Targeting API '[0-9]+' with architecture 'x86_64', ABI 'x86_64', and processor 'x86_64'
-- Android: Selected (Clang toolchain '[^']+' with )?GCC toolchain '[^']+'
-- Android: Selected (unified Clang toolchain|(Clang toolchain '[^']+' with )?GCC toolchain '[^']+')