Detect.cmake 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. # Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. # file Copyright.txt or https://cmake.org/licensing for details.
  3. configure_file(${FortranCInterface_SOURCE_DIR}/Input.cmake.in
  4. ${FortranCInterface_BINARY_DIR}/Input.cmake @ONLY)
  5. # Detect the Fortran/C interface on the first run or when the
  6. # configuration changes.
  7. if(NOT EXISTS ${FortranCInterface_BINARY_DIR}/Output.cmake
  8. OR NOT EXISTS ${FortranCInterface_BINARY_DIR}/Input.cmake
  9. OR NOT ${FortranCInterface_BINARY_DIR}/Output.cmake
  10. IS_NEWER_THAN ${FortranCInterface_BINARY_DIR}/Input.cmake
  11. OR NOT ${FortranCInterface_BINARY_DIR}/Output.cmake
  12. IS_NEWER_THAN ${FortranCInterface_SOURCE_DIR}/Output.cmake.in
  13. OR NOT ${FortranCInterface_BINARY_DIR}/Output.cmake
  14. IS_NEWER_THAN ${FortranCInterface_SOURCE_DIR}/CMakeLists.txt
  15. OR NOT ${FortranCInterface_BINARY_DIR}/Output.cmake
  16. IS_NEWER_THAN ${CMAKE_CURRENT_LIST_FILE}
  17. )
  18. message(CHECK_START "Detecting Fortran/C Interface")
  19. else()
  20. return()
  21. endif()
  22. # Invalidate verification results.
  23. unset(FortranCInterface_VERIFIED_C CACHE)
  24. unset(FortranCInterface_VERIFIED_CXX CACHE)
  25. set(_result)
  26. # Perform detection with only one architecture so that
  27. # the info strings are not repeated.
  28. if(CMAKE_OSX_ARCHITECTURES MATCHES "^([^;]+)(;|$)")
  29. set(_FortranCInterface_OSX_ARCH "-DCMAKE_OSX_ARCHITECTURES=${CMAKE_MATCH_1}")
  30. else()
  31. set(_FortranCInterface_OSX_ARCH "")
  32. endif()
  33. cmake_policy(GET CMP0056 _FortranCInterface_CMP0056)
  34. if(_FortranCInterface_CMP0056 STREQUAL "NEW")
  35. set(_FortranCInterface_EXE_LINKER_FLAGS "-DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_EXE_LINKER_FLAGS}")
  36. else()
  37. set(_FortranCInterface_EXE_LINKER_FLAGS "")
  38. endif()
  39. unset(_FortranCInterface_CMP0056)
  40. # Build a sample project which reports symbols.
  41. set(CMAKE_TRY_COMPILE_CONFIGURATION Release)
  42. try_compile(FortranCInterface_COMPILED
  43. PROJECT FortranCInterface
  44. TARGET FortranCInterface
  45. SOURCE_DIR ${FortranCInterface_SOURCE_DIR}
  46. BINARY_DIR ${FortranCInterface_BINARY_DIR}
  47. LOG_DESCRIPTION "Fortran/C interface test project"
  48. CMAKE_FLAGS
  49. "-DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS}"
  50. "-DCMAKE_Fortran_FLAGS:STRING=${CMAKE_Fortran_FLAGS}"
  51. "-DCMAKE_C_FLAGS_RELEASE:STRING=${CMAKE_C_FLAGS_RELEASE}"
  52. "-DCMAKE_Fortran_FLAGS_RELEASE:STRING=${CMAKE_Fortran_FLAGS_RELEASE}"
  53. ${_FortranCInterface_OSX_ARCH}
  54. ${_FortranCInterface_EXE_LINKER_FLAGS}
  55. )
  56. set(FortranCInterface_COMPILED ${FortranCInterface_COMPILED})
  57. unset(FortranCInterface_COMPILED CACHE)
  58. unset(_FortranCInterface_EXE_LINKER_FLAGS)
  59. unset(_FortranCInterface_OSX_ARCH)
  60. # Locate the sample project executable.
  61. set(FortranCInterface_EXE)
  62. if(FortranCInterface_COMPILED)
  63. include(${FortranCInterface_BINARY_DIR}/exe-Release.cmake OPTIONAL)
  64. else()
  65. set(_result "Failed to compile")
  66. endif()
  67. # Load symbols from INFO:symbol[] strings in the executable.
  68. set(FortranCInterface_SYMBOLS)
  69. if(FortranCInterface_EXE)
  70. cmake_policy(PUSH)
  71. cmake_policy(SET CMP0159 NEW) # file(STRINGS) with REGEX updates CMAKE_MATCH_<n>
  72. file(STRINGS "${FortranCInterface_EXE}" _info_strings
  73. LIMIT_COUNT 8 REGEX "INFO:[A-Za-z0-9_]+\\[[^]]*\\]")
  74. cmake_policy(POP)
  75. foreach(info ${_info_strings})
  76. if("${info}" MATCHES "INFO:symbol\\[([^]]*)\\]")
  77. list(APPEND FortranCInterface_SYMBOLS ${CMAKE_MATCH_1})
  78. endif()
  79. endforeach()
  80. elseif(NOT _result)
  81. set(_result "Failed to load sample executable")
  82. endif()
  83. set(_case_mysub "LOWER")
  84. set(_case_my_sub "LOWER")
  85. set(_case_MYSUB "UPPER")
  86. set(_case_MY_SUB "UPPER")
  87. set(_global_regex "^(_*)(mysub|MYSUB)([_$]*)$")
  88. set(_global__regex "^(_*)(my_sub|MY_SUB)([_$]*)$")
  89. set(_module_regex "^(_*)([A-Za-z$]*)(mymodule|MYMODULE)([A-Za-z_$]*)(mysub|MYSUB)([_$]*)$")
  90. set(_module__regex "^(_*)([A-Za-z$]*)(my_module|MY_MODULE)([A-Za-z_$]*)(my_sub|MY_SUB)([_$]*)$")
  91. # Parse the symbol names.
  92. foreach(symbol ${FortranCInterface_SYMBOLS})
  93. foreach(form "" "_")
  94. # Look for global symbols.
  95. string(REGEX REPLACE "${_global_${form}regex}"
  96. "\\1;\\2;\\3" pieces "${symbol}")
  97. list(LENGTH pieces len)
  98. if(len EQUAL 3)
  99. set(FortranCInterface_GLOBAL_${form}SYMBOL "${symbol}")
  100. list(GET pieces 0 FortranCInterface_GLOBAL_${form}PREFIX)
  101. list(GET pieces 1 name)
  102. list(GET pieces 2 FortranCInterface_GLOBAL_${form}SUFFIX)
  103. set(FortranCInterface_GLOBAL_${form}CASE "${_case_${name}}")
  104. endif()
  105. # Look for module symbols.
  106. string(REGEX REPLACE "${_module_${form}regex}"
  107. "\\1\\2;\\3;\\4;\\5;\\6" pieces "${symbol}")
  108. list(LENGTH pieces len)
  109. if(len EQUAL 5)
  110. set(FortranCInterface_MODULE_${form}SYMBOL "${symbol}")
  111. list(GET pieces 0 FortranCInterface_MODULE_${form}PREFIX)
  112. list(GET pieces 1 module)
  113. list(GET pieces 2 FortranCInterface_MODULE_${form}MIDDLE)
  114. list(GET pieces 3 name)
  115. list(GET pieces 4 FortranCInterface_MODULE_${form}SUFFIX)
  116. set(FortranCInterface_MODULE_${form}CASE "${_case_${name}}")
  117. endif()
  118. endforeach()
  119. endforeach()
  120. # Construct mangling macro definitions.
  121. set(_name_LOWER "name")
  122. set(_name_UPPER "NAME")
  123. foreach(form "" "_")
  124. if(FortranCInterface_GLOBAL_${form}SYMBOL)
  125. if(FortranCInterface_GLOBAL_${form}PREFIX)
  126. set(_prefix "${FortranCInterface_GLOBAL_${form}PREFIX}##")
  127. else()
  128. set(_prefix "")
  129. endif()
  130. if(FortranCInterface_GLOBAL_${form}SUFFIX)
  131. set(_suffix "##${FortranCInterface_GLOBAL_${form}SUFFIX}")
  132. else()
  133. set(_suffix "")
  134. endif()
  135. set(_name "${_name_${FortranCInterface_GLOBAL_${form}CASE}}")
  136. set(FortranCInterface_GLOBAL${form}_MACRO
  137. "(name,NAME) ${_prefix}${_name}${_suffix}")
  138. endif()
  139. if(FortranCInterface_MODULE_${form}SYMBOL)
  140. if(FortranCInterface_MODULE_${form}PREFIX)
  141. set(_prefix "${FortranCInterface_MODULE_${form}PREFIX}##")
  142. else()
  143. set(_prefix "")
  144. endif()
  145. if(FortranCInterface_MODULE_${form}SUFFIX)
  146. set(_suffix "##${FortranCInterface_MODULE_${form}SUFFIX}")
  147. else()
  148. set(_suffix "")
  149. endif()
  150. set(_name "${_name_${FortranCInterface_MODULE_${form}CASE}}")
  151. set(_middle "##${FortranCInterface_MODULE_${form}MIDDLE}##")
  152. set(FortranCInterface_MODULE${form}_MACRO
  153. "(mod_name,name, mod_NAME,NAME) ${_prefix}mod_${_name}${_middle}${_name}${_suffix}")
  154. endif()
  155. endforeach()
  156. # Summarize what is available.
  157. foreach(scope GLOBAL MODULE)
  158. if(FortranCInterface_${scope}_SYMBOL AND
  159. FortranCInterface_${scope}__SYMBOL)
  160. set(FortranCInterface_${scope}_FOUND 1)
  161. else()
  162. set(FortranCInterface_${scope}_FOUND 0)
  163. endif()
  164. endforeach()
  165. # Record the detection results.
  166. configure_file(${FortranCInterface_SOURCE_DIR}/Output.cmake.in
  167. ${FortranCInterface_BINARY_DIR}/Output.cmake @ONLY)
  168. # Report the results.
  169. if(FortranCInterface_GLOBAL_FOUND)
  170. if(FortranCInterface_MODULE_FOUND)
  171. set(_result "Found GLOBAL and MODULE mangling")
  172. else()
  173. set(_result "Found GLOBAL but not MODULE mangling")
  174. endif()
  175. set(_result_type CHECK_PASS)
  176. elseif(NOT _result)
  177. set(_result "Failed to recognize symbols")
  178. set(_result_type CHECK_FAIL)
  179. endif()
  180. message(${_result_type} "${_result}")