Introduce "generator expressions" to add_test()
[cmake.git] / Modules / FortranCInterface.cmake
blob580f84e17d4b75657a1f265aa1d456b320e53dee
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,
19 # respectively:
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>".
38 # Example usage:
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_().
44 # Example usage:
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)
75   return()
76 endif()
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
95     )
96   message(STATUS "Detecting Fortran/C Interface")
97   set(_result)
99   # Build a sample project which reports symbols.
100   try_compile(FortranCInterface_COMPILED
101     ${FortranCInterface_BINARY_DIR}
102     ${FortranCInterface_SOURCE_DIR}
103     FortranCInterface
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
113       NO_DEFAULT_PATH
114       )
115     set(FortranCInterface_EXE ${FortranCInterface_EXE})
116     unset(FortranCInterface_EXE CACHE)
117   else()
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")
123   endif()
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})
134       endif()
135     endforeach()
136   elseif(NOT _result)
137     set(_result "Failed to load sample executable")
138   endif()
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})
151     foreach(form "" "_")
152       # Look for global symbols.
153       string(REGEX REPLACE "${_global_${form}regex}"
154                            "\\1;\\2;\\3" pieces "${symbol}")
155       list(LENGTH pieces len)
156       if(len EQUAL 3)
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}}")
162       endif()
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)
168       if(len EQUAL 5)
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}}")
176       endif()
177     endforeach()
178   endforeach()
180   # Construct mangling macro definitions.
181   set(_name_LOWER "name")
182   set(_name_UPPER "NAME")
183   foreach(form "" "_")
184     if(FortranCInterface_GLOBAL_${form}SYMBOL)
185       if(FortranCInterface_GLOBAL_${form}PREFIX)
186         set(_prefix "${FortranCInterface_GLOBAL_${form}PREFIX}##")
187       else()
188         set(_prefix "")
189       endif()
190       if(FortranCInterface_GLOBAL_${form}SUFFIX)
191         set(_suffix "##${FortranCInterface_GLOBAL_${form}SUFFIX}")
192       else()
193         set(_suffix "")
194       endif()
195       set(_name "${_name_${FortranCInterface_GLOBAL_${form}CASE}}")
196       set(FortranCInterface_GLOBAL${form}_MACRO
197         "(name,NAME) ${_prefix}${_name}${_suffix}")
198     endif()
199     if(FortranCInterface_MODULE_${form}SYMBOL)
200       if(FortranCInterface_MODULE_${form}PREFIX)
201         set(_prefix "${FortranCInterface_MODULE_${form}PREFIX}##")
202       else()
203         set(_prefix "")
204       endif()
205       if(FortranCInterface_MODULE_${form}SUFFIX)
206         set(_suffix "##${FortranCInterface_MODULE_${form}SUFFIX}")
207       else()
208         set(_suffix "")
209       endif()
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}")
214     endif()
215   endforeach()
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)
222     else()
223       set(FortranCInterface_${scope}_FOUND 0)
224     endif()
225   endforeach()
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")
238     endif()
239   elseif(NOT _result)
240     set(_result "Failed to recognize symbols")
241   endif()
242   message(STATUS "Detecting Fortran/C Interface - ${_result}")
243 endif()
245 # Load the detection results.
246 include(${FortranCInterface_BINARY_DIR}/Output.cmake)
248 #-----------------------------------------------------------------------------
249 function(FortranCInterface_HEADER file)
250   # Parse arguments.
251   if(IS_ABSOLUTE "${file}")
252     set(FILE "${file}")
253   else()
254     set(FILE "${CMAKE_CURRENT_BINARY_DIR}/${file}")
255   endif()
256   set(MACRO_NAMESPACE "FortranCInterface_")
257   set(SYMBOL_NAMESPACE)
258   set(SYMBOLS)
259   set(doing)
260   foreach(arg ${ARGN})
261     if("x${arg}" MATCHES "^x(SYMBOLS|SYMBOL_NAMESPACE|MACRO_NAMESPACE)$")
262       set(doing "${arg}")
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}")
267       set(doing)
268     else()
269       message(AUTHOR_WARNING "Unknown argument: \"${arg}\"")
270     endif()
271   endforeach()
273   # Generate macro definitions.
274   set(HEADER_CONTENT)
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}
282 ${_desc_${macro}}
283 #define ${MACRO_NAMESPACE}${macro}${FortranCInterface_${macro}_MACRO}
285     endif()
286   endforeach()
288   # Generate symbol mangling definitions.
289   if(SYMBOLS)
290     set(HEADER_CONTENT "${HEADER_CONTENT}
291 /*--------------------------------------------------------------------------*/
292 /* Mangle some symbols automatically.                                       */
294   endif()
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 "_")
306         set(form "_")
307       else()
308         set(form "")
309       endif()
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")
312       else()
313         message(AUTHOR_WARNING "No FortranCInterface mangling known for ${f}")
314       endif()
315     else()
316       # Global symbol name.
317       if("${f}" MATCHES "_")
318         set(form "_")
319       else()
320         set(form "")
321       endif()
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")
326       else()
327         message(AUTHOR_WARNING "No FortranCInterface mangling known for ${f}")
328       endif()
329     endif()
330   endforeach(f)
332   # Store the content.
333   configure_file(${FortranCInterface_SOURCE_DIR}/Macro.h.in ${FILE} @ONLY)
334 endfunction()