FortranCInterface.cmake 7.7 KB

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