Determine-Compiler-NDK.cmake 11 KB

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