FortranCInterface.cmake 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  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. # RESULT place to store result TRUE if this linkage works, FALSE
  31. # if not.
  32. #
  33. function(test_fortran_mangling CODE PREFIX ISUPPER POSTFIX DOC RESULT)
  34. if(ISUPPER)
  35. set(FUNCTION "${PREFIX}SUB${POSTFIX}")
  36. else(ISUPPER)
  37. set(FUNCTION "${PREFIX}sub${POSTFIX}")
  38. endif(ISUPPER)
  39. # create a fortran file with sub called sub
  40. #
  41. set(TMP_DIR
  42. "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckFortranLink")
  43. file(REMOVE_RECURSE "${TMP_DIR}")
  44. file(WRITE "${TMP_DIR}/test.f" "${CODE}" )
  45. message(STATUS "checking Fortran ${DOC} linkage: ${FUNCTION}")
  46. file(WRITE "${TMP_DIR}/ctof.c"
  47. "
  48. extern ${FUNCTION}();
  49. int main() { ${FUNCTION}(); return 0;}
  50. "
  51. )
  52. file(WRITE "${TMP_DIR}/CMakeLists.txt"
  53. "
  54. project(testf C Fortran)
  55. add_library(flib test.f)
  56. add_executable(ctof ctof.c)
  57. target_link_libraries(ctof flib)
  58. "
  59. )
  60. set(FORTRAN_NAME_MANGLE_TEST FALSE)
  61. try_compile(FORTRAN_NAME_MANGLE_TEST "${TMP_DIR}" "${TMP_DIR}"
  62. testf
  63. OUTPUT_VARIABLE output)
  64. if(FORTRAN_NAME_MANGLE_TEST)
  65. set(${RESULT} TRUE PARENT_SCOPE)
  66. else()
  67. set(${RESULT} FALSE PARENT_SCOPE)
  68. endif()
  69. endfunction(test_fortran_mangling)
  70. # this function discovers the name mangling scheme used
  71. # for functions in a fortran module.
  72. function(discover_fortran_module_mangling prefix suffix found)
  73. set(CODE
  74. "
  75. module test_interface
  76. interface dummy
  77. module procedure sub
  78. end interface
  79. contains
  80. subroutine sub
  81. end subroutine
  82. end module test_interface
  83. ")
  84. foreach(interface
  85. "test_interface$"
  86. ".__test_interface_NMOD_"
  87. "__test_interface_MOD_")
  88. test_fortran_mangling("${CODE}" "${interface}"
  89. ${FORTRAN_C_MANGLING_UPPERCASE} "" "module" worked)
  90. if(worked)
  91. string(REGEX REPLACE "(.*)test_interface(.*)" "\\1" pre "${interface}")
  92. string(REGEX REPLACE "(.*)test_interface(.*)" "\\2" post "${interface}")
  93. set(${prefix} "${pre}" PARENT_SCOPE)
  94. set(${suffix} "${post}" PARENT_SCOPE)
  95. set(${found} TRUE PARENT_SCOPE)
  96. return()
  97. endif(worked)
  98. endforeach(interface)
  99. endfunction(discover_fortran_module_mangling)
  100. function(discover_fortran_mangling prefix isupper suffix found )
  101. set(CODE
  102. "
  103. subroutine sub
  104. end subroutine sub
  105. ")
  106. foreach(pre "_" "" "__")
  107. foreach(isup TRUE FALSE)
  108. foreach(post "" "_")
  109. set(worked FALSE)
  110. test_fortran_mangling("${CODE}" "${pre}" ${isup} "${post}" "function" worked )
  111. if(worked)
  112. message(STATUS "found Fortran function linkage")
  113. set(${isupper} "${isup}" PARENT_SCOPE)
  114. set(${prefix} "${pre}" PARENT_SCOPE)
  115. set(${suffix} "${post}" PARENT_SCOPE)
  116. set(${found} TRUE PARENT_SCOPE)
  117. return()
  118. endif()
  119. endforeach()
  120. endforeach()
  121. endforeach()
  122. set(${found} FALSE PARENT_SCOPE)
  123. endfunction(discover_fortran_mangling)
  124. function(create_fortran_c_interface NAMESPACE FUNCTIONS HEADER)
  125. if(NOT FORTRAN_C_MANGLING_FOUND)
  126. # find regular fortran function mangling
  127. discover_fortran_mangling(prefix isupper suffix found)
  128. if(NOT found)
  129. message(SEND_ERROR "Could not find fortran c name mangling.")
  130. return()
  131. endif(NOT found)
  132. # find fortran module function mangling
  133. set(FORTRAN_C_PREFIX "${prefix}" CACHE INTERNAL
  134. "PREFIX for Fortran to c name mangling")
  135. set(FORTRAN_C_SUFFIX "${suffix}" CACHE INTERNAL
  136. "SUFFIX for Fortran to c name mangling")
  137. set(FORTRAN_C_MANGLING_UPPERCASE ${isupper} CACHE INTERNAL
  138. "Was fortran to c mangling found" )
  139. set(FORTRAN_C_MANGLING_FOUND TRUE CACHE INTERNAL
  140. "Was fortran to c mangling found" )
  141. set(prefix )
  142. set(suffix )
  143. set(found FALSE)
  144. discover_fortran_module_mangling(prefix suffix found)
  145. if(found)
  146. message(STATUS "found Fortran module linkage")
  147. set(FORTRAN_C_MODULE_PREFIX "${prefix}" CACHE INTERNAL
  148. "PREFIX for Fortran to c name mangling")
  149. set(FORTRAN_C_MODULE_SUFFIX "${suffix}" CACHE INTERNAL
  150. "SUFFIX for Fortran to c name mangling")
  151. set(FORTRAN_C_MODULE_MANGLING_FOUND TRUE CACHE INTERNAL
  152. "SUFFIX for Fortran to c name mangling")
  153. else(found)
  154. set(FORTRAN_C_MODULE_MANGLING_FOUND FALSE CACHE INTERNAL
  155. "SUFFIX for Fortran to c name mangling")
  156. endif(found)
  157. endif(NOT FORTRAN_C_MANGLING_FOUND)
  158. foreach(f ${${FUNCTIONS}})
  159. if(${FORTRAN_C_MANGLING_UPPERCASE})
  160. string(TOUPPER "${f}" ff)
  161. else()
  162. string(TOLOWER "${f}" ff)
  163. endif()
  164. if("${f}" MATCHES ":")
  165. string(REGEX REPLACE "(.*):(.*)" "\\1" module "${f}")
  166. string(REGEX REPLACE "(.*):(.*)" "\\2" function "${f}")
  167. set(HEADER_CONTENT "${HEADER_CONTENT}
  168. #define ${NAMESPACE}${module}_${function} ${FORTRAN_C_MODULE_PREFIX}${module}${FORTRAN_C_MODULE_SUFFIX}${function}
  169. ")
  170. else("${f}" MATCHES ":")
  171. set(function "${FORTRAN_C_PREFIX}${ff}${FORTRAN_C_SUFFIX}")
  172. set(HEADER_CONTENT "${HEADER_CONTENT}
  173. #define ${NAMESPACE}${f} ${function}
  174. ")
  175. endif("${f}" MATCHES ":")
  176. endforeach(f)
  177. configure_file(
  178. "${CMAKE_ROOT}/Modules/FortranCInterface.h.in"
  179. ${HEADER} @ONLY)
  180. message(STATUS "created ${HEADER}")
  181. endfunction()