CMakeDetermineCompilerABI.cmake 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. # Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. # file LICENSE.rst or https://cmake.org/licensing for details.
  3. # Function to compile a source file to identify the compiler ABI.
  4. # This is used internally by CMake and should not be included by user
  5. # code.
  6. include(${CMAKE_ROOT}/Modules/Internal/CMakeDetermineLinkerId.cmake)
  7. include(${CMAKE_ROOT}/Modules/CMakeParseImplicitIncludeInfo.cmake)
  8. include(${CMAKE_ROOT}/Modules/CMakeParseImplicitLinkInfo.cmake)
  9. include(${CMAKE_ROOT}/Modules/CMakeParseLibraryArchitecture.cmake)
  10. include(CMakeTestCompilerCommon)
  11. function(CMAKE_DETERMINE_COMPILER_ABI lang src)
  12. if(NOT DEFINED CMAKE_${lang}_ABI_COMPILED)
  13. message(CHECK_START "Detecting ${lang} compiler ABI info")
  14. # Compile the ABI identification source.
  15. set(BIN "${CMAKE_PLATFORM_INFO_DIR}/CMakeDetermineCompilerABI_${lang}.bin")
  16. set(CMAKE_FLAGS )
  17. set(COMPILE_DEFINITIONS )
  18. set(LINK_OPTIONS )
  19. if(DEFINED CMAKE_${lang}_VERBOSE_FLAG)
  20. set(LINK_OPTIONS "${CMAKE_${lang}_VERBOSE_FLAG}")
  21. set(COMPILE_DEFINITIONS "${CMAKE_${lang}_VERBOSE_FLAG}")
  22. endif()
  23. if(DEFINED CMAKE_${lang}_VERBOSE_COMPILE_FLAG)
  24. set(COMPILE_DEFINITIONS "${CMAKE_${lang}_VERBOSE_COMPILE_FLAG}")
  25. endif()
  26. if(DEFINED CMAKE_${lang}_VERBOSE_LINK_FLAG)
  27. list(APPEND LINK_OPTIONS "${CMAKE_${lang}_VERBOSE_LINK_FLAG}")
  28. endif()
  29. if(lang MATCHES "^(CUDA|HIP)$")
  30. if(CMAKE_CUDA_ARCHITECTURES STREQUAL "native")
  31. # We are about to detect the native architectures, so we do
  32. # not yet know them. Use all architectures during detection.
  33. set(CMAKE_${lang}_ARCHITECTURES "all")
  34. endif()
  35. set(CMAKE_${lang}_RUNTIME_LIBRARY "Static")
  36. endif()
  37. if(lang STREQUAL "CXX")
  38. set(CMAKE_${lang}_SCAN_FOR_MODULES OFF)
  39. endif()
  40. if(NOT "x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xMSVC")
  41. # Avoid adding our own platform standard libraries for compilers
  42. # from which we might detect implicit link libraries.
  43. list(APPEND CMAKE_FLAGS "-DCMAKE_${lang}_STANDARD_LIBRARIES=")
  44. endif()
  45. list(JOIN LINK_OPTIONS " " LINK_OPTIONS)
  46. list(APPEND CMAKE_FLAGS "-DEXE_LINKER_FLAGS=${LINK_OPTIONS}")
  47. __TestCompiler_setTryCompileTargetType()
  48. # Avoid failing ABI detection caused by non-functionally relevant
  49. # compiler arguments
  50. if(CMAKE_TRY_COMPILE_CONFIGURATION)
  51. string(TOUPPER "${CMAKE_TRY_COMPILE_CONFIGURATION}" _tc_config)
  52. else()
  53. set(_tc_config "DEBUG")
  54. endif()
  55. foreach(v CMAKE_${lang}_FLAGS CMAKE_${lang}_FLAGS_${_tc_config})
  56. # Avoid failing ABI detection on warnings.
  57. string(REGEX REPLACE "(^| )-Werror([= ][^-][^ ]*)?( |$)" " " ${v} "${${v}}")
  58. # Avoid passing of "-pipe" when determining the compiler internals. With
  59. # "-pipe" GCC will use pipes to pass data between the involved
  60. # executables. This may lead to issues when their stderr output (which
  61. # contains the relevant compiler internals) becomes interweaved.
  62. string(REGEX REPLACE "(^| )-pipe( |$)" " " ${v} "${${v}}")
  63. # Suppress any formatting of warnings and/or errors
  64. string(REGEX REPLACE "(-f|/)diagnostics(-|:)color(=[a-z]+)?" "" ${v} "${${v}}")
  65. endforeach()
  66. # Save the current LC_ALL, LC_MESSAGES, and LANG environment variables
  67. # and set them to "C" that way GCC's "search starts here" text is in
  68. # English and we can grok it.
  69. set(_orig_lc_all $ENV{LC_ALL})
  70. set(_orig_lc_messages $ENV{LC_MESSAGES})
  71. set(_orig_lang $ENV{LANG})
  72. set(ENV{LC_ALL} C)
  73. set(ENV{LC_MESSAGES} C)
  74. set(ENV{LANG} C)
  75. try_compile(CMAKE_${lang}_ABI_COMPILED
  76. SOURCES ${src}
  77. CMAKE_FLAGS ${CMAKE_FLAGS}
  78. # Ignore unused flags when we are just determining the ABI.
  79. "--no-warn-unused-cli"
  80. COMPILE_DEFINITIONS ${COMPILE_DEFINITIONS}
  81. OUTPUT_VARIABLE OUTPUT
  82. COPY_FILE "${BIN}"
  83. COPY_FILE_ERROR _copy_error
  84. __CMAKE_INTERNAL ABI
  85. )
  86. # Restore original LC_ALL, LC_MESSAGES, and LANG
  87. set(ENV{LC_ALL} ${_orig_lc_all})
  88. set(ENV{LC_MESSAGES} ${_orig_lc_messages})
  89. set(ENV{LANG} ${_orig_lang})
  90. # Move result from cache to normal variable.
  91. set(CMAKE_${lang}_ABI_COMPILED ${CMAKE_${lang}_ABI_COMPILED})
  92. unset(CMAKE_${lang}_ABI_COMPILED CACHE)
  93. if(CMAKE_${lang}_ABI_COMPILED AND _copy_error)
  94. set(CMAKE_${lang}_ABI_COMPILED 0)
  95. endif()
  96. set(CMAKE_${lang}_ABI_COMPILED ${CMAKE_${lang}_ABI_COMPILED} PARENT_SCOPE)
  97. # Load the resulting information strings.
  98. if(CMAKE_${lang}_ABI_COMPILED)
  99. message(CHECK_PASS "done")
  100. if(CMAKE_HOST_APPLE AND CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND NOT CMAKE_OSX_ARCHITECTURES MATCHES "\\$")
  101. file(READ_MACHO "${BIN}" ARCHITECTURES archs CAPTURE_ERROR macho_error) # undocumented file() subcommand
  102. if (NOT macho_error)
  103. # sort and prune the list of found architectures
  104. set(arch_list_sorted ${archs})
  105. list(SORT arch_list_sorted)
  106. list(REMOVE_DUPLICATES arch_list_sorted)
  107. # sort and prune the list of requested architectures
  108. set(requested_arch_list ${CMAKE_OSX_ARCHITECTURES})
  109. list(SORT requested_arch_list)
  110. list(REMOVE_DUPLICATES requested_arch_list)
  111. message(CONFIGURE_LOG
  112. "Effective list of requested architectures (possibly empty) : \"${requested_arch_list}\"\n"
  113. "Effective list of architectures found in the ABI info binary: \"${arch_list_sorted}\"\n")
  114. # If all generated architectures were known to READ_MACHO (i.e. libmacho):
  115. # Compare requested and found:
  116. # - if no architecture(s) were requested explicitly, just check if READ_MACHO returned
  117. # an architecture for the ABI info binary.
  118. # - otherwise, check if the requested and found lists are equal
  119. if(arch_list_sorted MATCHES "unknown")
  120. # Rare but not impossible: a host with a toolchain capable of generating binaries with
  121. # architectures that the system libmacho is too old to know. Report the found archs as
  122. # usual, warn about the unknowns and skip the comparison with CMAKE_OSX_ARCHITECTURES.
  123. message(WARNING "The ${lang} compiler generates universal binaries with at least 1 architecture not known to the host")
  124. elseif(requested_arch_list AND arch_list_sorted
  125. AND NOT "${requested_arch_list}" STREQUAL "${arch_list_sorted}")
  126. # inform the user of the mismatch but show the raw input and output lists
  127. message(FATAL_ERROR
  128. "The ${lang} compiler targets architectures:\n"
  129. " \"${archs}\"\n"
  130. "but CMAKE_OSX_ARCHITECTURES is\n"
  131. " \"${CMAKE_OSX_ARCHITECTURES}\"\n")
  132. endif()
  133. endif()
  134. endif()
  135. cmake_policy(PUSH)
  136. cmake_policy(SET CMP0159 NEW) # file(STRINGS) with REGEX updates CMAKE_MATCH_<n>
  137. file(STRINGS "${BIN}" ABI_STRINGS LIMIT_COUNT 32 REGEX "INFO:[A-Za-z0-9_]+\\[[^]]*\\]")
  138. cmake_policy(POP)
  139. set(ABI_SIZEOF_DPTR "NOTFOUND")
  140. set(ABI_BYTE_ORDER "NOTFOUND")
  141. set(ABI_NAME "NOTFOUND")
  142. set(ARCHITECTURE_ID "")
  143. foreach(info ${ABI_STRINGS})
  144. if("${info}" MATCHES "INFO:sizeof_dptr\\[0*([^]]*)\\]" AND NOT ABI_SIZEOF_DPTR)
  145. set(ABI_SIZEOF_DPTR "${CMAKE_MATCH_1}")
  146. endif()
  147. if("${info}" MATCHES "INFO:byte_order\\[(BIG_ENDIAN|LITTLE_ENDIAN)\\]")
  148. set(byte_order "${CMAKE_MATCH_1}")
  149. if(ABI_BYTE_ORDER STREQUAL "NOTFOUND")
  150. # Tentatively use the value because this is the first occurrence.
  151. set(ABI_BYTE_ORDER "${byte_order}")
  152. elseif(NOT ABI_BYTE_ORDER STREQUAL "${byte_order}")
  153. # Drop value because multiple occurrences do not match.
  154. set(ABI_BYTE_ORDER "")
  155. endif()
  156. endif()
  157. if("${info}" MATCHES "INFO:abi\\[([^]]*)\\]" AND NOT ABI_NAME)
  158. set(ABI_NAME "${CMAKE_MATCH_1}")
  159. endif()
  160. if("${info}" MATCHES "INFO:arch\\[([^]\"]*)\\]")
  161. list(APPEND ARCHITECTURE_ID "${CMAKE_MATCH_1}")
  162. endif()
  163. endforeach()
  164. if(ABI_SIZEOF_DPTR)
  165. set(CMAKE_${lang}_SIZEOF_DATA_PTR "${ABI_SIZEOF_DPTR}" PARENT_SCOPE)
  166. elseif(CMAKE_${lang}_SIZEOF_DATA_PTR_DEFAULT)
  167. set(CMAKE_${lang}_SIZEOF_DATA_PTR "${CMAKE_${lang}_SIZEOF_DATA_PTR_DEFAULT}" PARENT_SCOPE)
  168. endif()
  169. if(ABI_BYTE_ORDER)
  170. set(CMAKE_${lang}_BYTE_ORDER "${ABI_BYTE_ORDER}" PARENT_SCOPE)
  171. endif()
  172. if(ABI_NAME)
  173. set(CMAKE_${lang}_COMPILER_ABI "${ABI_NAME}" PARENT_SCOPE)
  174. endif()
  175. # The GNU Fortran compiler does not predefine architecture macros.
  176. if(NOT CMAKE_${lang}_COMPILER_ARCHITECTURE_ID AND NOT ARCHITECTURE_ID
  177. AND lang STREQUAL "Fortran" AND CMAKE_${lang}_COMPILER_ID STREQUAL "GNU")
  178. execute_process(COMMAND "${CMAKE_${lang}_COMPILER}" -dumpmachine
  179. OUTPUT_VARIABLE _dumpmachine_triple OUTPUT_STRIP_TRAILING_WHITESPACE
  180. ERROR_VARIABLE _dumpmachine_stderr
  181. RESULT_VARIABLE _dumpmachine_result
  182. )
  183. if(_dumpmachine_result EQUAL 0)
  184. include(Internal/CMakeParseCompilerArchitectureId)
  185. cmake_parse_compiler_architecture_id("${_dumpmachine_triple}" ARCHITECTURE_ID)
  186. endif()
  187. endif()
  188. # For some compilers we detect the architecture id during compiler identification.
  189. # If this was not one of those, use what was detected during compiler ABI detection,
  190. # which might be a list, e.g., when CMAKE_OSX_ARCHITECTURES has multiple values.
  191. if(NOT CMAKE_${lang}_COMPILER_ARCHITECTURE_ID AND ARCHITECTURE_ID)
  192. list(SORT ARCHITECTURE_ID)
  193. set(CMAKE_${lang}_COMPILER_ARCHITECTURE_ID "${ARCHITECTURE_ID}" PARENT_SCOPE)
  194. endif()
  195. # Parse implicit include directory for this language, if available.
  196. if(CMAKE_${lang}_VERBOSE_FLAG)
  197. set (implicit_incdirs "")
  198. cmake_parse_implicit_include_info("${OUTPUT}" "${lang}"
  199. implicit_incdirs log rv)
  200. message(CONFIGURE_LOG
  201. "Parsed ${lang} implicit include dir info: rv=${rv}\n${log}\n\n")
  202. if("${rv}" STREQUAL "done")
  203. # Entries that we have been told to explicitly pass as standard include
  204. # directories will not be implicitly added by the compiler.
  205. if(CMAKE_${lang}_STANDARD_INCLUDE_DIRECTORIES)
  206. list(REMOVE_ITEM implicit_incdirs ${CMAKE_${lang}_STANDARD_INCLUDE_DIRECTORIES})
  207. endif()
  208. # We parsed implicit include directories, so override the default initializer.
  209. set(_CMAKE_${lang}_IMPLICIT_INCLUDE_DIRECTORIES_INIT "${implicit_incdirs}")
  210. endif()
  211. endif()
  212. set(CMAKE_${lang}_IMPLICIT_INCLUDE_DIRECTORIES "${_CMAKE_${lang}_IMPLICIT_INCLUDE_DIRECTORIES_INIT}" PARENT_SCOPE)
  213. if(_CMAKE_${lang}_IMPLICIT_LINK_INFORMATION_DETERMINED_EARLY)
  214. # Use implicit linker information detected during compiler id step.
  215. set(implicit_dirs "${CMAKE_${lang}_IMPLICIT_LINK_DIRECTORIES}")
  216. set(implicit_objs "")
  217. set(implicit_libs "${CMAKE_${lang}_IMPLICIT_LINK_LIBRARIES}")
  218. set(implicit_fwks "${CMAKE_${lang}_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES}")
  219. else()
  220. # Parse implicit linker information for this language, if available.
  221. set(implicit_dirs "")
  222. set(implicit_objs "")
  223. set(implicit_libs "")
  224. set(implicit_fwks "")
  225. set(compute_artifacts COMPUTE_LINKER linker_tool)
  226. if(CMAKE_${lang}_VERBOSE_FLAG)
  227. list(APPEND compute_artifacts COMPUTE_IMPLICIT_LIBS implicit_libs
  228. COMPUTE_IMPLICIT_DIRS implicit_dirs
  229. COMPUTE_IMPLICIT_FWKS implicit_fwks
  230. COMPUTE_IMPLICIT_OBJECTS implicit_objs)
  231. endif()
  232. cmake_parse_implicit_link_info2("${OUTPUT}" log "${CMAKE_${lang}_IMPLICIT_OBJECT_REGEX}"
  233. ${compute_artifacts} LANGUAGE ${lang})
  234. message(CONFIGURE_LOG
  235. "Parsed ${lang} implicit link information:\n${log}\n\n")
  236. # for VS IDE Intel Fortran we have to figure out the
  237. # implicit link path for the fortran run time using
  238. # a try-compile
  239. if("${lang}" MATCHES "Fortran"
  240. AND "${CMAKE_GENERATOR}" MATCHES "Visual Studio")
  241. message(CHECK_START "Determine Intel Fortran Compiler Implicit Link Path")
  242. # Build a sample project which reports symbols.
  243. try_compile(IFORT_LIB_PATH_COMPILED
  244. PROJECT IntelFortranImplicit
  245. SOURCE_DIR ${CMAKE_ROOT}/Modules/IntelVSImplicitPath
  246. BINARY_DIR ${CMAKE_BINARY_DIR}/CMakeFiles/IntelVSImplicitPath
  247. CMAKE_FLAGS
  248. "-DCMAKE_Fortran_FLAGS:STRING=${CMAKE_Fortran_FLAGS}"
  249. OUTPUT_VARIABLE _output)
  250. file(WRITE
  251. "${CMAKE_BINARY_DIR}/CMakeFiles/IntelVSImplicitPath/output.txt"
  252. "${_output}")
  253. include(${CMAKE_BINARY_DIR}/CMakeFiles/IntelVSImplicitPath/output.cmake OPTIONAL)
  254. message(CHECK_PASS "done")
  255. endif()
  256. endif()
  257. # Implicit link libraries cannot be used explicitly for multiple
  258. # OS X architectures, so we skip it.
  259. if(DEFINED CMAKE_OSX_ARCHITECTURES)
  260. if("${CMAKE_OSX_ARCHITECTURES}" MATCHES ";")
  261. set(implicit_libs "")
  262. endif()
  263. endif()
  264. # Filter out implicit link directories excluded by our Platform/<os>* modules.
  265. if(DEFINED CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES_EXCLUDE)
  266. list(REMOVE_ITEM implicit_dirs ${CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES_EXCLUDE})
  267. endif()
  268. # Filter out implicit link information excluded by the environment.
  269. if(DEFINED ENV{CMAKE_${lang}_IMPLICIT_LINK_LIBRARIES_EXCLUDE})
  270. list(REMOVE_ITEM implicit_libs $ENV{CMAKE_${lang}_IMPLICIT_LINK_LIBRARIES_EXCLUDE})
  271. endif()
  272. if(DEFINED ENV{CMAKE_${lang}_IMPLICIT_LINK_DIRECTORIES_EXCLUDE})
  273. list(REMOVE_ITEM implicit_dirs $ENV{CMAKE_${lang}_IMPLICIT_LINK_DIRECTORIES_EXCLUDE})
  274. endif()
  275. set(CMAKE_${lang}_COMPILER_LINKER "${linker_tool}" PARENT_SCOPE)
  276. cmake_determine_linker_id(${lang} "${linker_tool}")
  277. set(CMAKE_${lang}_COMPILER_LINKER_ID "${CMAKE_${lang}_COMPILER_LINKER_ID}" PARENT_SCOPE)
  278. set(CMAKE_${lang}_COMPILER_LINKER_VERSION ${CMAKE_${lang}_COMPILER_LINKER_VERSION} PARENT_SCOPE)
  279. set(CMAKE_${lang}_COMPILER_LINKER_FRONTEND_VARIANT ${CMAKE_${lang}_COMPILER_LINKER_FRONTEND_VARIANT} PARENT_SCOPE)
  280. set(CMAKE_${lang}_IMPLICIT_LINK_LIBRARIES "${implicit_libs}" PARENT_SCOPE)
  281. set(CMAKE_${lang}_IMPLICIT_LINK_DIRECTORIES "${implicit_dirs}" PARENT_SCOPE)
  282. set(CMAKE_${lang}_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "${implicit_fwks}" PARENT_SCOPE)
  283. cmake_parse_library_architecture(${lang} "${implicit_dirs}" "${implicit_objs}" architecture_flag)
  284. if(architecture_flag)
  285. set(CMAKE_${lang}_LIBRARY_ARCHITECTURE "${architecture_flag}" PARENT_SCOPE)
  286. endif()
  287. else()
  288. message(CHECK_FAIL "failed")
  289. endif()
  290. endif()
  291. endfunction()