Detect.cmake 6.2 KB

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