1 # - Fortran/C Interface Detection
2 # This module automatically detects the API by which C and Fortran
3 # languages interact. Variables indicate if the mangling is found:
4 # FortranCInterface_GLOBAL_FOUND = Global subroutines and functions
5 # FortranCInterface_MODULE_FOUND = Module subroutines and functions
6 # (declared by "MODULE PROCEDURE")
7 # A function is provided to generate a C header file containing macros
8 # to mangle symbol names:
9 # FortranCInterface_HEADER(<file>
10 # [MACRO_NAMESPACE <macro-ns>]
11 # [SYMBOL_NAMESPACE <ns>]
12 # [SYMBOLS [<module>:]<function> ...])
13 # It generates in <file> definitions of the following macros:
14 # #define FortranCInterface_GLOBAL (name,NAME) ...
15 # #define FortranCInterface_GLOBAL_(name,NAME) ...
16 # #define FortranCInterface_MODULE (mod,name, MOD,NAME) ...
17 # #define FortranCInterface_MODULE_(mod,name, MOD,NAME) ...
18 # These macros mangle four categories of Fortran symbols,
20 # - Global symbols without '_': call mysub()
21 # - Global symbols with '_' : call my_sub()
22 # - Module symbols without '_': use mymod; call mysub()
23 # - Module symbols with '_' : use mymod; call my_sub()
24 # If mangling for a category is not known, its macro is left undefined.
25 # All macros require raw names in both lower case and upper case.
26 # The MACRO_NAMESPACE option replaces the default "FortranCInterface_"
27 # prefix with a given namespace "<macro-ns>".
29 # The SYMBOLS option lists symbols to mangle automatically with C
30 # preprocessor definitions:
31 # <function> ==> #define <ns><function> ...
32 # <module>:<function> ==> #define <ns><module>_<function> ...
33 # If the mangling for some symbol is not known then no preprocessor
34 # definition is created, and a warning is displayed.
35 # The SYMBOL_NAMESPACE option prefixes all preprocessor definitions
36 # generated by the SYMBOLS option with a given namespace "<ns>".
39 # include(FortranCInterface)
40 # FortranCInterface_HEADER(FC.h MACRO_NAMESPACE "FC_")
41 # This creates a "FC.h" header that defines mangling macros
42 # FC_GLOBAL(), FC_GLOBAL_(), FC_MODULE(), and FC_MODULE_().
45 # include(FortranCInterface)
46 # FortranCInterface_HEADER(FCMangle.h
47 # MACRO_NAMESPACE "FC_"
48 # SYMBOL_NAMESPACE "FC_"
49 # SYMBOLS mysub mymod:my_sub)
50 # This creates a "FC.h" header that defines the same FC_*() mangling
51 # macros as the previous example plus preprocessor symbols FC_mysub
52 # and FC_mymod_my_sub.
54 # FortranCInterface is aware of possible GLOBAL and MODULE manglings
55 # for many Fortran compilers, but it also provides an interface to
56 # specify new possible manglings. Set the variables
57 # FortranCInterface_GLOBAL_SYMBOLS
58 # FortranCInterface_MODULE_SYMBOLS
59 # before including FortranCInterface to specify manglings of the
60 # symbols "MySub", "My_Sub", "MyModule:MySub", and "My_Module:My_Sub".
61 # For example, the code:
62 # set(FortranCInterface_GLOBAL_SYMBOLS mysub_ my_sub__ MYSUB_)
63 # # ^^^^^ ^^^^^^ ^^^^^
64 # set(FortranCInterface_MODULE_SYMBOLS
65 # __mymodule_MOD_mysub __my_module_MOD_my_sub)
66 # # ^^^^^^^^ ^^^^^ ^^^^^^^^^ ^^^^^^
67 # include(FortranCInterface)
68 # tells FortranCInterface to try given GLOBAL and MODULE manglings.
69 # (The carets point at raw symbol names for clarity in this example
70 # but are not needed.)
72 #-----------------------------------------------------------------------------
73 # Execute at most once in a project.
74 if(FortranCInterface_SOURCE_DIR)
78 #-----------------------------------------------------------------------------
79 # Set up an interface detection project.
80 set(FortranCInterface_SOURCE_DIR ${CMAKE_ROOT}/Modules/FortranCInterface)
81 set(FortranCInterface_BINARY_DIR ${CMAKE_BINARY_DIR}/CMakeFiles/FortranCInterface)
82 configure_file(${FortranCInterface_SOURCE_DIR}/Input.cmake.in
83 ${FortranCInterface_BINARY_DIR}/Input.cmake @ONLY)
85 # Detect the Fortran/C interface on the first run or when the
86 # configuration changes.
87 if(${FortranCInterface_BINARY_DIR}/Input.cmake
88 IS_NEWER_THAN ${FortranCInterface_BINARY_DIR}/Output.cmake
89 OR ${FortranCInterface_SOURCE_DIR}/Output.cmake.in
90 IS_NEWER_THAN ${FortranCInterface_BINARY_DIR}/Output.cmake
91 OR ${FortranCInterface_SOURCE_DIR}/CMakeLists.txt
92 IS_NEWER_THAN ${FortranCInterface_BINARY_DIR}/Output.cmake
93 OR ${CMAKE_CURRENT_LIST_FILE}
94 IS_NEWER_THAN ${FortranCInterface_BINARY_DIR}/Output.cmake
96 message(STATUS "Detecting Fortran/C Interface")
99 # Build a sample project which reports symbols.
100 try_compile(FortranCInterface_COMPILED
101 ${FortranCInterface_BINARY_DIR}
102 ${FortranCInterface_SOURCE_DIR}
104 OUTPUT_VARIABLE FortranCInterface_OUTPUT)
105 set(FortranCInterface_COMPILED ${FortranCInterface_COMPILED})
106 unset(FortranCInterface_COMPILED CACHE)
108 # Locate the sample project executable.
109 if(FortranCInterface_COMPILED)
110 find_program(FortranCInterface_EXE
111 NAMES FortranCInterface
112 PATHS ${FortranCInterface_BINARY_DIR} ${FortranCInterface_BINARY_DIR}/Debug
115 set(FortranCInterface_EXE ${FortranCInterface_EXE})
116 unset(FortranCInterface_EXE CACHE)
118 set(_result "Failed to compile")
119 set(FortranCInterface_EXE)
120 file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
121 "Fortran/C interface test project failed with the following output:\n"
122 "${FortranCInterface_OUTPUT}\n")
125 # Load symbols from INFO:symbol[] strings in the executable.
126 set(FortranCInterface_SYMBOLS)
127 if(FortranCInterface_EXE)
128 file(STRINGS "${FortranCInterface_EXE}" _info_strings
129 LIMIT_COUNT 8 REGEX "INFO:[^[]*\\[")
130 foreach(info ${_info_strings})
131 if("${info}" MATCHES ".*INFO:symbol\\[([^]]*)\\].*")
132 string(REGEX REPLACE ".*INFO:symbol\\[([^]]*)\\].*" "\\1" symbol "${info}")
133 list(APPEND FortranCInterface_SYMBOLS ${symbol})
137 set(_result "Failed to load sample executable")
140 set(_case_mysub "LOWER")
141 set(_case_my_sub "LOWER")
142 set(_case_MYSUB "UPPER")
143 set(_case_MY_SUB "UPPER")
144 set(_global_regex "^(_*)(mysub|MYSUB)([_$]*)$")
145 set(_global__regex "^(_*)(my_sub|MY_SUB)([_$]*)$")
146 set(_module_regex "^(_*)(mymodule|MYMODULE)([A-Za-z_$]*)(mysub|MYSUB)([_$]*)$")
147 set(_module__regex "^(_*)(my_module|MY_MODULE)([A-Za-z_$]*)(my_sub|MY_SUB)([_$]*)$")
149 # Parse the symbol names.
150 foreach(symbol ${FortranCInterface_SYMBOLS})
152 # Look for global symbols.
153 string(REGEX REPLACE "${_global_${form}regex}"
154 "\\1;\\2;\\3" pieces "${symbol}")
155 list(LENGTH pieces len)
157 set(FortranCInterface_GLOBAL_${form}SYMBOL "${symbol}")
158 list(GET pieces 0 FortranCInterface_GLOBAL_${form}PREFIX)
159 list(GET pieces 1 name)
160 list(GET pieces 2 FortranCInterface_GLOBAL_${form}SUFFIX)
161 set(FortranCInterface_GLOBAL_${form}CASE "${_case_${name}}")
164 # Look for module symbols.
165 string(REGEX REPLACE "${_module_${form}regex}"
166 "\\1;\\2;\\3;\\4;\\5" pieces "${symbol}")
167 list(LENGTH pieces len)
169 set(FortranCInterface_MODULE_${form}SYMBOL "${symbol}")
170 list(GET pieces 0 FortranCInterface_MODULE_${form}PREFIX)
171 list(GET pieces 1 module)
172 list(GET pieces 2 FortranCInterface_MODULE_${form}MIDDLE)
173 list(GET pieces 3 name)
174 list(GET pieces 4 FortranCInterface_MODULE_${form}SUFFIX)
175 set(FortranCInterface_MODULE_${form}CASE "${_case_${name}}")
180 # Construct mangling macro definitions.
181 set(_name_LOWER "name")
182 set(_name_UPPER "NAME")
184 if(FortranCInterface_GLOBAL_${form}SYMBOL)
185 if(FortranCInterface_GLOBAL_${form}PREFIX)
186 set(_prefix "${FortranCInterface_GLOBAL_${form}PREFIX}##")
190 if(FortranCInterface_GLOBAL_${form}SUFFIX)
191 set(_suffix "##${FortranCInterface_GLOBAL_${form}SUFFIX}")
195 set(_name "${_name_${FortranCInterface_GLOBAL_${form}CASE}}")
196 set(FortranCInterface_GLOBAL${form}_MACRO
197 "(name,NAME) ${_prefix}${_name}${_suffix}")
199 if(FortranCInterface_MODULE_${form}SYMBOL)
200 if(FortranCInterface_MODULE_${form}PREFIX)
201 set(_prefix "${FortranCInterface_MODULE_${form}PREFIX}##")
205 if(FortranCInterface_MODULE_${form}SUFFIX)
206 set(_suffix "##${FortranCInterface_MODULE_${form}SUFFIX}")
210 set(_name "${_name_${FortranCInterface_MODULE_${form}CASE}}")
211 set(_middle "##${FortranCInterface_MODULE_${form}MIDDLE}##")
212 set(FortranCInterface_MODULE${form}_MACRO
213 "(mod_name,name, mod_NAME,NAME) ${_prefix}mod_${_name}${_middle}${_name}${_suffix}")
217 # Summarize what is available.
218 foreach(scope GLOBAL MODULE)
219 if(FortranCInterface_${scope}_SYMBOL AND
220 FortranCInterface_${scope}__SYMBOL)
221 set(FortranCInterface_${scope}_FOUND 1)
223 set(FortranCInterface_${scope}_FOUND 0)
227 # Record the detection results.
228 configure_file(${FortranCInterface_SOURCE_DIR}/Output.cmake.in
229 ${FortranCInterface_BINARY_DIR}/Output.cmake @ONLY)
230 file(APPEND ${FortranCInterface_BINARY_DIR}/Output.cmake "\n")
232 # Report the results.
233 if(FortranCInterface_GLOBAL_FOUND)
234 if(FortranCInterface_MODULE_FOUND)
235 set(_result "Found GLOBAL and MODULE mangling")
236 else(FortranCInterface_MODULE_FOUND)
237 set(_result "Found GLOBAL but not MODULE mangling")
240 set(_result "Failed to recognize symbols")
242 message(STATUS "Detecting Fortran/C Interface - ${_result}")
245 # Load the detection results.
246 include(${FortranCInterface_BINARY_DIR}/Output.cmake)
248 #-----------------------------------------------------------------------------
249 function(FortranCInterface_HEADER file)
251 if(IS_ABSOLUTE "${file}")
254 set(FILE "${CMAKE_CURRENT_BINARY_DIR}/${file}")
256 set(MACRO_NAMESPACE "FortranCInterface_")
257 set(SYMBOL_NAMESPACE)
261 if("x${arg}" MATCHES "^x(SYMBOLS|SYMBOL_NAMESPACE|MACRO_NAMESPACE)$")
263 elseif("x${doing}" MATCHES "^x(SYMBOLS)$")
264 list(APPEND "${doing}" "${arg}")
265 elseif("x${doing}" MATCHES "^x(SYMBOL_NAMESPACE|MACRO_NAMESPACE)$")
266 set("${doing}" "${arg}")
269 message(AUTHOR_WARNING "Unknown argument: \"${arg}\"")
273 # Generate macro definitions.
275 set(_desc_GLOBAL "/* Mangling for Fortran global symbols without underscores. */")
276 set(_desc_GLOBAL_ "/* Mangling for Fortran global symbols with underscores. */")
277 set(_desc_MODULE "/* Mangling for Fortran module symbols without underscores. */")
278 set(_desc_MODULE_ "/* Mangling for Fortran module symbols with underscores. */")
279 foreach(macro GLOBAL GLOBAL_ MODULE MODULE_)
280 if(FortranCInterface_${macro}_MACRO)
281 set(HEADER_CONTENT "${HEADER_CONTENT}
283 #define ${MACRO_NAMESPACE}${macro}${FortranCInterface_${macro}_MACRO}
288 # Generate symbol mangling definitions.
290 set(HEADER_CONTENT "${HEADER_CONTENT}
291 /*--------------------------------------------------------------------------*/
292 /* Mangle some symbols automatically. */
295 foreach(f ${SYMBOLS})
296 if("${f}" MATCHES ":")
297 # Module symbol name. Parse "<module>:<function>" syntax.
298 string(REPLACE ":" ";" pieces "${f}")
299 list(GET pieces 0 module)
300 list(GET pieces 1 function)
301 string(TOUPPER "${module}" m_upper)
302 string(TOLOWER "${module}" m_lower)
303 string(TOUPPER "${function}" f_upper)
304 string(TOLOWER "${function}" f_lower)
305 if("${function}" MATCHES "_")
310 if(FortranCInterface_MODULE${form}_MACRO)
311 set(HEADER_CONTENT "${HEADER_CONTENT}#define ${SYMBOL_NAMESPACE}${module}_${function} ${MACRO_NAMESPACE}MODULE${form}(${m_lower},${f_lower}, ${m_upper},${f_upper})\n")
313 message(AUTHOR_WARNING "No FortranCInterface mangling known for ${f}")
316 # Global symbol name.
317 if("${f}" MATCHES "_")
322 string(TOUPPER "${f}" f_upper)
323 string(TOLOWER "${f}" f_lower)
324 if(FortranCInterface_GLOBAL${form}_MACRO)
325 set(HEADER_CONTENT "${HEADER_CONTENT}#define ${SYMBOL_NAMESPACE}${f} ${MACRO_NAMESPACE}GLOBAL${form}(${f_lower}, ${f_upper})\n")
327 message(AUTHOR_WARNING "No FortranCInterface mangling known for ${f}")
333 configure_file(${FortranCInterface_SOURCE_DIR}/Macro.h.in ${FILE} @ONLY)