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#[=======================================================================[.rst: 5FortranCInterface 6----------------- 7 8Fortran/C Interface Detection 9 10This module automatically detects the API by which C and Fortran 11languages interact. 12 13Module Variables 14^^^^^^^^^^^^^^^^ 15 16Variables that indicate if the mangling is found: 17 18``FortranCInterface_GLOBAL_FOUND`` 19 Global subroutines and functions. 20 21``FortranCInterface_MODULE_FOUND`` 22 Module subroutines and functions (declared by "MODULE PROCEDURE"). 23 24This module also provides the following variables to specify 25the detected mangling, though a typical use case does not need 26to reference them and can use the `Module Functions`_ below. 27 28``FortranCInterface_GLOBAL_PREFIX`` 29 Prefix for a global symbol without an underscore. 30 31``FortranCInterface_GLOBAL_SUFFIX`` 32 Suffix for a global symbol without an underscore. 33 34``FortranCInterface_GLOBAL_CASE`` 35 The case for a global symbol without an underscore, 36 either ``UPPER`` or ``LOWER``. 37 38``FortranCInterface_GLOBAL__PREFIX`` 39 Prefix for a global symbol with an underscore. 40 41``FortranCInterface_GLOBAL__SUFFIX`` 42 Suffix for a global symbol with an underscore. 43 44``FortranCInterface_GLOBAL__CASE`` 45 The case for a global symbol with an underscore, 46 either ``UPPER`` or ``LOWER``. 47 48``FortranCInterface_MODULE_PREFIX`` 49 Prefix for a module symbol without an underscore. 50 51``FortranCInterface_MODULE_MIDDLE`` 52 Middle of a module symbol without an underscore that appears 53 between the name of the module and the name of the symbol. 54 55``FortranCInterface_MODULE_SUFFIX`` 56 Suffix for a module symbol without an underscore. 57 58``FortranCInterface_MODULE_CASE`` 59 The case for a module symbol without an underscore, 60 either ``UPPER`` or ``LOWER``. 61 62``FortranCInterface_MODULE__PREFIX`` 63 Prefix for a module symbol with an underscore. 64 65``FortranCInterface_MODULE__MIDDLE`` 66 Middle of a module symbol with an underscore that appears 67 between the name of the module and the name of the symbol. 68 69``FortranCInterface_MODULE__SUFFIX`` 70 Suffix for a module symbol with an underscore. 71 72``FortranCInterface_MODULE__CASE`` 73 The case for a module symbol with an underscore, 74 either ``UPPER`` or ``LOWER``. 75 76Module Functions 77^^^^^^^^^^^^^^^^ 78 79.. command:: FortranCInterface_HEADER 80 81 The ``FortranCInterface_HEADER`` function is provided to generate a 82 C header file containing macros to mangle symbol names:: 83 84 FortranCInterface_HEADER(<file> 85 [MACRO_NAMESPACE <macro-ns>] 86 [SYMBOL_NAMESPACE <ns>] 87 [SYMBOLS [<module>:]<function> ...]) 88 89 It generates in ``<file>`` definitions of the following macros:: 90 91 #define FortranCInterface_GLOBAL (name,NAME) ... 92 #define FortranCInterface_GLOBAL_(name,NAME) ... 93 #define FortranCInterface_MODULE (mod,name, MOD,NAME) ... 94 #define FortranCInterface_MODULE_(mod,name, MOD,NAME) ... 95 96 These macros mangle four categories of Fortran symbols, respectively: 97 98 * Global symbols without '_': ``call mysub()`` 99 * Global symbols with '_' : ``call my_sub()`` 100 * Module symbols without '_': ``use mymod; call mysub()`` 101 * Module symbols with '_' : ``use mymod; call my_sub()`` 102 103 If mangling for a category is not known, its macro is left undefined. 104 All macros require raw names in both lower case and upper case. 105 106 The options are: 107 108 ``MACRO_NAMESPACE`` 109 Replace the default ``FortranCInterface_`` prefix with a given 110 namespace ``<macro-ns>``. 111 112 ``SYMBOLS`` 113 List symbols to mangle automatically with C preprocessor definitions:: 114 115 <function> ==> #define <ns><function> ... 116 <module>:<function> ==> #define <ns><module>_<function> ... 117 118 If the mangling for some symbol is not known then no preprocessor 119 definition is created, and a warning is displayed. 120 121 ``SYMBOL_NAMESPACE`` 122 Prefix all preprocessor definitions generated by the ``SYMBOLS`` 123 option with a given namespace ``<ns>``. 124 125.. command:: FortranCInterface_VERIFY 126 127 The ``FortranCInterface_VERIFY`` function is provided to verify 128 that the Fortran and C/C++ compilers work together:: 129 130 FortranCInterface_VERIFY([CXX] [QUIET]) 131 132 It tests whether a simple test executable using Fortran and C (and C++ 133 when the CXX option is given) compiles and links successfully. The 134 result is stored in the cache entry ``FortranCInterface_VERIFIED_C`` 135 (or ``FortranCInterface_VERIFIED_CXX`` if ``CXX`` is given) as a boolean. 136 If the check fails and ``QUIET`` is not given the function terminates with a 137 fatal error message describing the problem. The purpose of this check 138 is to stop a build early for incompatible compiler combinations. The 139 test is built in the ``Release`` configuration. 140 141Example Usage 142^^^^^^^^^^^^^ 143 144.. code-block:: cmake 145 146 include(FortranCInterface) 147 FortranCInterface_HEADER(FC.h MACRO_NAMESPACE "FC_") 148 149This creates a "FC.h" header that defines mangling macros ``FC_GLOBAL()``, 150``FC_GLOBAL_()``, ``FC_MODULE()``, and ``FC_MODULE_()``. 151 152.. code-block:: cmake 153 154 include(FortranCInterface) 155 FortranCInterface_HEADER(FCMangle.h 156 MACRO_NAMESPACE "FC_" 157 SYMBOL_NAMESPACE "FC_" 158 SYMBOLS mysub mymod:my_sub) 159 160This creates a "FCMangle.h" header that defines the same ``FC_*()`` 161mangling macros as the previous example plus preprocessor symbols 162``FC_mysub`` and ``FC_mymod_my_sub``. 163 164Additional Manglings 165^^^^^^^^^^^^^^^^^^^^ 166 167FortranCInterface is aware of possible ``GLOBAL`` and ``MODULE`` manglings 168for many Fortran compilers, but it also provides an interface to specify 169new possible manglings. Set the variables:: 170 171 FortranCInterface_GLOBAL_SYMBOLS 172 FortranCInterface_MODULE_SYMBOLS 173 174before including FortranCInterface to specify manglings of the symbols 175``MySub``, ``My_Sub``, ``MyModule:MySub``, and ``My_Module:My_Sub``. 176For example, the code: 177 178.. code-block:: cmake 179 180 set(FortranCInterface_GLOBAL_SYMBOLS mysub_ my_sub__ MYSUB_) 181 # ^^^^^ ^^^^^^ ^^^^^ 182 set(FortranCInterface_MODULE_SYMBOLS 183 __mymodule_MOD_mysub __my_module_MOD_my_sub) 184 # ^^^^^^^^ ^^^^^ ^^^^^^^^^ ^^^^^^ 185 include(FortranCInterface) 186 187tells FortranCInterface to try given ``GLOBAL`` and ``MODULE`` manglings. 188(The carets point at raw symbol names for clarity in this example but 189are not needed.) 190#]=======================================================================] 191 192#----------------------------------------------------------------------------- 193# Execute at most once in a project. 194if(FortranCInterface_SOURCE_DIR) 195 return() 196endif() 197 198cmake_policy(PUSH) 199cmake_policy(SET CMP0007 NEW) 200 201#----------------------------------------------------------------------------- 202# Verify that C and Fortran are available. 203foreach(lang C Fortran) 204 if(NOT CMAKE_${lang}_COMPILER_LOADED) 205 message(FATAL_ERROR 206 "FortranCInterface requires the ${lang} language to be enabled.") 207 endif() 208endforeach() 209 210#----------------------------------------------------------------------------- 211set(FortranCInterface_SOURCE_DIR ${CMAKE_ROOT}/Modules/FortranCInterface) 212 213# MinGW's make tool does not always like () in the path 214if("${CMAKE_GENERATOR}" MATCHES "MinGW" AND 215 "${FortranCInterface_SOURCE_DIR}" MATCHES "[()]") 216 file(COPY ${FortranCInterface_SOURCE_DIR}/ 217 DESTINATION ${CMAKE_BINARY_DIR}/CMakeFiles/FortranCInterfaceMinGW) 218 set(FortranCInterface_SOURCE_DIR ${CMAKE_BINARY_DIR}/CMakeFiles/FortranCInterfaceMinGW) 219endif() 220 221# Create the interface detection project if it does not exist. 222if(NOT FortranCInterface_BINARY_DIR) 223 set(FortranCInterface_BINARY_DIR ${CMAKE_BINARY_DIR}/CMakeFiles/FortranCInterface) 224 include(${FortranCInterface_SOURCE_DIR}/Detect.cmake) 225endif() 226 227# Load the detection results. 228include(${FortranCInterface_BINARY_DIR}/Output.cmake) 229 230#----------------------------------------------------------------------------- 231function(FortranCInterface_HEADER file) 232 # Parse arguments. 233 if(IS_ABSOLUTE "${file}") 234 set(FILE "${file}") 235 else() 236 set(FILE "${CMAKE_CURRENT_BINARY_DIR}/${file}") 237 endif() 238 set(MACRO_NAMESPACE "FortranCInterface_") 239 set(SYMBOL_NAMESPACE) 240 set(SYMBOLS) 241 set(doing) 242 foreach(arg ${ARGN}) 243 if("x${arg}" MATCHES "^x(SYMBOLS|SYMBOL_NAMESPACE|MACRO_NAMESPACE)$") 244 set(doing "${arg}") 245 elseif("x${doing}" MATCHES "^x(SYMBOLS)$") 246 list(APPEND "${doing}" "${arg}") 247 elseif("x${doing}" MATCHES "^x(SYMBOL_NAMESPACE|MACRO_NAMESPACE)$") 248 set("${doing}" "${arg}") 249 set(doing) 250 else() 251 message(AUTHOR_WARNING "Unknown argument: \"${arg}\"") 252 endif() 253 endforeach() 254 255 # Generate macro definitions. 256 set(HEADER_CONTENT) 257 set(_desc_GLOBAL "/* Mangling for Fortran global symbols without underscores. */") 258 set(_desc_GLOBAL_ "/* Mangling for Fortran global symbols with underscores. */") 259 set(_desc_MODULE "/* Mangling for Fortran module symbols without underscores. */") 260 set(_desc_MODULE_ "/* Mangling for Fortran module symbols with underscores. */") 261 foreach(macro GLOBAL GLOBAL_ MODULE MODULE_) 262 if(FortranCInterface_${macro}_MACRO) 263 string(APPEND HEADER_CONTENT " 264${_desc_${macro}} 265#define ${MACRO_NAMESPACE}${macro}${FortranCInterface_${macro}_MACRO} 266") 267 endif() 268 endforeach() 269 270 # Generate symbol mangling definitions. 271 if(SYMBOLS) 272 string(APPEND HEADER_CONTENT " 273/*--------------------------------------------------------------------------*/ 274/* Mangle some symbols automatically. */ 275") 276 endif() 277 foreach(f ${SYMBOLS}) 278 if("${f}" MATCHES ":") 279 # Module symbol name. Parse "<module>:<function>" syntax. 280 string(REPLACE ":" ";" pieces "${f}") 281 list(GET pieces 0 module) 282 list(GET pieces 1 function) 283 string(TOUPPER "${module}" m_upper) 284 string(TOLOWER "${module}" m_lower) 285 string(TOUPPER "${function}" f_upper) 286 string(TOLOWER "${function}" f_lower) 287 if("${function}" MATCHES "_") 288 set(form "_") 289 else() 290 set(form "") 291 endif() 292 if(FortranCInterface_MODULE${form}_MACRO) 293 string(APPEND HEADER_CONTENT "#define ${SYMBOL_NAMESPACE}${module}_${function} ${MACRO_NAMESPACE}MODULE${form}(${m_lower},${f_lower}, ${m_upper},${f_upper})\n") 294 else() 295 message(AUTHOR_WARNING "No FortranCInterface mangling known for ${f}") 296 endif() 297 else() 298 # Global symbol name. 299 if("${f}" MATCHES "_") 300 set(form "_") 301 else() 302 set(form "") 303 endif() 304 string(TOUPPER "${f}" f_upper) 305 string(TOLOWER "${f}" f_lower) 306 if(FortranCInterface_GLOBAL${form}_MACRO) 307 string(APPEND HEADER_CONTENT "#define ${SYMBOL_NAMESPACE}${f} ${MACRO_NAMESPACE}GLOBAL${form}(${f_lower}, ${f_upper})\n") 308 else() 309 message(AUTHOR_WARNING "No FortranCInterface mangling known for ${f}") 310 endif() 311 endif() 312 endforeach() 313 314 # Store the content. 315 configure_file(${FortranCInterface_SOURCE_DIR}/Macro.h.in ${FILE} @ONLY) 316endfunction() 317 318function(FortranCInterface_VERIFY) 319 # Check arguments. 320 321 set(lang C) 322 set(quiet 0) 323 set(verify_cxx 0) 324 foreach(arg ${ARGN}) 325 if("${arg}" STREQUAL "QUIET") 326 set(quiet 1) 327 elseif("${arg}" STREQUAL "CXX") 328 set(lang CXX) 329 set(verify_cxx 1) 330 else() 331 message(FATAL_ERROR 332 "FortranCInterface_VERIFY - called with unknown argument:\n ${arg}") 333 endif() 334 endforeach() 335 336 if(NOT CMAKE_${lang}_COMPILER_LOADED) 337 message(FATAL_ERROR 338 "FortranCInterface_VERIFY(${lang}) requires ${lang} to be enabled.") 339 endif() 340 341 # Build the verification project if not yet built. 342 if(NOT DEFINED FortranCInterface_VERIFIED_${lang}) 343 set(_desc "Verifying Fortran/${lang} Compiler Compatibility") 344 message(CHECK_START "${_desc}") 345 346 cmake_policy(GET CMP0056 _FortranCInterface_CMP0056) 347 if(_FortranCInterface_CMP0056 STREQUAL "NEW") 348 set(_FortranCInterface_EXE_LINKER_FLAGS "-DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_EXE_LINKER_FLAGS}") 349 else() 350 set(_FortranCInterface_EXE_LINKER_FLAGS "") 351 endif() 352 353 # Build a sample project which reports symbols. 354 set(CMAKE_TRY_COMPILE_CONFIGURATION Release) 355 try_compile(FortranCInterface_VERIFY_${lang}_COMPILED 356 ${FortranCInterface_BINARY_DIR}/Verify${lang} 357 ${FortranCInterface_SOURCE_DIR}/Verify 358 VerifyFortranC # project name 359 VerifyFortranC # target name 360 CMAKE_FLAGS -DVERIFY_CXX=${verify_cxx} 361 -DCMAKE_VERBOSE_MAKEFILE=ON 362 "-DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS}" 363 "-DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS}" 364 "-DCMAKE_Fortran_FLAGS:STRING=${CMAKE_Fortran_FLAGS}" 365 "-DCMAKE_C_FLAGS_RELEASE:STRING=${CMAKE_C_FLAGS_RELEASE}" 366 "-DCMAKE_CXX_FLAGS_RELEASE:STRING=${CMAKE_CXX_FLAGS_RELEASE}" 367 "-DCMAKE_Fortran_FLAGS_RELEASE:STRING=${CMAKE_Fortran_FLAGS_RELEASE}" 368 ${_FortranCInterface_EXE_LINKER_FLAGS} 369 OUTPUT_VARIABLE _output) 370 file(WRITE "${FortranCInterface_BINARY_DIR}/Verify${lang}/output.txt" "${_output}") 371 372 # Report results. 373 if(FortranCInterface_VERIFY_${lang}_COMPILED) 374 message(CHECK_PASS "Success") 375 file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log 376 "${_desc} passed with the following output:\n${_output}\n\n") 377 set(FortranCInterface_VERIFIED_${lang} 1 CACHE INTERNAL "Fortran/${lang} compatibility") 378 else() 379 message(CHECK_FAIL "Failed") 380 file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log 381 "${_desc} failed with the following output:\n${_output}\n\n") 382 set(FortranCInterface_VERIFIED_${lang} 0 CACHE INTERNAL "Fortran/${lang} compatibility") 383 endif() 384 unset(FortranCInterface_VERIFY_${lang}_COMPILED CACHE) 385 endif() 386 387 # Error if compilers are incompatible. 388 if(NOT FortranCInterface_VERIFIED_${lang} AND NOT quiet) 389 file(READ "${FortranCInterface_BINARY_DIR}/Verify${lang}/output.txt" _output) 390 string(REPLACE "\n" "\n " _output "${_output}") 391 message(FATAL_ERROR 392 "The Fortran compiler:\n ${CMAKE_Fortran_COMPILER}\n" 393 "and the ${lang} compiler:\n ${CMAKE_${lang}_COMPILER}\n" 394 "failed to compile a simple test project using both languages. " 395 "The output was:\n ${_output}") 396 endif() 397endfunction() 398 399# Restore including context policies. 400cmake_policy(POP) 401