FortranCInterface.cmake 7.5 KB

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