Merge branch 'master' of git.gromacs.org:gromacs
[gromacs/qmmm-gamess-us.git] / cmake / FortranCInterface.cmake
blob6551658c76fb346d174407c75430f127a5f9af91
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 
7 # fortran compiler.  
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
18 #   works.
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
32 #        if not.
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)
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)
76   set(CODE 
77     "
78       module test_interface
79       interface dummy
80          module procedure sub
81       end interface
82       contains
83         subroutine sub
84         end subroutine
85       end module test_interface
86     ")
87   set(worked FALSE)
88   foreach(interface 
89       "test_interface$" 
90       "TEST_INTERFACE_mp_" 
91       "_test_interface__" 
92       "__test_interface__" 
93       "__test_interface_NMOD_" 
94       "__test_interface_MOD_")
95     test_fortran_mangling("${CODE}" "${interface}"
96       ${FORTRAN_C_MANGLING_UPPERCASE} "" "module" "sub" worked)
97     if(worked)
98       # if this is the upper case module match then
99       # lower case it for the extraction of pre and post strings
100       if("${interface}" MATCHES "TEST_INTERFACE")
101         string(TOLOWER "${interface}" interface)
102       endif()
103       string(REGEX REPLACE "(.*)test_interface(.*)" "\\1" pre "${interface}")
104       string(REGEX REPLACE "(.*)test_interface(.*)" "\\2" post "${interface}")
105       set(${prefix} "${pre}" PARENT_SCOPE)
106       set(${suffix} "${post}" PARENT_SCOPE)
107       set(${found} TRUE PARENT_SCOPE)
108       return()
109     endif(worked)
110   endforeach(interface)
111   if(NOT worked)
112     message(STATUS "Failed to find C binding to Fortran module functions.")
113     set(${prefix} "BROKEN_C_FORTRAN_MODULE_BINDING" PARENT_SCOPE)
114     set(${suffix} "BROKEN_C_FORTRAN_MODULE_BINDING" PARENT_SCOPE)
115     set(${found} FALSE PARENT_SCOPE)
116   endif(NOT worked)
117 endfunction(discover_fortran_module_mangling)
120 function(discover_fortran_mangling prefix isupper suffix extra_under_score
121     found )
122   set(CODE 
123     "
124       subroutine sub
125       end subroutine sub
126     ")
127   foreach(post "_" "")
128     foreach(isup FALSE TRUE)
129       foreach(pre "" "_" "__")
130         set(worked FALSE)
131         test_fortran_mangling("${CODE}" "${pre}" ${isup}
132           "${post}" "function" sub worked )
133         if(worked)
134           message(STATUS "found Fortran function linkage")
135           set(${isupper} "${isup}" PARENT_SCOPE)
136           set(${prefix} "${pre}" PARENT_SCOPE)
137           set(${suffix} "${post}" PARENT_SCOPE)
138           set(${found} TRUE PARENT_SCOPE)
139           set(CODE 
140             "
141       subroutine my_sub
142       end subroutine my_sub
143     ")
144           set(worked FALSE)
145           test_fortran_mangling("${CODE}" "${pre}" ${isup}
146             "${post}" "function with _ " my_sub worked )
147           if(worked)
148             set(${extra_under_score} FALSE PARENT_SCOPE)
149           else(worked)
150             test_fortran_mangling("${CODE}" "${pre}" ${isup}
151               "${post}_" "function with _ " my_sub worked )
152             if(worked)
153               set(${extra_under_score} TRUE PARENT_SCOPE)
154             endif(worked)
155           endif(worked)
156         return()
157         endif()
158       endforeach()
159     endforeach()
160   endforeach()
161   set(${found} FALSE PARENT_SCOPE)
162 endfunction(discover_fortran_mangling)
164 function(create_fortran_c_interface NAMESPACE FUNCTIONS HEADER)
165   if(NOT FORTRAN_C_MANGLING_FOUND)
166     # find regular fortran function mangling
167     discover_fortran_mangling(prefix isupper suffix extra_under found)
168     if(NOT found)
169       message(SEND_ERROR "Could not find fortran c name mangling.")
170       return()
171     endif(NOT found)
172     # find fortran module function mangling
173     set(FORTRAN_C_PREFIX "${prefix}" CACHE INTERNAL
174       "PREFIX for Fortran to c name mangling")
175     set(FORTRAN_C_SUFFIX "${suffix}" CACHE INTERNAL
176       "SUFFIX for Fortran to c name mangling")
177     set(FORTRAN_C_MANGLING_UPPERCASE ${isupper} CACHE INTERNAL 
178       "Was fortran to c mangling found" )
179     set(FORTRAN_C_MANGLING_EXTRA_UNDERSCORE ${extra_under} CACHE INTERNAL 
180       "If a function has a _ in the name does the compiler append an extra _" )
181     set(FORTRAN_C_MANGLING_FOUND TRUE CACHE INTERNAL 
182       "Was fortran to c mangling found" )
183     set(prefix )
184     set(suffix )
185     set(found FALSE)
186     # only try this if the compiler is F90 compatible
187     if(CMAKE_Fortran_COMPILER_SUPPORTS_F90)
188       discover_fortran_module_mangling(prefix suffix found)
189     endif(CMAKE_Fortran_COMPILER_SUPPORTS_F90)
190     if(found)
191       message(STATUS "found Fortran module linkage")
192     else(found)
193       message(STATUS "Failed to find Fortran module linkage")
194     endif(found)
195     set(FORTRAN_C_MODULE_PREFIX "${prefix}" CACHE INTERNAL
196       "PREFIX for Fortran to c name mangling")
197     set(FORTRAN_C_MODULE_SUFFIX "${suffix}" CACHE INTERNAL
198       "SUFFIX for Fortran to c name mangling")
199     set(FORTRAN_C_MODULE_MANGLING_FOUND ${found} CACHE INTERNAL
200       "Was for Fortran to c name mangling found for modules")
201   endif(NOT FORTRAN_C_MANGLING_FOUND)
202   foreach(f ${${FUNCTIONS}})
203     if(FORTRAN_C_MANGLING_UPPERCASE)
204       string(TOUPPER "${f}" fcase)
205     else()
206       string(TOLOWER "${f}" fcase)
207     endif()
208     if("${f}" MATCHES ":")
209       string(REGEX REPLACE "(.*):(.*)" "\\1" module "${f}")
210       string(REGEX REPLACE "(.*):(.*)" "\\2" function "${f}")
211       string(REGEX REPLACE "(.*):(.*)" "\\1" module_case "${fcase}")
212       string(REGEX REPLACE "(.*):(.*)" "\\2" function_case "${fcase}")
213       set(HEADER_CONTENT "${HEADER_CONTENT}
214 #define ${NAMESPACE}${module}_${function} ${FORTRAN_C_MODULE_PREFIX}${module_case}${FORTRAN_C_MODULE_SUFFIX}${function_case}
216     else("${f}" MATCHES ":")
217       set(function "${FORTRAN_C_PREFIX}${fcase}${FORTRAN_C_SUFFIX}")
218       if("${f}" MATCHES "_" AND FORTRAN_C_MANGLING_EXTRA_UNDERSCORE)
219         set(function "${function}_")
220       endif("${f}" MATCHES "_" AND FORTRAN_C_MANGLING_EXTRA_UNDERSCORE)
221       set(HEADER_CONTENT "${HEADER_CONTENT}
222 #define ${NAMESPACE}${f} ${function}
224     endif("${f}" MATCHES ":")
225   endforeach(f)
226   configure_file(
227     "${CMAKE_ROOT}/Modules/FortranCInterface.h.in"
228     ${HEADER} @ONLY)
229   message(STATUS "created ${HEADER}")
230 endfunction()