Determine-Compiler-NDK.cmake 13 KB

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