Detect.cmake 6.7 KB

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