1# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2# file Copyright.txt or https://cmake.org/licensing for details.
3
4configure_file(${FortranCInterface_SOURCE_DIR}/Input.cmake.in
5               ${FortranCInterface_BINARY_DIR}/Input.cmake @ONLY)
6
7# Detect the Fortran/C interface on the first run or when the
8# configuration changes.
9if(NOT EXISTS ${FortranCInterface_BINARY_DIR}/Output.cmake
10    OR NOT EXISTS ${FortranCInterface_BINARY_DIR}/Input.cmake
11    OR NOT ${FortranCInterface_BINARY_DIR}/Output.cmake
12      IS_NEWER_THAN ${FortranCInterface_BINARY_DIR}/Input.cmake
13    OR NOT ${FortranCInterface_SOURCE_DIR}/Output.cmake
14      IS_NEWER_THAN ${FortranCInterface_SOURCE_DIR}/Output.cmake.in
15    OR NOT ${FortranCInterface_BINARY_DIR}/Output.cmake
16      IS_NEWER_THAN ${FortranCInterface_SOURCE_DIR}/CMakeLists.txt
17    OR NOT ${FortranCInterface_BINARY_DIR}/Output.cmake
18      IS_NEWER_THAN ${CMAKE_CURRENT_LIST_FILE}
19    )
20  message(CHECK_START "Detecting Fortran/C Interface")
21else()
22  return()
23endif()
24
25# Invalidate verification results.
26unset(FortranCInterface_VERIFIED_C CACHE)
27unset(FortranCInterface_VERIFIED_CXX CACHE)
28
29set(_result)
30
31cmake_policy(GET CMP0056 _FortranCInterface_CMP0056)
32if(_FortranCInterface_CMP0056 STREQUAL "NEW")
33  set(_FortranCInterface_EXE_LINKER_FLAGS "-DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_EXE_LINKER_FLAGS}")
34else()
35  set(_FortranCInterface_EXE_LINKER_FLAGS "")
36endif()
37unset(_FortranCInterface_CMP0056)
38
39# Build a sample project which reports symbols.
40set(CMAKE_TRY_COMPILE_CONFIGURATION Release)
41try_compile(FortranCInterface_COMPILED
42  ${FortranCInterface_BINARY_DIR}
43  ${FortranCInterface_SOURCE_DIR}
44  FortranCInterface # project name
45  FortranCInterface # target name
46  CMAKE_FLAGS
47    "-DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS}"
48    "-DCMAKE_Fortran_FLAGS:STRING=${CMAKE_Fortran_FLAGS}"
49    "-DCMAKE_C_FLAGS_RELEASE:STRING=${CMAKE_C_FLAGS_RELEASE}"
50    "-DCMAKE_Fortran_FLAGS_RELEASE:STRING=${CMAKE_Fortran_FLAGS_RELEASE}"
51    ${_FortranCInterface_EXE_LINKER_FLAGS}
52  OUTPUT_VARIABLE FortranCInterface_OUTPUT)
53set(FortranCInterface_COMPILED ${FortranCInterface_COMPILED})
54unset(FortranCInterface_COMPILED CACHE)
55unset(_FortranCInterface_EXE_LINKER_FLAGS)
56
57# Locate the sample project executable.
58set(FortranCInterface_EXE)
59if(FortranCInterface_COMPILED)
60  include(${FortranCInterface_BINARY_DIR}/exe-Release.cmake OPTIONAL)
61else()
62  set(_result "Failed to compile")
63  file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
64    "Fortran/C interface test project failed with the following output:\n"
65    "${FortranCInterface_OUTPUT}\n")
66endif()
67
68# Load symbols from INFO:symbol[] strings in the executable.
69set(FortranCInterface_SYMBOLS)
70if(FortranCInterface_EXE)
71  file(STRINGS "${FortranCInterface_EXE}" _info_strings
72    LIMIT_COUNT 8 REGEX "INFO:[A-Za-z0-9_]+\\[[^]]*\\]")
73  foreach(info ${_info_strings})
74    if("${info}" MATCHES "INFO:symbol\\[([^]]*)\\]")
75      list(APPEND FortranCInterface_SYMBOLS ${CMAKE_MATCH_1})
76    endif()
77  endforeach()
78elseif(NOT _result)
79  set(_result "Failed to load sample executable")
80endif()
81
82set(_case_mysub "LOWER")
83set(_case_my_sub "LOWER")
84set(_case_MYSUB "UPPER")
85set(_case_MY_SUB "UPPER")
86set(_global_regex  "^(_*)(mysub|MYSUB)([_$]*)$")
87set(_global__regex "^(_*)(my_sub|MY_SUB)([_$]*)$")
88set(_module_regex  "^(_*)(mymodule|MYMODULE)([A-Za-z_$]*)(mysub|MYSUB)([_$]*)$")
89set(_module__regex "^(_*)(my_module|MY_MODULE)([A-Za-z_$]*)(my_sub|MY_SUB)([_$]*)$")
90
91# Parse the symbol names.
92foreach(symbol ${FortranCInterface_SYMBOLS})
93  foreach(form "" "_")
94    # Look for global symbols.
95    string(REGEX REPLACE "${_global_${form}regex}"
96                         "\\1;\\2;\\3" pieces "${symbol}")
97    list(LENGTH pieces len)
98    if(len EQUAL 3)
99      set(FortranCInterface_GLOBAL_${form}SYMBOL "${symbol}")
100      list(GET pieces 0 FortranCInterface_GLOBAL_${form}PREFIX)
101      list(GET pieces 1 name)
102      list(GET pieces 2 FortranCInterface_GLOBAL_${form}SUFFIX)
103      set(FortranCInterface_GLOBAL_${form}CASE "${_case_${name}}")
104    endif()
105
106    # Look for module symbols.
107    string(REGEX REPLACE "${_module_${form}regex}"
108                         "\\1;\\2;\\3;\\4;\\5" pieces "${symbol}")
109    list(LENGTH pieces len)
110    if(len EQUAL 5)
111      set(FortranCInterface_MODULE_${form}SYMBOL "${symbol}")
112      list(GET pieces 0 FortranCInterface_MODULE_${form}PREFIX)
113      list(GET pieces 1 module)
114      list(GET pieces 2 FortranCInterface_MODULE_${form}MIDDLE)
115      list(GET pieces 3 name)
116      list(GET pieces 4 FortranCInterface_MODULE_${form}SUFFIX)
117      set(FortranCInterface_MODULE_${form}CASE "${_case_${name}}")
118    endif()
119  endforeach()
120endforeach()
121
122# Construct mangling macro definitions.
123set(_name_LOWER "name")
124set(_name_UPPER "NAME")
125foreach(form "" "_")
126  if(FortranCInterface_GLOBAL_${form}SYMBOL)
127    if(FortranCInterface_GLOBAL_${form}PREFIX)
128      set(_prefix "${FortranCInterface_GLOBAL_${form}PREFIX}##")
129    else()
130      set(_prefix "")
131    endif()
132    if(FortranCInterface_GLOBAL_${form}SUFFIX)
133      set(_suffix "##${FortranCInterface_GLOBAL_${form}SUFFIX}")
134    else()
135      set(_suffix "")
136    endif()
137    set(_name "${_name_${FortranCInterface_GLOBAL_${form}CASE}}")
138    set(FortranCInterface_GLOBAL${form}_MACRO
139      "(name,NAME) ${_prefix}${_name}${_suffix}")
140  endif()
141  if(FortranCInterface_MODULE_${form}SYMBOL)
142    if(FortranCInterface_MODULE_${form}PREFIX)
143      set(_prefix "${FortranCInterface_MODULE_${form}PREFIX}##")
144    else()
145      set(_prefix "")
146    endif()
147    if(FortranCInterface_MODULE_${form}SUFFIX)
148      set(_suffix "##${FortranCInterface_MODULE_${form}SUFFIX}")
149    else()
150      set(_suffix "")
151    endif()
152    set(_name "${_name_${FortranCInterface_MODULE_${form}CASE}}")
153    set(_middle "##${FortranCInterface_MODULE_${form}MIDDLE}##")
154    set(FortranCInterface_MODULE${form}_MACRO
155      "(mod_name,name, mod_NAME,NAME) ${_prefix}mod_${_name}${_middle}${_name}${_suffix}")
156  endif()
157endforeach()
158
159# Summarize what is available.
160foreach(scope GLOBAL MODULE)
161  if(FortranCInterface_${scope}_SYMBOL AND
162      FortranCInterface_${scope}__SYMBOL)
163    set(FortranCInterface_${scope}_FOUND 1)
164  else()
165    set(FortranCInterface_${scope}_FOUND 0)
166  endif()
167endforeach()
168
169# Record the detection results.
170configure_file(${FortranCInterface_SOURCE_DIR}/Output.cmake.in
171               ${FortranCInterface_BINARY_DIR}/Output.cmake @ONLY)
172file(APPEND ${FortranCInterface_BINARY_DIR}/Output.cmake "\n")
173
174# Report the results.
175if(FortranCInterface_GLOBAL_FOUND)
176  if(FortranCInterface_MODULE_FOUND)
177    set(_result "Found GLOBAL and MODULE mangling")
178  else()
179    set(_result "Found GLOBAL but not MODULE mangling")
180  endif()
181  set(_result_type CHECK_PASS)
182elseif(NOT _result)
183  set(_result "Failed to recognize symbols")
184  set(_result_type CHECK_FAIL)
185endif()
186message(${_result_type} "${_result}")
187