1 # FortranCInterface.cmake
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
9 # The function tages a list of functions and the name of
10 # a header file to configure.
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
19 # discover_fortran_module_mangling - try different types of
20 # fortran modle name mangling to find one that works
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
34 function(test_fortran_mangling CODE PREFIX ISUPPER POSTFIX DOC SUB RESULT)
36 string(TOUPPER "${SUB}" sub)
38 string(TOLOWER "${SUB}" sub)
40 set(FUNCTION "${PREFIX}${sub}${POSTFIX}")
41 # create a fortran file with sub called sub
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"
51 int main() { ${FUNCTION}(); return 0;}
54 file(WRITE "${TMP_DIR}/CMakeLists.txt"
56 project(testf C Fortran)
57 add_library(flib test.f)
58 add_executable(ctof ctof.c)
59 target_link_libraries(ctof flib)
62 set(FORTRAN_NAME_MANGLE_TEST FALSE)
63 try_compile(FORTRAN_NAME_MANGLE_TEST "${TMP_DIR}" "${TMP_DIR}"
65 OUTPUT_VARIABLE output)
66 if(FORTRAN_NAME_MANGLE_TEST)
67 set(${RESULT} TRUE PARENT_SCOPE)
69 set(${RESULT} FALSE PARENT_SCOPE)
71 endfunction(test_fortran_mangling)
73 # this function discovers the name mangling scheme used
74 # for functions in a fortran module.
75 function(discover_fortran_module_mangling prefix suffix found)
85 end module test_interface
91 "__test_interface_NMOD_"
92 "__test_interface_MOD_")
93 test_fortran_mangling("${CODE}" "${interface}"
94 ${FORTRAN_C_MANGLING_UPPERCASE} "" "module" "sub" worked)
96 # if this is the upper case module match then
97 # lower case it for the extraction of pre and post strings
98 if("${interface}" MATCHES "TEST_INTERFACE")
99 string(TOLOWER "${interface}" interface)
101 string(REGEX REPLACE "(.*)test_interface(.*)" "\\1" pre "${interface}")
102 string(REGEX REPLACE "(.*)test_interface(.*)" "\\2" post "${interface}")
103 set(${prefix} "${pre}" PARENT_SCOPE)
104 set(${suffix} "${post}" PARENT_SCOPE)
105 set(${found} TRUE PARENT_SCOPE)
108 endforeach(interface)
110 message(STATUS "Failed to find C binding to Fortran module functions.")
111 set(${prefix} "BROKEN_C_FORTRAN_MODULE_BINDING" PARENT_SCOPE)
112 set(${suffix} "BROKEN_C_FORTRAN_MODULE_BINDING" PARENT_SCOPE)
113 set(${found} FALSE PARENT_SCOPE)
115 endfunction(discover_fortran_module_mangling)
118 function(discover_fortran_mangling prefix isupper suffix extra_under_score
126 foreach(isup FALSE TRUE)
127 foreach(pre "" "_" "__")
129 test_fortran_mangling("${CODE}" "${pre}" ${isup}
130 "${post}" "function" sub worked )
132 message(STATUS "found Fortran function linkage")
133 set(${isupper} "${isup}" PARENT_SCOPE)
134 set(${prefix} "${pre}" PARENT_SCOPE)
135 set(${suffix} "${post}" PARENT_SCOPE)
136 set(${found} TRUE PARENT_SCOPE)
140 end subroutine my_sub
143 test_fortran_mangling("${CODE}" "${pre}" ${isup}
144 "${post}" "function with _ " my_sub worked )
146 set(${extra_under_score} FALSE PARENT_SCOPE)
148 test_fortran_mangling("${CODE}" "${pre}" ${isup}
149 "${post}_" "function with _ " my_sub worked )
151 set(${extra_under_score} TRUE PARENT_SCOPE)
159 set(${found} FALSE PARENT_SCOPE)
160 endfunction(discover_fortran_mangling)
162 function(create_fortran_c_interface NAMESPACE FUNCTIONS HEADER)
163 if(NOT FORTRAN_C_MANGLING_FOUND)
164 # find regular fortran function mangling
165 discover_fortran_mangling(prefix isupper suffix extra_under found)
167 message(SEND_ERROR "Could not find fortran c name mangling.")
170 # find fortran module function mangling
171 set(FORTRAN_C_PREFIX "${prefix}" CACHE INTERNAL
172 "PREFIX for Fortran to c name mangling")
173 set(FORTRAN_C_SUFFIX "${suffix}" CACHE INTERNAL
174 "SUFFIX for Fortran to c name mangling")
175 set(FORTRAN_C_MANGLING_UPPERCASE ${isupper} CACHE INTERNAL
176 "Was fortran to c mangling found" )
177 set(FORTRAN_C_MANGLING_EXTRA_UNDERSCORE ${extra_under} CACHE INTERNAL
178 "If a function has a _ in the name does the compiler append an extra _" )
179 set(FORTRAN_C_MANGLING_FOUND TRUE CACHE INTERNAL
180 "Was fortran to c mangling found" )
184 # only try this if the compiler is F90 compatible
185 if(CMAKE_Fortran_COMPILER_SUPPORTS_F90)
186 discover_fortran_module_mangling(prefix suffix found)
187 endif(CMAKE_Fortran_COMPILER_SUPPORTS_F90)
189 message(STATUS "found Fortran module linkage")
190 set(FORTRAN_C_MODULE_PREFIX "${prefix}" CACHE INTERNAL
191 "PREFIX for Fortran to c name mangling")
192 set(FORTRAN_C_MODULE_SUFFIX "${suffix}" CACHE INTERNAL
193 "SUFFIX for Fortran to c name mangling")
194 set(FORTRAN_C_MODULE_MANGLING_FOUND TRUE CACHE INTERNAL
195 "SUFFIX for Fortran to c name mangling")
197 set(FORTRAN_C_MODULE_MANGLING_FOUND FALSE CACHE INTERNAL
198 "Fortran to C Module calling not availible.")
200 endif(NOT FORTRAN_C_MANGLING_FOUND)
201 foreach(f ${${FUNCTIONS}})
202 if(FORTRAN_C_MANGLING_UPPERCASE)
203 string(TOUPPER "${f}" fcase)
205 string(TOLOWER "${f}" fcase)
207 if("${f}" MATCHES ":")
208 string(REGEX REPLACE "(.*):(.*)" "\\1" module "${f}")
209 string(REGEX REPLACE "(.*):(.*)" "\\2" function "${f}")
210 string(REGEX REPLACE "(.*):(.*)" "\\1" module_case "${fcase}")
211 string(REGEX REPLACE "(.*):(.*)" "\\2" function_case "${fcase}")
212 set(HEADER_CONTENT "${HEADER_CONTENT}
213 #define ${NAMESPACE}${module}_${function} ${FORTRAN_C_MODULE_PREFIX}${module_case}${FORTRAN_C_MODULE_SUFFIX}${function_case}
215 else("${f}" MATCHES ":")
216 set(function "${FORTRAN_C_PREFIX}${fcase}${FORTRAN_C_SUFFIX}")
217 if("${f}" MATCHES "_" AND FORTRAN_C_MANGLING_EXTRA_UNDERSCORE)
218 set(function "${function}_")
219 endif("${f}" MATCHES "_" AND FORTRAN_C_MANGLING_EXTRA_UNDERSCORE)
220 set(HEADER_CONTENT "${HEADER_CONTENT}
221 #define ${NAMESPACE}${f} ${function}
223 endif("${f}" MATCHES ":")
226 "${CMAKE_ROOT}/Modules/FortranCInterface.h.in"
228 message(STATUS "created ${HEADER}")