Detect.cmake 6.8 KB

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