Detect.cmake 6.4 KB

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