Imported Upstream version 3.21.4
[platform/upstream/cmake.git] / Modules / FortranCInterface / Detect.cmake
1 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2 # file Copyright.txt or https://cmake.org/licensing for details.
3
4 configure_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.
9 if(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")
21 else()
22   return()
23 endif()
24
25 # Invalidate verification results.
26 unset(FortranCInterface_VERIFIED_C CACHE)
27 unset(FortranCInterface_VERIFIED_CXX CACHE)
28
29 set(_result)
30
31 cmake_policy(GET CMP0056 _FortranCInterface_CMP0056)
32 if(_FortranCInterface_CMP0056 STREQUAL "NEW")
33   set(_FortranCInterface_EXE_LINKER_FLAGS "-DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_EXE_LINKER_FLAGS}")
34 else()
35   set(_FortranCInterface_EXE_LINKER_FLAGS "")
36 endif()
37 unset(_FortranCInterface_CMP0056)
38
39 # Build a sample project which reports symbols.
40 set(CMAKE_TRY_COMPILE_CONFIGURATION Release)
41 try_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)
53 set(FortranCInterface_COMPILED ${FortranCInterface_COMPILED})
54 unset(FortranCInterface_COMPILED CACHE)
55 unset(_FortranCInterface_EXE_LINKER_FLAGS)
56
57 # Locate the sample project executable.
58 set(FortranCInterface_EXE)
59 if(FortranCInterface_COMPILED)
60   include(${FortranCInterface_BINARY_DIR}/exe-Release.cmake OPTIONAL)
61 else()
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")
66 endif()
67
68 # Load symbols from INFO:symbol[] strings in the executable.
69 set(FortranCInterface_SYMBOLS)
70 if(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()
78 elseif(NOT _result)
79   set(_result "Failed to load sample executable")
80 endif()
81
82 set(_case_mysub "LOWER")
83 set(_case_my_sub "LOWER")
84 set(_case_MYSUB "UPPER")
85 set(_case_MY_SUB "UPPER")
86 set(_global_regex  "^(_*)(mysub|MYSUB)([_$]*)$")
87 set(_global__regex "^(_*)(my_sub|MY_SUB)([_$]*)$")
88 set(_module_regex  "^(_*)(mymodule|MYMODULE)([A-Za-z_$]*)(mysub|MYSUB)([_$]*)$")
89 set(_module__regex "^(_*)(my_module|MY_MODULE)([A-Za-z_$]*)(my_sub|MY_SUB)([_$]*)$")
90
91 # Parse the symbol names.
92 foreach(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()
120 endforeach()
121
122 # Construct mangling macro definitions.
123 set(_name_LOWER "name")
124 set(_name_UPPER "NAME")
125 foreach(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()
157 endforeach()
158
159 # Summarize what is available.
160 foreach(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()
167 endforeach()
168
169 # Record the detection results.
170 configure_file(${FortranCInterface_SOURCE_DIR}/Output.cmake.in
171                ${FortranCInterface_BINARY_DIR}/Output.cmake @ONLY)
172 file(APPEND ${FortranCInterface_BINARY_DIR}/Output.cmake "\n")
173
174 # Report the results.
175 if(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)
182 elseif(NOT _result)
183   set(_result "Failed to recognize symbols")
184   set(_result_type CHECK_FAIL)
185 endif()
186 message(${_result_type} "${_result}")