blob: b01340eb4a11e546cca25a2fd07a47e5417a6683 [file] [log] [blame]
# Copyright (C) 2016 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Configurable variables.
# Modeled after the ndk-build system.
# For any variables defined in:
# https://developer.android.com/ndk/guides/android_mk.html
# https://developer.android.com/ndk/guides/application_mk.html
# if it makes sense for CMake, then replace LOCAL, APP, or NDK with ANDROID, and
# we have that variable below.
#
# ANDROID_TOOLCHAIN
# ANDROID_ABI
# ANDROID_PLATFORM
# ANDROID_STL
# ANDROID_PIE
# ANDROID_CPP_FEATURES
# ANDROID_ALLOW_UNDEFINED_SYMBOLS
# ANDROID_ARM_MODE
# ANDROID_ARM_NEON
# ANDROID_DISABLE_FORMAT_STRING_CHECKS
# ANDROID_CCACHE
cmake_minimum_required(VERSION 3.6.0)
# CMake invokes the toolchain file twice during the first build, but only once
# during subsequent rebuilds. This was causing the various flags to be added
# twice on the first build, and on a rebuild ninja would see only one set of the
# flags and rebuild the world.
# https://github.com/android-ndk/ndk/issues/323
if(ANDROID_NDK_TOOLCHAIN_INCLUDED)
return()
endif(ANDROID_NDK_TOOLCHAIN_INCLUDED)
set(ANDROID_NDK_TOOLCHAIN_INCLUDED true)
if(DEFINED ANDROID_USE_LEGACY_TOOLCHAIN_FILE)
set(_USE_LEGACY_TOOLCHAIN_FILE ${ANDROID_USE_LEGACY_TOOLCHAIN_FILE})
elseif(CMAKE_VERSION VERSION_LESS "3.21")
set(_USE_LEGACY_TOOLCHAIN_FILE true)
else()
set(_USE_LEGACY_TOOLCHAIN_FILE false)
endif()
if(_USE_LEGACY_TOOLCHAIN_FILE)
include("${CMAKE_CURRENT_LIST_DIR}/android-legacy.toolchain.cmake")
return()
endif()
# Android NDK path
get_filename_component(ANDROID_NDK_EXPECTED_PATH
"${CMAKE_CURRENT_LIST_DIR}/../.." ABSOLUTE)
if(NOT ANDROID_NDK)
set(CMAKE_ANDROID_NDK "${ANDROID_NDK_EXPECTED_PATH}")
else()
# Allow the user to specify their own NDK path, but emit a warning. This is an
# uncommon use case, but helpful if users want to use a bleeding edge
# toolchain file with a stable NDK.
# https://github.com/android-ndk/ndk/issues/473
get_filename_component(ANDROID_NDK "${ANDROID_NDK}" ABSOLUTE)
if(NOT "${ANDROID_NDK}" STREQUAL "${ANDROID_NDK_EXPECTED_PATH}")
message(WARNING "Using custom NDK path (ANDROID_NDK is set): ${ANDROID_NDK}")
endif()
set(CMAKE_ANDROID_NDK ${ANDROID_NDK})
endif()
unset(ANDROID_NDK_EXPECTED_PATH)
file(TO_CMAKE_PATH "${CMAKE_ANDROID_NDK}" CMAKE_ANDROID_NDK)
# Android NDK revision
# Possible formats:
# * r16, build 1234: 16.0.1234
# * r16b, build 1234: 16.1.1234
# * r16 beta 1, build 1234: 16.0.1234-beta1
#
# Canary builds are not specially marked.
file(READ "${CMAKE_ANDROID_NDK}/source.properties" ANDROID_NDK_SOURCE_PROPERTIES)
set(ANDROID_NDK_REVISION_REGEX
"^Pkg\\.Desc = Android NDK\nPkg\\.Revision = ([0-9]+)\\.([0-9]+)\\.([0-9]+)(-beta([0-9]+))?")
if(NOT ANDROID_NDK_SOURCE_PROPERTIES MATCHES "${ANDROID_NDK_REVISION_REGEX}")
message(SEND_ERROR "Failed to parse Android NDK revision: ${CMAKE_ANDROID_NDK}/source.properties.\n${ANDROID_NDK_SOURCE_PROPERTIES}")
endif()
set(ANDROID_NDK_MAJOR "${CMAKE_MATCH_1}")
set(ANDROID_NDK_MINOR "${CMAKE_MATCH_2}")
set(ANDROID_NDK_BUILD "${CMAKE_MATCH_3}")
set(ANDROID_NDK_BETA "${CMAKE_MATCH_5}")
if(ANDROID_NDK_BETA STREQUAL "")
set(ANDROID_NDK_BETA "0")
endif()
set(ANDROID_NDK_REVISION
"${ANDROID_NDK_MAJOR}.${ANDROID_NDK_MINOR}.${ANDROID_NDK_BUILD}${CMAKE_MATCH_4}")
# Touch toolchain variable to suppress "unused variable" warning.
# This happens if CMake is invoked with the same command line the second time.
if(CMAKE_TOOLCHAIN_FILE)
endif()
# Determine the ABI.
if(NOT CMAKE_ANDROID_ARCH_ABI)
if(ANDROID_ABI STREQUAL "armeabi-v7a with NEON")
set(CMAKE_ANDROID_ARCH_ABI armeabi-v7a)
set(CMAKE_ANDROID_ARM_NEON TRUE)
elseif(ANDROID_ABI)
set(CMAKE_ANDROID_ARCH_ABI ${ANDROID_ABI})
elseif(ANDROID_TOOLCHAIN_NAME MATCHES "^arm-linux-androideabi-")
set(CMAKE_ANDROID_ARCH_ABI armeabi-v7a)
elseif(ANDROID_TOOLCHAIN_NAME MATCHES "^aarch64-linux-android-")
set(CMAKE_ANDROID_ARCH_ABI arm64-v8a)
elseif(ANDROID_TOOLCHAIN_NAME MATCHES "^x86-")
set(CMAKE_ANDROID_ARCH_ABI x86)
elseif(ANDROID_TOOLCHAIN_NAME MATCHES "^x86_64-")
set(CMAKE_ANDROID_ARCH_ABI x86_64)
else()
set(CMAKE_ANDROID_ARCH_ABI armeabi-v7a)
endif()
endif()
if(CMAKE_ANDROID_ARCH_ABI STREQUAL "armeabi-v7a" AND NOT DEFINED CMAKE_ANDROID_ARM_NEON)
if(DEFINED ANDROID_ARM_NEON)
set(CMAKE_ANDROID_ARM_NEON ${ANDROID_ARM_NEON})
else()
set(CMAKE_ANDROID_ARM_NEON TRUE)
endif()
endif()
if(NOT DEFINED CMAKE_ANDROID_ARM_MODE)
if(DEFINED ANDROID_FORCE_ARM_BUILD)
set(CMAKE_ANDROID_ARM_MODE ${ANDROID_FORCE_ARM_BUILD})
elseif(DEFINED ANDROID_ARM_MODE)
if(ANDROID_ARM_MODE STREQUAL "arm")
set(CMAKE_ANDROID_ARM_MODE TRUE)
elseif(ANDROID_ARM_MODE STREQUAL "thumb")
set(CMAKE_ANDROID_ARM_MODE FALSE)
else()
message(FATAL_ERROR "Invalid Android ARM mode: ${ANDROID_ARM_MODE}.")
endif()
endif()
endif()
# PIE is supported on all currently supported Android releases, but it is not
# supported with static executables, so we still provide ANDROID_PIE as an
# escape hatch for those.
if(NOT DEFINED CMAKE_POSITION_INDEPENDENT_CODE)
if(DEFINED ANDROID_PIE)
set(CMAKE_POSITION_INDEPENDENT_CODE ${ANDROID_PIE})
elseif(DEFINED ANDROID_APP_PIE)
set(CMAKE_POSITION_INDEPENDENT_CODE ${ANDROID_APP_PIE})
else()
set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
endif()
endif()
# Default values for configurable variables.
if(NOT ANDROID_TOOLCHAIN)
set(ANDROID_TOOLCHAIN clang)
elseif(ANDROID_TOOLCHAIN STREQUAL gcc)
message(FATAL_ERROR "GCC is no longer supported. See "
"https://android.googlesource.com/platform/ndk/+/master/docs/ClangMigration.md.")
endif()
include(${CMAKE_ANDROID_NDK}/build/cmake/adjust_api_level.cmake)
adjust_api_level("${ANDROID_PLATFORM}" CMAKE_SYSTEM_VERSION)
if(NOT DEFINED CMAKE_ANDROID_STL_TYPE AND DEFINED ANDROID_STL)
set(CMAKE_ANDROID_STL_TYPE ${ANDROID_STL})
endif()
if("${CMAKE_ANDROID_STL_TYPE}" STREQUAL "gnustl_shared" OR
"${CMAKE_ANDROID_STL_TYPE}" STREQUAL "gnustl_static" OR
"${CMAKE_ANDROID_STL_TYPE}" STREQUAL "stlport_shared" OR
"${CMAKE_ANDROID_STL_TYPE}" STREQUAL "stlport_static")
message(FATAL_ERROR "\
${CMAKE_ANDROID_STL_TYPE} is no longer supported. Please switch to either c++_shared \
or c++_static. See https://developer.android.com/ndk/guides/cpp-support.html \
for more information.")
endif()
# Standard cross-compiling stuff.
set(CMAKE_SYSTEM_NAME Android)
# STL.
if(ANDROID_STL)
set(CMAKE_ANDROID_STL_TYPE ${ANDROID_STL})
endif()
if(NDK_CCACHE AND NOT ANDROID_CCACHE)
set(ANDROID_CCACHE "${NDK_CCACHE}")
endif()
if(ANDROID_CCACHE)
set(CMAKE_C_COMPILER_LAUNCHER "${ANDROID_CCACHE}")
set(CMAKE_CXX_COMPILER_LAUNCHER "${ANDROID_CCACHE}")
endif()
# Configuration specific flags.
if(ANDROID_STL_FORCE_FEATURES AND NOT DEFINED ANDROID_CPP_FEATURES)
set(ANDROID_CPP_FEATURES "rtti exceptions")
endif()
if(ANDROID_CPP_FEATURES)
separate_arguments(ANDROID_CPP_FEATURES)
foreach(feature ${ANDROID_CPP_FEATURES})
if(NOT ${feature} MATCHES "^(rtti|exceptions|no-rtti|no-exceptions)$")
message(FATAL_ERROR "Invalid Android C++ feature: ${feature}.")
endif()
if(${feature} STREQUAL "rtti")
set(CMAKE_ANDROID_RTTI TRUE)
endif()
if(${feature} STREQUAL "no-rtti")
set(CMAKE_ANDROID_RTTI FALSE)
endif()
if(${feature} STREQUAL "exceptions")
set(CMAKE_ANDROID_EXCEPTION TRUE)
endif()
if(${feature} STREQUAL "no-exceptions")
set(CMAKE_ANDROID_EXCEPTION FALSE)
endif()
endforeach()
string(REPLACE ";" " " ANDROID_CPP_FEATURES "${ANDROID_CPP_FEATURES}")
endif()
# Export configurable variables for the try_compile() command.
set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES
ANDROID_ABI
ANDROID_ALLOW_UNDEFINED_SYMBOLS
ANDROID_ARM_MODE
ANDROID_ARM_NEON
ANDROID_CCACHE
ANDROID_CPP_FEATURES
ANDROID_DISABLE_FORMAT_STRING_CHECKS
ANDROID_PIE
ANDROID_PLATFORM
ANDROID_STL
ANDROID_TOOLCHAIN
ANDROID_USE_LEGACY_TOOLCHAIN_FILE
)
if(DEFINED ANDROID_NO_UNDEFINED AND NOT DEFINED ANDROID_ALLOW_UNDEFINED_SYMBOLS)
if(ANDROID_NO_UNDEFINED)
set(ANDROID_ALLOW_UNDEFINED_SYMBOLS FALSE)
else()
set(ANDROID_ALLOW_UNDEFINED_SYMBOLS TRUE)
endif()
endif()
if(DEFINED ANDROID_SO_UNDEFINED AND NOT DEFINED ANDROID_ALLOW_UNDEFINED_SYMBOLS)
set(ANDROID_ALLOW_UNDEFINED_SYMBOLS "${ANDROID_SO_UNDEFINED}")
endif()
# Exports compatible variables defined in exports.cmake.
set(_ANDROID_EXPORT_COMPATIBILITY_VARIABLES TRUE)
if(CMAKE_HOST_SYSTEM_NAME STREQUAL Linux)
set(ANDROID_HOST_TAG linux-x86_64)
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL Darwin)
set(ANDROID_HOST_TAG darwin-x86_64)
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL Windows)
set(ANDROID_HOST_TAG windows-x86_64)
endif()
# Toolchain.
set(ANDROID_TOOLCHAIN_ROOT
"${CMAKE_ANDROID_NDK}/toolchains/llvm/prebuilt/${ANDROID_HOST_TAG}")
# NB: This variable causes CMake to automatically pass --sysroot to the
# toolchain. Studio currently relies on this to recognize Android builds. If
# this variable is removed, ensure that flag is still passed.
# TODO: Teach Studio to recognize Android builds based on --target.
set(CMAKE_SYSROOT "${ANDROID_TOOLCHAIN_ROOT}/sysroot")