FortranCInterface.cmake 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. # FortranCInterface.cmake
  2. #
  3. # This file defines the function create_fortran_c_interface.
  4. # this function is used to create a configured header file
  5. # that contains a mapping from C to a Fortran function using
  6. # the correct name mangling scheme as defined by the current
  7. # fortran compiler.
  8. #
  9. # The function tages a list of functions and the name of
  10. # a header file to configure.
  11. #
  12. # This file also defines some helper functions that are used
  13. # to detect the fortran name mangling scheme used by the
  14. # current Fortran compiler.
  15. # test_fortran_mangling - test a single fortran mangling
  16. # discover_fortran_mangling - loop over all combos of fortran
  17. # name mangling and call test_fortran_mangling until one of them
  18. # works.
  19. # discover_fortran_module_mangling - try different types of
  20. # fortran modle name mangling to find one that works
  21. #
  22. #
  23. #
  24. # this function tests a single fortran mangling.
  25. # CODE - test code to try should define a subroutine called "sub"
  26. # PREFIX - string to put in front of sub
  27. # POSTFIX - string to put after sub
  28. # ISUPPER - if TRUE then sub will be called as SUB
  29. # DOC - string used in status checking Fortran ${DOC} linkage
  30. # SUB - the name of the SUB to call
  31. # RESULT place to store result TRUE if this linkage works, FALSE
  32. # if not.
  33. #
  34. function(test_fortran_mangling CODE PREFIX ISUPPER POSTFIX DOC SUB RESULT)
  35. if(ISUPPER)
  36. string(TOUPPER "${SUB}" sub)
  37. else(ISUPPER)
  38. string(TOLOWER "${SUB}" sub)
  39. endif(ISUPPER)
  40. set(FUNCTION "${PREFIX}${sub}${POSTFIX}")
  41. # create a fortran file with sub called sub
  42. #
  43. set(TMP_DIR
  44. "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckFortranLink")
  45. file(REMOVE_RECURSE "${TMP_DIR}")
  46. file(WRITE "${TMP_DIR}/test.f" "${CODE}" )
  47. message(STATUS "checking Fortran ${DOC} linkage: ${FUNCTION}")
  48. file(WRITE "${TMP_DIR}/ctof.c"
  49. "
  50. extern ${FUNCTION}();
  51. int main() { ${FUNCTION}(); return 0;}
  52. "
  53. )
  54. file(WRITE "${TMP_DIR}/CMakeLists.txt"
  55. "
  56. project(testf C Fortran)
  57. add_library(flib test.f)
  58. add_executable(ctof ctof.c)
  59. target_link_libraries(ctof flib)
  60. "
  61. )
  62. set(FORTRAN_NAME_MANGLE_TEST FALSE)
  63. try_compile(FORTRAN_NAME_MANGLE_TEST "${TMP_DIR}" "${TMP_DIR}"
  64. testf
  65. OUTPUT_VARIABLE output)
  66. if(FORTRAN_NAME_MANGLE_TEST)
  67. set(${RESULT} TRUE PARENT_SCOPE)
  68. else()
  69. set(${RESULT} FALSE PARENT_SCOPE)
  70. endif()
  71. endfunction(test_fortran_mangling)
  72. # this function discovers the name mangling scheme used
  73. # for functions in a fortran module.
  74. function(discover_fortran_module_mangling prefix suffix found)
  75. set(CODE
  76. "
  77. module test_interface
  78. interface dummy
  79. module procedure sub
  80. end interface
  81. contains
  82. subroutine sub
  83. end subroutine
  84. end module test_interface
  85. ")
  86. set(worked FALSE)
  87. foreach(interface
  88. "test_interface$"
  89. "TEST_INTERFACE_mp_"
  90. "_test_interface__"
  91. "__test_interface__"
  92. "__test_interface_NMOD_"
  93. "__test_interface_MOD_")
  94. test_fortran_mangling("${CODE}" "${interface}"
  95. ${FORTRAN_C_MANGLING_UPPERCASE} "" "module" "sub" worked)
  96. if(worked)
  97. # if this is the upper case module match then
  98. # lower case it for the extraction of pre and post strings
  99. if("${interface}" MATCHES "TEST_INTERFACE")
  100. string(TOLOWER "${interface}" interface)
  101. endif()
  102. string(REGEX REPLACE "(.*)test_interface(.*)" "\\1" pre "${interface}")
  103. string(REGEX REPLACE "(.*)test_interface(.*)" "\\2" post "${interface}")
  104. set(${prefix} "${pre}" PARENT_SCOPE)
  105. set(${suffix} "${post}" PARENT_SCOPE)
  106. set(${found} TRUE PARENT_SCOPE)
  107. return()
  108. endif(worked)
  109. endforeach(interface)
  110. if(NOT worked)
  111. message(STATUS "Failed to find C binding to Fortran module functions.")
  112. set(${prefix} "BROKEN_C_FORTRAN_MODULE_BINDING" PARENT_SCOPE)
  113. set(${suffix} "BROKEN_C_FORTRAN_MODULE_BINDING" PARENT_SCOPE)
  114. set(${found} FALSE PARENT_SCOPE)
  115. endif(NOT worked)
  116. endfunction(discover_fortran_module_mangling)
  117. function(discover_fortran_mangling prefix isupper suffix extra_under_score
  118. found )
  119. set(CODE
  120. "
  121. subroutine sub
  122. end subroutine sub
  123. ")
  124. foreach(post "_" "")
  125. foreach(isup FALSE TRUE)
  126. foreach(pre "" "_" "__")
  127. set(worked FALSE)
  128. test_fortran_mangling("${CODE}" "${pre}" ${isup}
  129. "${post}" "function" sub worked )
  130. if(worked)
  131. message(STATUS "found Fortran function linkage")
  132. set(${isupper} "${isup}" PARENT_SCOPE)
  133. set(${prefix} "${pre}" PARENT_SCOPE)
  134. set(${suffix} "${post}" PARENT_SCOPE)
  135. set(${found} TRUE PARENT_SCOPE)
  136. set(CODE
  137. "
  138. subroutine my_sub
  139. end subroutine my_sub
  140. ")
  141. set(worked FALSE)
  142. test_fortran_mangling("${CODE}" "${pre}" ${isup}
  143. "${post}" "function with _ " my_sub worked )
  144. if(worked)
  145. set(${extra_under_score} FALSE PARENT_SCOPE)
  146. else(worked)
  147. test_fortran_mangling("${CODE}" "${pre}" ${isup}
  148. "${post}_" "function with _ " my_sub worked )
  149. if(worked)
  150. set(${extra_under_score} TRUE PARENT_SCOPE)
  151. endif(worked)
  152. endif(worked)
  153. return()
  154. endif()
  155. endforeach()
  156. endforeach()
  157. endforeach()
  158. set(${found} FALSE PARENT_SCOPE)
  159. endfunction(discover_fortran_mangling)
  160. function(create_fortran_c_interface NAMESPACE FUNCTIONS HEADER)
  161. if(NOT FORTRAN_C_MANGLING_FOUND)
  162. # find regular fortran function mangling
  163. discover_fortran_mangling(prefix isupper suffix extra_under found)
  164. if(NOT found)
  165. message(SEND_ERROR "Could not find fortran c name mangling.")
  166. return()
  167. endif(NOT found)
  168. # find fortran module function mangling
  169. set(FORTRAN_C_PREFIX "${prefix}" CACHE INTERNAL
  170. "PREFIX for Fortran to c name mangling")
  171. set(FORTRAN_C_SUFFIX "${suffix}" CACHE INTERNAL
  172. "SUFFIX for Fortran to c name mangling")
  173. set(FORTRAN_C_MANGLING_UPPERCASE ${isupper} CACHE INTERNAL
  174. "Was fortran to c mangling found" )
  175. set(FORTRAN_C_MANGLING_EXTRA_UNDERSCORE ${extra_under} CACHE INTERNAL
  176. "If a function has a _ in the name does the compiler append an extra _" )
  177. set(FORTRAN_C_MANGLING_FOUND TRUE CACHE INTERNAL
  178. "Was fortran to c mangling found" )
  179. set(prefix )
  180. set(suffix )
  181. set(found FALSE)
  182. # only try this if the compiler is F90 compatible
  183. if(CMAKE_Fortran_COMPILER_SUPPORTS_F90)
  184. discover_fortran_module_mangling(prefix suffix found)
  185. endif(CMAKE_Fortran_COMPILER_SUPPORTS_F90)
  186. if(found)
  187. message(STATUS "found Fortran module linkage")
  188. else(found)
  189. message(STATUS "Failed to find Fortran module linkage")
  190. endif(found)
  191. set(FORTRAN_C_MODULE_PREFIX "${prefix}" CACHE INTERNAL
  192. "PREFIX for Fortran to c name mangling")
  193. set(FORTRAN_C_MODULE_SUFFIX "${suffix}" CACHE INTERNAL
  194. "SUFFIX for Fortran to c name mangling")
  195. set(FORTRAN_C_MODULE_MANGLING_FOUND ${found} CACHE INTERNAL
  196. "Was for Fortran to c name mangling found for modules")
  197. endif(NOT FORTRAN_C_MANGLING_FOUND)
  198. foreach(f ${${FUNCTIONS}})
  199. if(FORTRAN_C_MANGLING_UPPERCASE)
  200. string(TOUPPER "${f}" fcase)
  201. else()
  202. string(TOLOWER "${f}" fcase)
  203. endif()
  204. if("${f}" MATCHES ":")
  205. string(REGEX REPLACE "(.*):(.*)" "\\1" module "${f}")
  206. string(REGEX REPLACE "(.*):(.*)" "\\2" function "${f}")
  207. string(REGEX REPLACE "(.*):(.*)" "\\1" module_case "${fcase}")
  208. string(REGEX REPLACE "(.*):(.*)" "\\2" function_case "${fcase}")
  209. set(HEADER_CONTENT "${HEADER_CONTENT}
  210. #define ${NAMESPACE}${module}_${function} ${FORTRAN_C_MODULE_PREFIX}${module_case}${FORTRAN_C_MODULE_SUFFIX}${function_case}
  211. ")
  212. else("${f}" MATCHES ":")
  213. set(function "${FORTRAN_C_PREFIX}${fcase}${FORTRAN_C_SUFFIX}")
  214. if("${f}" MATCHES "_" AND FORTRAN_C_MANGLING_EXTRA_UNDERSCORE)
  215. set(function "${function}_")
  216. endif("${f}" MATCHES "_" AND FORTRAN_C_MANGLING_EXTRA_UNDERSCORE)
  217. set(HEADER_CONTENT "${HEADER_CONTENT}
  218. #define ${NAMESPACE}${f} ${function}
  219. ")
  220. endif("${f}" MATCHES ":")
  221. endforeach(f)
  222. configure_file(
  223. "${CMAKE_ROOT}/Modules/FortranCInterface.h.in"
  224. ${HEADER} @ONLY)
  225. message(STATUS "created ${HEADER}")
  226. endfunction()