FortranCInterface.cmake 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  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. foreach(interface
  87. "test_interface$"
  88. "TEST_INTERFACE_mp_"
  89. "__test_interface_NMOD_"
  90. "__test_interface_MOD_")
  91. test_fortran_mangling("${CODE}" "${interface}"
  92. ${FORTRAN_C_MANGLING_UPPERCASE} "" "module" "sub" worked)
  93. if(worked)
  94. string(REGEX REPLACE "(.*)test_interface(.*)" "\\1" pre "${interface}")
  95. string(REGEX REPLACE "(.*)test_interface(.*)" "\\2" post "${interface}")
  96. set(${prefix} "${pre}" PARENT_SCOPE)
  97. set(${suffix} "${post}" PARENT_SCOPE)
  98. set(${found} TRUE PARENT_SCOPE)
  99. return()
  100. endif(worked)
  101. endforeach(interface)
  102. endfunction(discover_fortran_module_mangling)
  103. function(discover_fortran_mangling prefix isupper suffix extra_under_score
  104. found )
  105. set(CODE
  106. "
  107. subroutine sub
  108. end subroutine sub
  109. ")
  110. foreach(post "_" "")
  111. foreach(isup FALSE TRUE)
  112. foreach(pre "" "_" "__")
  113. set(worked FALSE)
  114. test_fortran_mangling("${CODE}" "${pre}" ${isup}
  115. "${post}" "function" sub worked )
  116. if(worked)
  117. message(STATUS "found Fortran function linkage")
  118. set(${isupper} "${isup}" PARENT_SCOPE)
  119. set(${prefix} "${pre}" PARENT_SCOPE)
  120. set(${suffix} "${post}" PARENT_SCOPE)
  121. set(${found} TRUE PARENT_SCOPE)
  122. set(CODE
  123. "
  124. subroutine my_sub
  125. end subroutine my_sub
  126. ")
  127. set(worked FALSE)
  128. test_fortran_mangling("${CODE}" "${pre}" ${isup}
  129. "${post}" "function with _ " my_sub worked )
  130. if(worked)
  131. set(${extra_under_score} FALSE PARENT_SCOPE)
  132. else(worked)
  133. test_fortran_mangling("${CODE}" "${pre}" ${isup}
  134. "${post}_" "function with _ " my_sub worked )
  135. if(worked)
  136. set(${extra_under_score} TRUE PARENT_SCOPE)
  137. endif(worked)
  138. endif(worked)
  139. return()
  140. endif()
  141. endforeach()
  142. endforeach()
  143. endforeach()
  144. set(${found} FALSE PARENT_SCOPE)
  145. endfunction(discover_fortran_mangling)
  146. function(create_fortran_c_interface NAMESPACE FUNCTIONS HEADER)
  147. if(NOT FORTRAN_C_MANGLING_FOUND)
  148. # find regular fortran function mangling
  149. discover_fortran_mangling(prefix isupper suffix extra_under found)
  150. if(NOT found)
  151. message(SEND_ERROR "Could not find fortran c name mangling.")
  152. return()
  153. endif(NOT found)
  154. # find fortran module function mangling
  155. set(FORTRAN_C_PREFIX "${prefix}" CACHE INTERNAL
  156. "PREFIX for Fortran to c name mangling")
  157. set(FORTRAN_C_SUFFIX "${suffix}" CACHE INTERNAL
  158. "SUFFIX for Fortran to c name mangling")
  159. set(FORTRAN_C_MANGLING_UPPERCASE ${isupper} CACHE INTERNAL
  160. "Was fortran to c mangling found" )
  161. set(FORTRAN_C_MANGLING_EXTRA_UNDERSCORE ${extra_under} CACHE INTERNAL
  162. "If a function has a _ in the name does the compiler append an extra _" )
  163. set(FORTRAN_C_MANGLING_FOUND TRUE CACHE INTERNAL
  164. "Was fortran to c mangling found" )
  165. set(prefix )
  166. set(suffix )
  167. set(found FALSE)
  168. # only try this if the compiler is F90 compatible
  169. if(CMAKE_Fortran_COMPILER_SUPPORTS_F90)
  170. discover_fortran_module_mangling(prefix suffix found)
  171. endif(CMAKE_Fortran_COMPILER_SUPPORTS_F90)
  172. if(found)
  173. message(STATUS "found Fortran module linkage")
  174. set(FORTRAN_C_MODULE_PREFIX "${prefix}" CACHE INTERNAL
  175. "PREFIX for Fortran to c name mangling")
  176. set(FORTRAN_C_MODULE_SUFFIX "${suffix}" CACHE INTERNAL
  177. "SUFFIX for Fortran to c name mangling")
  178. set(FORTRAN_C_MODULE_MANGLING_FOUND TRUE CACHE INTERNAL
  179. "SUFFIX for Fortran to c name mangling")
  180. else(found)
  181. set(FORTRAN_C_MODULE_MANGLING_FOUND FALSE CACHE INTERNAL
  182. "SUFFIX for Fortran to c name mangling")
  183. endif(found)
  184. endif(NOT FORTRAN_C_MANGLING_FOUND)
  185. foreach(f ${${FUNCTIONS}})
  186. if(FORTRAN_C_MANGLING_UPPERCASE)
  187. string(TOUPPER "${f}" f)
  188. else()
  189. string(TOLOWER "${f}" f)
  190. endif()
  191. if("${f}" MATCHES ":")
  192. string(REGEX REPLACE "(.*):(.*)" "\\1" module "${f}")
  193. string(REGEX REPLACE "(.*):(.*)" "\\2" function "${f}")
  194. set(HEADER_CONTENT "${HEADER_CONTENT}
  195. #define ${NAMESPACE}${module}_${function} ${FORTRAN_C_MODULE_PREFIX}${module}${FORTRAN_C_MODULE_SUFFIX}${function}
  196. ")
  197. else("${f}" MATCHES ":")
  198. set(function "${FORTRAN_C_PREFIX}${f}${FORTRAN_C_SUFFIX}")
  199. if("${f}" MATCHES "_" AND FORTRAN_C_MANGLING_EXTRA_UNDERSCORE)
  200. set(function "${function}_")
  201. endif("${f}" MATCHES "_" AND FORTRAN_C_MANGLING_EXTRA_UNDERSCORE)
  202. set(HEADER_CONTENT "${HEADER_CONTENT}
  203. #define ${NAMESPACE}${f} ${function}
  204. ")
  205. endif("${f}" MATCHES ":")
  206. endforeach(f)
  207. configure_file(
  208. "${CMAKE_ROOT}/Modules/FortranCInterface.h.in"
  209. ${HEADER} @ONLY)
  210. message(STATUS "created ${HEADER}")
  211. endfunction()