1# Distributed under the OSI-approved BSD 3-Clause License. See accompanying 2# file Copyright.txt or https://cmake.org/licensing for details. 3 4# In Android NDK r19 and above there is a single clang toolchain. 5if(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED) 6 if(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION AND NOT CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION STREQUAL "clang") 7 message(FATAL_ERROR 8 "Android: The CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION value '${CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION}' " 9 "is not supported by this NDK. It must be 'clang' or not set at all." 10 ) 11 endif() 12 message(STATUS "Android: Selected unified Clang toolchain") 13 set(_ANDROID_TOOL_NDK_TOOLCHAIN_VERSION "clang") 14 set(_ANDROID_TOOL_C_COMPILER "${CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED}/bin/clang${_ANDROID_HOST_EXT}") 15 set(_ANDROID_TOOL_C_TOOLCHAIN_MACHINE "${CMAKE_ANDROID_ARCH_TRIPLE}") 16 set(_ANDROID_TOOL_C_TOOLCHAIN_VERSION "") 17 set(_ANDROID_TOOL_C_COMPILER_EXTERNAL_TOOLCHAIN "") 18 set(_ANDROID_TOOL_C_TOOLCHAIN_PREFIX "${CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED}/bin/${CMAKE_ANDROID_ARCH_TRIPLE}-") 19 set(_ANDROID_TOOL_C_TOOLCHAIN_SUFFIX "${_ANDROID_HOST_EXT}") 20 set(_ANDROID_TOOL_CXX_COMPILER "${CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED}/bin/clang++${_ANDROID_HOST_EXT}") 21 set(_ANDROID_TOOL_CXX_TOOLCHAIN_MACHINE "${CMAKE_ANDROID_ARCH_TRIPLE}") 22 set(_ANDROID_TOOL_CXX_TOOLCHAIN_VERSION "") 23 set(_ANDROID_TOOL_CXX_COMPILER_EXTERNAL_TOOLCHAIN "") 24 set(_ANDROID_TOOL_CXX_TOOLCHAIN_PREFIX "${CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED}/bin/${CMAKE_ANDROID_ARCH_TRIPLE}-") 25 set(_ANDROID_TOOL_CXX_TOOLCHAIN_SUFFIX "${_ANDROID_HOST_EXT}") 26 set(_CMAKE_TOOLCHAIN_PREFIX "${CMAKE_ANDROID_ARCH_TRIPLE}-") 27 return() 28endif() 29 30# In Android NDK releases there is build system toolchain selection logic in 31# these files: 32# 33# * <ndk>/build/core/init.mk 34# * <ndk>/build/core/setup-toolchain.mk 35# * <ndk>/[build/core/]toolchains/<toolchain>/{config.mk,setup.mk} 36# 37# We parse information out of the ``config.mk`` and ``setup.mk`` files below. 38# 39# There is also a "toolchains" directory with the prebuilt toolchains themselves: 40# 41# * <triple-or-arch>-<gcc-version>/prebuilt/<host>/bin/<triple>-gcc(.exe)? 42# The gcc compiler to be invoked. 43# 44# * llvm*/prebuilt/<host>/bin/clang 45# The clang compiler to be invoked with flags: 46# -target <triple> 47# -gcc-toolchain <ndk>/toolchains/<triple-or-arch>-<gcc-version> 48 49# Glob available toolchains in the NDK, restricted by any version request. 50if(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION STREQUAL "clang") 51 set(_ANDROID_TOOL_PATTERNS "*-clang" "*-clang[0-9].[0-9]") 52elseif(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION) 53 if(NOT CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION MATCHES "^(clang)?[0-9]\\.[0-9]$") 54 message(FATAL_ERROR 55 "Android: The CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION value '${CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION}' " 56 "is not one of the allowed forms:\n" 57 " <major>.<minor> = GCC of specified version\n" 58 " clang<major>.<minor> = Clang of specified version\n" 59 " clang = Clang of most recent available version\n" 60 ) 61 endif() 62 set(_ANDROID_TOOL_PATTERNS "*-${CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION}") 63else() 64 # If we can find any gcc toolchains then use one by default. 65 # Otherwise we look for clang toolchains (e.g. NDK r18+). 66 file(GLOB _ANDROID_CONFIG_MKS_FOR_GCC 67 "${CMAKE_ANDROID_NDK}/build/core/toolchains/*-[0-9].[0-9]/config.mk" 68 "${CMAKE_ANDROID_NDK}/toolchains/*-[0-9].[0-9]/config.mk" 69 ) 70 if(_ANDROID_CONFIG_MKS_FOR_GCC) 71 set(_ANDROID_TOOL_PATTERNS "*-[0-9].[0-9]") 72 else() 73 set(_ANDROID_TOOL_PATTERNS "*-clang") 74 endif() 75 unset(_ANDROID_CONFIG_MKS_FOR_GCC) 76endif() 77set(_ANDROID_CONFIG_MK_PATTERNS) 78foreach(base "build/core/toolchains" "toolchains") 79 foreach(pattern IN LISTS _ANDROID_TOOL_PATTERNS) 80 list(APPEND _ANDROID_CONFIG_MK_PATTERNS 81 "${CMAKE_ANDROID_NDK}/${base}/${pattern}/config.mk" 82 ) 83 endforeach() 84endforeach() 85unset(_ANDROID_TOOL_PATTERNS) 86file(GLOB _ANDROID_CONFIG_MKS ${_ANDROID_CONFIG_MK_PATTERNS}) 87unset(_ANDROID_CONFIG_MK_PATTERNS) 88 89# Find the newest toolchain version matching the ABI. 90set(_ANDROID_TOOL_NAME "") 91set(_ANDROID_TOOL_VERS 0) 92set(_ANDROID_TOOL_VERS_NDK "") 93set(_ANDROID_TOOL_SETUP_MK "") 94foreach(config_mk IN LISTS _ANDROID_CONFIG_MKS) 95 # Check that the toolchain matches the ABI. 96 file(STRINGS "${config_mk}" _ANDROID_TOOL_ABIS REGEX "^TOOLCHAIN_ABIS :=.* ${CMAKE_ANDROID_ARCH_ABI}( |$)") 97 if(NOT _ANDROID_TOOL_ABIS) 98 continue() 99 endif() 100 unset(_ANDROID_TOOL_ABIS) 101 102 # Check the version. 103 if("${config_mk}" MATCHES [[/([^/]+-((clang)?([0-9]\.[0-9]|)))/config.mk$]]) 104 set(_ANDROID_CUR_NAME "${CMAKE_MATCH_1}") 105 set(_ANDROID_CUR_VERS "${CMAKE_MATCH_4}") 106 set(_ANDROID_CUR_VERS_NDK "${CMAKE_MATCH_2}") 107 if(_ANDROID_TOOL_VERS STREQUAL "") 108 # already the latest possible 109 elseif(_ANDROID_CUR_VERS STREQUAL "" OR _ANDROID_CUR_VERS VERSION_GREATER _ANDROID_TOOL_VERS) 110 set(_ANDROID_TOOL_NAME "${_ANDROID_CUR_NAME}") 111 set(_ANDROID_TOOL_VERS "${_ANDROID_CUR_VERS}") 112 set(_ANDROID_TOOL_VERS_NDK "${_ANDROID_CUR_VERS_NDK}") 113 string(REPLACE "/config.mk" "/setup.mk" _ANDROID_TOOL_SETUP_MK "${config_mk}") 114 endif() 115 unset(_ANDROID_CUR_TOOL) 116 unset(_ANDROID_CUR_VERS) 117 unset(_ANDROID_CUR_VERS_NDK) 118 endif() 119endforeach() 120 121# Verify that we have a suitable toolchain. 122if(NOT _ANDROID_TOOL_NAME) 123 if(_ANDROID_CONFIG_MKS) 124 string(REPLACE ";" "\n " _ANDROID_TOOLS_MSG "after considering:;${_ANDROID_CONFIG_MKS}") 125 else() 126 set(_ANDROID_TOOLS_MSG "") 127 endif() 128 if(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION) 129 string(CONCAT _ANDROID_TOOLS_MSG 130 "of the version specified by CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION:\n" 131 " ${CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION}\n" 132 "${_ANDROID_TOOLS_MSG}") 133 endif() 134 message(FATAL_ERROR 135 "Android: No toolchain for ABI '${CMAKE_ANDROID_ARCH_ABI}' found in the NDK:\n" 136 " ${CMAKE_ANDROID_NDK}\n" 137 "${_ANDROID_TOOLS_MSG}" 138 ) 139endif() 140unset(_ANDROID_CONFIG_MKS) 141 142# For clang toolchains we still need to find a gcc toolchain. 143if(_ANDROID_TOOL_NAME MATCHES "-clang") 144 set(_ANDROID_TOOL_CLANG_NAME "${_ANDROID_TOOL_NAME}") 145 set(_ANDROID_TOOL_CLANG_VERS "${_ANDROID_TOOL_VERS}") 146 set(_ANDROID_TOOL_NAME "") 147 set(_ANDROID_TOOL_VERS "") 148else() 149 set(_ANDROID_TOOL_CLANG_NAME "") 150 set(_ANDROID_TOOL_CLANG_VERS "") 151endif() 152 153# Parse the toolchain setup.mk file to extract information we need. 154# Their content is not standardized across toolchains or NDK versions, 155# so we match known cases. Note that the parsing is stateful across 156# lines because we need to substitute for some Make variable references. 157if(CMAKE_ANDROID_NDK_TOOLCHAIN_DEBUG) 158 message(STATUS "loading: ${_ANDROID_TOOL_SETUP_MK}") 159endif() 160file(STRINGS "${_ANDROID_TOOL_SETUP_MK}" _ANDROID_TOOL_SETUP REGEX "^(LLVM|TOOLCHAIN)_[A-Z_]+ +:= +.*$") 161unset(_ANDROID_TOOL_SETUP_MK) 162set(_ANDROID_TOOL_PREFIX "") 163set(_ANDROID_TOOL_NAME_ONLY "") 164set(_ANDROID_TOOL_LLVM_NAME "llvm") 165set(_ANDROID_TOOL_LLVM_VERS "") 166foreach(line IN LISTS _ANDROID_TOOL_SETUP) 167 if(CMAKE_ANDROID_NDK_TOOLCHAIN_DEBUG) 168 message(STATUS "setup.mk: ${line}") 169 endif() 170 171 if(line MATCHES [[^TOOLCHAIN_PREFIX +:= +.*/bin/([^$/ ]*) *$]]) 172 # We just matched the toolchain prefix with no Make variable references. 173 set(_ANDROID_TOOL_PREFIX "${CMAKE_MATCH_1}") 174 elseif(_ANDROID_TOOL_CLANG_NAME) 175 # For clang toolchains we need to find more information. 176 if(line MATCHES [[^TOOLCHAIN_VERSION +:= +([0-9.]+) *$]]) 177 # We just matched the gcc toolchain version number. Save it for later. 178 set(_ANDROID_TOOL_VERS "${CMAKE_MATCH_1}") 179 elseif(line MATCHES [[^TOOLCHAIN_NAME +:= +(.*\$\(TOOLCHAIN_VERSION\)) *$]]) 180 # We just matched the gcc toolchain name with a version number placeholder, so substitute it. 181 # The gcc toolchain version number will have already been extracted from a TOOLCHAIN_VERSION line. 182 string(REPLACE "$(TOOLCHAIN_VERSION)" "${_ANDROID_TOOL_VERS}" _ANDROID_TOOL_NAME "${CMAKE_MATCH_1}") 183 elseif(line MATCHES [[^TOOLCHAIN_NAME +:= +([^$/ ]+) *$]]) 184 # We just matched the gcc toolchain name without version number. Save it for later. 185 set(_ANDROID_TOOL_NAME_ONLY "${CMAKE_MATCH_1}") 186 elseif(line MATCHES [[^TOOLCHAIN_PREFIX +:= +.*/bin/(\$\(TOOLCHAIN_NAME\)-) *$]]) 187 # We just matched the toolchain prefix with a name placeholder, so substitute it. 188 # The gcc toolchain name will have already been extracted without version number from a TOOLCHAIN_NAME line. 189 string(REPLACE "$(TOOLCHAIN_NAME)" "${_ANDROID_TOOL_NAME_ONLY}" _ANDROID_TOOL_PREFIX "${CMAKE_MATCH_1}") 190 elseif(line MATCHES [[^LLVM_VERSION +:= +([0-9.]+)$]]) 191 # We just matched the llvm prebuilt binary toolchain version number. Save it for later. 192 set(_ANDROID_TOOL_LLVM_VERS "${CMAKE_MATCH_1}") 193 elseif(line MATCHES [[^LLVM_NAME +:= +(llvm-\$\(LLVM_VERSION\)) *$]]) 194 # We just matched the llvm prebuilt binary toolchain directory name with a version number placeholder, 195 # so substitute it. The llvm prebuilt binary toolchain version number will have already been extracted 196 # from a LLVM_VERSION line. 197 string(REPLACE "$(LLVM_VERSION)" "${_ANDROID_TOOL_LLVM_VERS}" _ANDROID_TOOL_LLVM_NAME "${CMAKE_MATCH_1}") 198 elseif(line MATCHES [[^LLVM_TOOLCHAIN_PREBUILT_ROOT +:= +\$\(call get-toolchain-root.*,([^$ ]+)\) *$]]) 199 # We just matched the llvm prebuilt binary toolchain directory name. 200 set(_ANDROID_TOOL_LLVM_NAME "${CMAKE_MATCH_1}") 201 elseif(line MATCHES [[^TOOLCHAIN_ROOT +:= +\$\(call get-toolchain-root.*,(\$\(TOOLCHAIN_NAME\)-[0-9.]+)\) *$]]) 202 # We just matched a placeholder for the name followed by a version number. 203 # The gcc toolchain name will have already been extracted without version number from a TOOLCHAIN_NAME line. 204 # Substitute for the placeholder to get the full gcc toolchain name. 205 string(REPLACE "$(TOOLCHAIN_NAME)" "${_ANDROID_TOOL_NAME_ONLY}" _ANDROID_TOOL_NAME "${CMAKE_MATCH_1}") 206 elseif(line MATCHES [[^TOOLCHAIN_ROOT +:= +\$\(call get-toolchain-root.*,([^$ ]+)\) *$]]) 207 # We just matched the full gcc toolchain name without placeholder. 208 set(_ANDROID_TOOL_NAME "${CMAKE_MATCH_1}") 209 endif() 210 endif() 211endforeach() 212unset(_ANDROID_TOOL_NAME_ONLY) 213unset(_ANDROID_TOOL_LLVM_VERS) 214unset(_ANDROID_TOOL_SETUP) 215 216# Fall back to parsing the version and prefix from the tool name. 217if(NOT _ANDROID_TOOL_VERS AND "${_ANDROID_TOOL_NAME}" MATCHES "-([0-9.]+)$") 218 set(_ANDROID_TOOL_VERS "${CMAKE_MATCH_1}") 219endif() 220if(NOT _ANDROID_TOOL_PREFIX AND "${_ANDROID_TOOL_NAME}" MATCHES "^(.*-)[0-9.]+$") 221 set(_ANDROID_TOOL_PREFIX "${CMAKE_MATCH_1}") 222endif() 223 224# Help CMakeFindBinUtils locate things. 225set(_CMAKE_TOOLCHAIN_PREFIX "${_ANDROID_TOOL_PREFIX}") 226 227set(_ANDROID_TOOL_NDK_TOOLCHAIN_VERSION "${_ANDROID_TOOL_VERS_NDK}") 228 229# _ANDROID_TOOL_PREFIX should now match `gcc -dumpmachine`. 230string(REGEX REPLACE "-$" "" _ANDROID_TOOL_C_TOOLCHAIN_MACHINE "${_ANDROID_TOOL_PREFIX}") 231 232set(_ANDROID_TOOL_C_TOOLCHAIN_VERSION "${_ANDROID_TOOL_VERS}") 233set(_ANDROID_TOOL_C_TOOLCHAIN_PREFIX "${CMAKE_ANDROID_NDK}/toolchains/${_ANDROID_TOOL_NAME}/prebuilt/${CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG}/bin/${_ANDROID_TOOL_PREFIX}") 234set(_ANDROID_TOOL_C_TOOLCHAIN_SUFFIX "${_ANDROID_HOST_EXT}") 235 236set(_ANDROID_TOOL_CXX_TOOLCHAIN_MACHINE "${_ANDROID_TOOL_C_TOOLCHAIN_MACHINE}") 237set(_ANDROID_TOOL_CXX_TOOLCHAIN_VERSION "${_ANDROID_TOOL_C_TOOLCHAIN_VERSION}") 238set(_ANDROID_TOOL_CXX_TOOLCHAIN_PREFIX "${_ANDROID_TOOL_C_TOOLCHAIN_PREFIX}") 239set(_ANDROID_TOOL_CXX_TOOLCHAIN_SUFFIX "${_ANDROID_TOOL_C_TOOLCHAIN_SUFFIX}") 240 241if(_ANDROID_TOOL_CLANG_NAME) 242 message(STATUS "Android: Selected Clang toolchain '${_ANDROID_TOOL_CLANG_NAME}' with GCC toolchain '${_ANDROID_TOOL_NAME}'") 243 set(_ANDROID_TOOL_C_COMPILER "${CMAKE_ANDROID_NDK}/toolchains/${_ANDROID_TOOL_LLVM_NAME}/prebuilt/${CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG}/bin/clang${_ANDROID_HOST_EXT}") 244 set(_ANDROID_TOOL_C_COMPILER_EXTERNAL_TOOLCHAIN ${CMAKE_ANDROID_NDK}/toolchains/${_ANDROID_TOOL_NAME}/prebuilt/${CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG}) 245 set(_ANDROID_TOOL_CXX_COMPILER "${CMAKE_ANDROID_NDK}/toolchains/${_ANDROID_TOOL_LLVM_NAME}/prebuilt/${CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG}/bin/clang++${_ANDROID_HOST_EXT}") 246 set(_ANDROID_TOOL_CXX_COMPILER_EXTERNAL_TOOLCHAIN "${_ANDROID_TOOL_C_COMPILER_EXTERNAL_TOOLCHAIN}") 247else() 248 message(STATUS "Android: Selected GCC toolchain '${_ANDROID_TOOL_NAME}'") 249 set(_ANDROID_TOOL_C_COMPILER "${_ANDROID_TOOL_C_TOOLCHAIN_PREFIX}gcc${_ANDROID_TOOL_C_TOOLCHAIN_SUFFIX}") 250 set(_ANDROID_TOOL_C_COMPILER_EXTERNAL_TOOLCHAIN "") 251 set(_ANDROID_TOOL_CXX_COMPILER "${_ANDROID_TOOL_CXX_TOOLCHAIN_PREFIX}g++${_ANDROID_TOOL_CXX_TOOLCHAIN_SUFFIX}") 252 set(_ANDROID_TOOL_CXX_COMPILER_EXTERNAL_TOOLCHAIN "") 253endif() 254 255if(CMAKE_ANDROID_NDK_TOOLCHAIN_DEBUG) 256 message(STATUS "_ANDROID_TOOL_NAME=${_ANDROID_TOOL_NAME}") 257 message(STATUS "_ANDROID_TOOL_VERS=${_ANDROID_TOOL_VERS}") 258 message(STATUS "_ANDROID_TOOL_VERS_NDK=${_ANDROID_TOOL_VERS_NDK}") 259 message(STATUS "_ANDROID_TOOL_PREFIX=${_ANDROID_TOOL_PREFIX}") 260 message(STATUS "_ANDROID_TOOL_CLANG_NAME=${_ANDROID_TOOL_CLANG_NAME}") 261 message(STATUS "_ANDROID_TOOL_CLANG_VERS=${_ANDROID_TOOL_CLANG_VERS}") 262 message(STATUS "_ANDROID_TOOL_LLVM_NAME=${_ANDROID_TOOL_LLVM_NAME}") 263endif() 264 265unset(_ANDROID_TOOL_NAME) 266unset(_ANDROID_TOOL_VERS) 267unset(_ANDROID_TOOL_VERS_NDK) 268unset(_ANDROID_TOOL_PREFIX) 269unset(_ANDROID_TOOL_CLANG_NAME) 270unset(_ANDROID_TOOL_CLANG_VERS) 271unset(_ANDROID_TOOL_LLVM_NAME) 272