diff options
Diffstat (limited to 'Modules/FortranCInterface')
22 files changed, 427 insertions, 0 deletions
diff --git a/Modules/FortranCInterface/CMakeLists.txt b/Modules/FortranCInterface/CMakeLists.txt new file mode 100644 index 0000000..13e4498 --- /dev/null +++ b/Modules/FortranCInterface/CMakeLists.txt @@ -0,0 +1,107 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +cmake_minimum_required(VERSION ${CMAKE_VERSION}) +project(FortranCInterface C Fortran) +include(${FortranCInterface_BINARY_DIR}/Input.cmake OPTIONAL) + +# Check if the C compiler supports '$' in identifiers. +include(CheckCSourceCompiles) +check_c_source_compiles(" +extern int dollar$(void); +int main() { return 0; } +" C_SUPPORTS_DOLLAR) + +# List manglings of global symbol names to try. +set(global_symbols + my_sub # VisualAge + my_sub_ # GNU, Intel, HP, SunPro, PGI + my_sub__ # GNU g77 + MY_SUB # Intel on Windows + mysub # VisualAge + mysub_ # GNU, Intel, HP, SunPro, PGI + MYSUB # Intel on Windows + ${FortranCInterface_GLOBAL_SYMBOLS} + ) +list(REMOVE_DUPLICATES global_symbols) + +# List manglings of module symbol names to try. +set(module_symbols + __my_module_MOD_my_sub # GNU 4.3 + __my_module_NMOD_my_sub # VisualAge + __my_module__my_sub # GNU 4.2 + __mymodule_MOD_mysub # GNU 4.3 + __mymodule_NMOD_mysub # VisualAge + __mymodule__mysub # GNU 4.2 + my_module$my_sub # HP + my_module_mp_my_sub_ # Intel + MY_MODULE_mp_MY_SUB # Intel on Windows + my_module_my_sub_ # PGI + my_module_MP_my_sub # NAG + mymodule$mysub # HP + mymodule_mp_mysub_ # Intel + MYMODULE_mp_MYSUB # Intel on Windows + mymodule_mysub_ # PGI + mymodule_MP_mysub # NAG + ${FortranCInterface_MODULE_SYMBOLS} + ) +list(REMOVE_DUPLICATES module_symbols) + +# Note that some compiler manglings cannot be invoked from C: +# SunPro uses "my_module.my_sub_" +# PathScale uses "MY_SUB.in.MY_MODULE" + +# Add module symbols only with Fortran90. +if(CMAKE_Fortran_COMPILER_SUPPORTS_F90) + set(myfort_modules mymodule.f90 my_module.f90) + set(call_mod call_mod.f90) + set_property(SOURCE main.F PROPERTY COMPILE_DEFINITIONS CALL_MOD) +else() + set(module_symbols) +endif() + +# Generate C symbol sources. +set(symbol_sources) +if(NOT CMAKE_Fortran_COMPILER_ID MATCHES "^(PathScale|Cray)$") + # Provide mymodule_ and my_module_ init symbols because: + # - PGI Fortran uses module init symbols + # but not for: + # - PathScale Fortran uses module init symbols but module symbols + # use '.in.' so we cannot provide them anyway. + # - Cray Fortran >= 7.3.2 uses module init symbols but module symbols + # use 'mysub$mymodule_' so we cannot provide them anyway. + list(APPEND symbol_sources mymodule_.c my_module_.c MY_MODULE.c MYMODULE.c) +endif() +foreach(symbol IN LISTS global_symbols module_symbols) + # Skip symbols with '$' if C cannot handle them. + if(C_SUPPORTS_DOLLAR OR NOT "${symbol}" MATCHES "\\$") + if("${symbol}" MATCHES "SUB") + set(upper "-UPPER") + else() + set(upper) + endif() + string(REPLACE "$" "S" name "${symbol}") + set(source ${CMAKE_CURRENT_BINARY_DIR}/symbols/${name}${upper}.c) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/symbol.c.in ${source} @ONLY) + list(APPEND symbol_sources ${source}) + endif() +endforeach() + +# Provide symbols through Fortran. +add_library(myfort STATIC mysub.f my_sub.f ${myfort_modules}) + +# Provide symbols through C but fall back to Fortran. +add_library(symbols STATIC ${symbol_sources}) +target_link_libraries(symbols PUBLIC myfort) + +# In case the Fortran compiler produces PIC by default make sure +# the C compiler produces PIC even if it is not its default. +set_property(TARGET symbols PROPERTY POSITION_INDEPENDENT_CODE 1) + +# Require symbols through Fortran. +add_executable(FortranCInterface main.F call_sub.f ${call_mod}) +target_link_libraries(FortranCInterface PUBLIC symbols) + +file(GENERATE OUTPUT exe-$<CONFIG>.cmake CONTENT [[ +set(FortranCInterface_EXE "$<TARGET_FILE:FortranCInterface>") +]]) diff --git a/Modules/FortranCInterface/Detect.cmake b/Modules/FortranCInterface/Detect.cmake new file mode 100644 index 0000000..c75067b --- /dev/null +++ b/Modules/FortranCInterface/Detect.cmake @@ -0,0 +1,174 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +configure_file(${FortranCInterface_SOURCE_DIR}/Input.cmake.in + ${FortranCInterface_BINARY_DIR}/Input.cmake @ONLY) + +# Detect the Fortran/C interface on the first run or when the +# configuration changes. +if(${FortranCInterface_BINARY_DIR}/Input.cmake + IS_NEWER_THAN ${FortranCInterface_BINARY_DIR}/Output.cmake + OR ${FortranCInterface_SOURCE_DIR}/Output.cmake.in + IS_NEWER_THAN ${FortranCInterface_BINARY_DIR}/Output.cmake + OR ${FortranCInterface_SOURCE_DIR}/CMakeLists.txt + IS_NEWER_THAN ${FortranCInterface_BINARY_DIR}/Output.cmake + OR ${CMAKE_CURRENT_LIST_FILE} + IS_NEWER_THAN ${FortranCInterface_BINARY_DIR}/Output.cmake + ) + message(CHECK_START "Detecting Fortran/C Interface") +else() + return() +endif() + +# Invalidate verification results. +unset(FortranCInterface_VERIFIED_C CACHE) +unset(FortranCInterface_VERIFIED_CXX CACHE) + +set(_result) + +# Build a sample project which reports symbols. +set(CMAKE_TRY_COMPILE_CONFIGURATION Release) +try_compile(FortranCInterface_COMPILED + ${FortranCInterface_BINARY_DIR} + ${FortranCInterface_SOURCE_DIR} + FortranCInterface # project name + FortranCInterface # target name + CMAKE_FLAGS + "-DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS}" + "-DCMAKE_Fortran_FLAGS:STRING=${CMAKE_Fortran_FLAGS}" + "-DCMAKE_C_FLAGS_RELEASE:STRING=${CMAKE_C_FLAGS_RELEASE}" + "-DCMAKE_Fortran_FLAGS_RELEASE:STRING=${CMAKE_Fortran_FLAGS_RELEASE}" + OUTPUT_VARIABLE FortranCInterface_OUTPUT) +set(FortranCInterface_COMPILED ${FortranCInterface_COMPILED}) +unset(FortranCInterface_COMPILED CACHE) + +# Locate the sample project executable. +set(FortranCInterface_EXE) +if(FortranCInterface_COMPILED) + include(${FortranCInterface_BINARY_DIR}/exe-Release.cmake OPTIONAL) +else() + set(_result "Failed to compile") + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "Fortran/C interface test project failed with the following output:\n" + "${FortranCInterface_OUTPUT}\n") +endif() + +# Load symbols from INFO:symbol[] strings in the executable. +set(FortranCInterface_SYMBOLS) +if(FortranCInterface_EXE) + file(STRINGS "${FortranCInterface_EXE}" _info_strings + LIMIT_COUNT 8 REGEX "INFO:[A-Za-z0-9_]+\\[[^]]*\\]") + foreach(info ${_info_strings}) + if("${info}" MATCHES "INFO:symbol\\[([^]]*)\\]") + list(APPEND FortranCInterface_SYMBOLS ${CMAKE_MATCH_1}) + endif() + endforeach() +elseif(NOT _result) + set(_result "Failed to load sample executable") +endif() + +set(_case_mysub "LOWER") +set(_case_my_sub "LOWER") +set(_case_MYSUB "UPPER") +set(_case_MY_SUB "UPPER") +set(_global_regex "^(_*)(mysub|MYSUB)([_$]*)$") +set(_global__regex "^(_*)(my_sub|MY_SUB)([_$]*)$") +set(_module_regex "^(_*)(mymodule|MYMODULE)([A-Za-z_$]*)(mysub|MYSUB)([_$]*)$") +set(_module__regex "^(_*)(my_module|MY_MODULE)([A-Za-z_$]*)(my_sub|MY_SUB)([_$]*)$") + +# Parse the symbol names. +foreach(symbol ${FortranCInterface_SYMBOLS}) + foreach(form "" "_") + # Look for global symbols. + string(REGEX REPLACE "${_global_${form}regex}" + "\\1;\\2;\\3" pieces "${symbol}") + list(LENGTH pieces len) + if(len EQUAL 3) + set(FortranCInterface_GLOBAL_${form}SYMBOL "${symbol}") + list(GET pieces 0 FortranCInterface_GLOBAL_${form}PREFIX) + list(GET pieces 1 name) + list(GET pieces 2 FortranCInterface_GLOBAL_${form}SUFFIX) + set(FortranCInterface_GLOBAL_${form}CASE "${_case_${name}}") + endif() + + # Look for module symbols. + string(REGEX REPLACE "${_module_${form}regex}" + "\\1;\\2;\\3;\\4;\\5" pieces "${symbol}") + list(LENGTH pieces len) + if(len EQUAL 5) + set(FortranCInterface_MODULE_${form}SYMBOL "${symbol}") + list(GET pieces 0 FortranCInterface_MODULE_${form}PREFIX) + list(GET pieces 1 module) + list(GET pieces 2 FortranCInterface_MODULE_${form}MIDDLE) + list(GET pieces 3 name) + list(GET pieces 4 FortranCInterface_MODULE_${form}SUFFIX) + set(FortranCInterface_MODULE_${form}CASE "${_case_${name}}") + endif() + endforeach() +endforeach() + +# Construct mangling macro definitions. +set(_name_LOWER "name") +set(_name_UPPER "NAME") +foreach(form "" "_") + if(FortranCInterface_GLOBAL_${form}SYMBOL) + if(FortranCInterface_GLOBAL_${form}PREFIX) + set(_prefix "${FortranCInterface_GLOBAL_${form}PREFIX}##") + else() + set(_prefix "") + endif() + if(FortranCInterface_GLOBAL_${form}SUFFIX) + set(_suffix "##${FortranCInterface_GLOBAL_${form}SUFFIX}") + else() + set(_suffix "") + endif() + set(_name "${_name_${FortranCInterface_GLOBAL_${form}CASE}}") + set(FortranCInterface_GLOBAL${form}_MACRO + "(name,NAME) ${_prefix}${_name}${_suffix}") + endif() + if(FortranCInterface_MODULE_${form}SYMBOL) + if(FortranCInterface_MODULE_${form}PREFIX) + set(_prefix "${FortranCInterface_MODULE_${form}PREFIX}##") + else() + set(_prefix "") + endif() + if(FortranCInterface_MODULE_${form}SUFFIX) + set(_suffix "##${FortranCInterface_MODULE_${form}SUFFIX}") + else() + set(_suffix "") + endif() + set(_name "${_name_${FortranCInterface_MODULE_${form}CASE}}") + set(_middle "##${FortranCInterface_MODULE_${form}MIDDLE}##") + set(FortranCInterface_MODULE${form}_MACRO + "(mod_name,name, mod_NAME,NAME) ${_prefix}mod_${_name}${_middle}${_name}${_suffix}") + endif() +endforeach() + +# Summarize what is available. +foreach(scope GLOBAL MODULE) + if(FortranCInterface_${scope}_SYMBOL AND + FortranCInterface_${scope}__SYMBOL) + set(FortranCInterface_${scope}_FOUND 1) + else() + set(FortranCInterface_${scope}_FOUND 0) + endif() +endforeach() + +# Record the detection results. +configure_file(${FortranCInterface_SOURCE_DIR}/Output.cmake.in + ${FortranCInterface_BINARY_DIR}/Output.cmake @ONLY) +file(APPEND ${FortranCInterface_BINARY_DIR}/Output.cmake "\n") + +# Report the results. +if(FortranCInterface_GLOBAL_FOUND) + if(FortranCInterface_MODULE_FOUND) + set(_result "Found GLOBAL and MODULE mangling") + else() + set(_result "Found GLOBAL but not MODULE mangling") + endif() + set(_result_type CHECK_PASS) +elseif(NOT _result) + set(_result "Failed to recognize symbols") + set(_result_type CHECK_FAIL) +endif() +message(${_result_type} "${_result}") diff --git a/Modules/FortranCInterface/Input.cmake.in b/Modules/FortranCInterface/Input.cmake.in new file mode 100644 index 0000000..f261e3b --- /dev/null +++ b/Modules/FortranCInterface/Input.cmake.in @@ -0,0 +1,3 @@ +set(CMAKE_Fortran_COMPILER_ID "@CMAKE_Fortran_COMPILER_ID@") +set(FortranCInterface_GLOBAL_SYMBOLS "@FortranCInterface_GLOBAL_SYMBOLS@") +set(FortranCInterface_MODULE_SYMBOLS "@FortranCInterface_MODULE_SYMBOLS@") diff --git a/Modules/FortranCInterface/MYMODULE.c b/Modules/FortranCInterface/MYMODULE.c new file mode 100644 index 0000000..19b51fb --- /dev/null +++ b/Modules/FortranCInterface/MYMODULE.c @@ -0,0 +1,3 @@ +void MYMODULE(void) +{ +} diff --git a/Modules/FortranCInterface/MY_MODULE.c b/Modules/FortranCInterface/MY_MODULE.c new file mode 100644 index 0000000..87b3071 --- /dev/null +++ b/Modules/FortranCInterface/MY_MODULE.c @@ -0,0 +1,3 @@ +void MY_MODULE(void) +{ +} diff --git a/Modules/FortranCInterface/Macro.h.in b/Modules/FortranCInterface/Macro.h.in new file mode 100644 index 0000000..d015a62 --- /dev/null +++ b/Modules/FortranCInterface/Macro.h.in @@ -0,0 +1,4 @@ +#ifndef @MACRO_NAMESPACE@HEADER_INCLUDED +#define @MACRO_NAMESPACE@HEADER_INCLUDED +@HEADER_CONTENT@ +#endif diff --git a/Modules/FortranCInterface/Output.cmake.in b/Modules/FortranCInterface/Output.cmake.in new file mode 100644 index 0000000..bce410e --- /dev/null +++ b/Modules/FortranCInterface/Output.cmake.in @@ -0,0 +1,33 @@ +# Global symbol without underscore. +set(FortranCInterface_GLOBAL_SYMBOL "@FortranCInterface_GLOBAL_SYMBOL@") +set(FortranCInterface_GLOBAL_PREFIX "@FortranCInterface_GLOBAL_PREFIX@") +set(FortranCInterface_GLOBAL_SUFFIX "@FortranCInterface_GLOBAL_SUFFIX@") +set(FortranCInterface_GLOBAL_CASE "@FortranCInterface_GLOBAL_CASE@") +set(FortranCInterface_GLOBAL_MACRO "@FortranCInterface_GLOBAL_MACRO@") + +# Global symbol with underscore. +set(FortranCInterface_GLOBAL__SYMBOL "@FortranCInterface_GLOBAL__SYMBOL@") +set(FortranCInterface_GLOBAL__PREFIX "@FortranCInterface_GLOBAL__PREFIX@") +set(FortranCInterface_GLOBAL__SUFFIX "@FortranCInterface_GLOBAL__SUFFIX@") +set(FortranCInterface_GLOBAL__CASE "@FortranCInterface_GLOBAL__CASE@") +set(FortranCInterface_GLOBAL__MACRO "@FortranCInterface_GLOBAL__MACRO@") + +# Module symbol without underscore. +set(FortranCInterface_MODULE_SYMBOL "@FortranCInterface_MODULE_SYMBOL@") +set(FortranCInterface_MODULE_PREFIX "@FortranCInterface_MODULE_PREFIX@") +set(FortranCInterface_MODULE_MIDDLE "@FortranCInterface_MODULE_MIDDLE@") +set(FortranCInterface_MODULE_SUFFIX "@FortranCInterface_MODULE_SUFFIX@") +set(FortranCInterface_MODULE_CASE "@FortranCInterface_MODULE_CASE@") +set(FortranCInterface_MODULE_MACRO "@FortranCInterface_MODULE_MACRO@") + +# Module symbol with underscore. +set(FortranCInterface_MODULE__SYMBOL "@FortranCInterface_MODULE__SYMBOL@") +set(FortranCInterface_MODULE__PREFIX "@FortranCInterface_MODULE__PREFIX@") +set(FortranCInterface_MODULE__MIDDLE "@FortranCInterface_MODULE__MIDDLE@") +set(FortranCInterface_MODULE__SUFFIX "@FortranCInterface_MODULE__SUFFIX@") +set(FortranCInterface_MODULE__CASE "@FortranCInterface_MODULE__CASE@") +set(FortranCInterface_MODULE__MACRO "@FortranCInterface_MODULE__MACRO@") + +# Summarize what was found. +set(FortranCInterface_GLOBAL_FOUND @FortranCInterface_GLOBAL_FOUND@) +set(FortranCInterface_MODULE_FOUND @FortranCInterface_MODULE_FOUND@) diff --git a/Modules/FortranCInterface/Verify/CMakeLists.txt b/Modules/FortranCInterface/Verify/CMakeLists.txt new file mode 100644 index 0000000..98cdeb7 --- /dev/null +++ b/Modules/FortranCInterface/Verify/CMakeLists.txt @@ -0,0 +1,26 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +cmake_minimum_required(VERSION ${CMAKE_VERSION}) +project(VerifyFortranC C Fortran) + +option(VERIFY_CXX "Whether to verify C++ and Fortran" OFF) +if(VERIFY_CXX) + enable_language(CXX) + set(VerifyCXX VerifyCXX.cxx) + add_definitions(-DVERIFY_CXX) +endif() + +include(FortranCInterface) + +FortranCInterface_HEADER(VerifyFortran.h SYMBOLS VerifyFortran) +include_directories(${VerifyFortranC_BINARY_DIR}) + +add_library(VerifyFortran STATIC VerifyFortran.f) +add_executable(VerifyFortranC main.c VerifyC.c ${VerifyCXX}) +target_link_libraries(VerifyFortranC VerifyFortran) + +if(NOT VERIFY_CXX) + # The entry point (main) is defined in C; link with the C compiler. + set_property(TARGET VerifyFortranC PROPERTY LINKER_LANGUAGE C) +endif() diff --git a/Modules/FortranCInterface/Verify/VerifyC.c b/Modules/FortranCInterface/Verify/VerifyC.c new file mode 100644 index 0000000..7f847ef --- /dev/null +++ b/Modules/FortranCInterface/Verify/VerifyC.c @@ -0,0 +1,5 @@ +#include <stdio.h> +void VerifyC(void) +{ + printf("VerifyC\n"); +} diff --git a/Modules/FortranCInterface/Verify/VerifyCXX.cxx b/Modules/FortranCInterface/Verify/VerifyCXX.cxx new file mode 100644 index 0000000..689fac5 --- /dev/null +++ b/Modules/FortranCInterface/Verify/VerifyCXX.cxx @@ -0,0 +1,4 @@ +extern "C" void VerifyCXX(void) +{ + delete new int; +} diff --git a/Modules/FortranCInterface/Verify/VerifyFortran.f b/Modules/FortranCInterface/Verify/VerifyFortran.f new file mode 100644 index 0000000..a17e48d --- /dev/null +++ b/Modules/FortranCInterface/Verify/VerifyFortran.f @@ -0,0 +1,3 @@ + subroutine VerifyFortran + print *, 'VerifyFortran' + end diff --git a/Modules/FortranCInterface/Verify/main.c b/Modules/FortranCInterface/Verify/main.c new file mode 100644 index 0000000..582ef1d --- /dev/null +++ b/Modules/FortranCInterface/Verify/main.c @@ -0,0 +1,16 @@ +extern void VerifyC(void); +#ifdef VERIFY_CXX +extern void VerifyCXX(void); +#endif +#include "VerifyFortran.h" +extern void VerifyFortran(void); + +int main(void) +{ + VerifyC(); +#ifdef VERIFY_CXX + VerifyCXX(); +#endif + VerifyFortran(); + return 0; +} diff --git a/Modules/FortranCInterface/call_mod.f90 b/Modules/FortranCInterface/call_mod.f90 new file mode 100644 index 0000000..9b6af64 --- /dev/null +++ b/Modules/FortranCInterface/call_mod.f90 @@ -0,0 +1,6 @@ +subroutine call_mod + use mymodule + use my_module + call mysub() + call my_sub() +end subroutine call_mod diff --git a/Modules/FortranCInterface/call_sub.f b/Modules/FortranCInterface/call_sub.f new file mode 100644 index 0000000..ce3d50b --- /dev/null +++ b/Modules/FortranCInterface/call_sub.f @@ -0,0 +1,4 @@ + subroutine call_sub + call mysub() + call my_sub() + end diff --git a/Modules/FortranCInterface/main.F b/Modules/FortranCInterface/main.F new file mode 100644 index 0000000..84991b0 --- /dev/null +++ b/Modules/FortranCInterface/main.F @@ -0,0 +1,6 @@ + program main + call call_sub() +#ifdef CALL_MOD + call call_mod() +#endif + end diff --git a/Modules/FortranCInterface/my_module.f90 b/Modules/FortranCInterface/my_module.f90 new file mode 100644 index 0000000..82713b4 --- /dev/null +++ b/Modules/FortranCInterface/my_module.f90 @@ -0,0 +1,8 @@ +module my_module + interface my_interface + module procedure my_sub + end interface +contains + subroutine my_sub + end subroutine my_sub +end module my_module diff --git a/Modules/FortranCInterface/my_module_.c b/Modules/FortranCInterface/my_module_.c new file mode 100644 index 0000000..6fa89d1 --- /dev/null +++ b/Modules/FortranCInterface/my_module_.c @@ -0,0 +1,3 @@ +void my_module_(void) +{ +} diff --git a/Modules/FortranCInterface/my_sub.f b/Modules/FortranCInterface/my_sub.f new file mode 100644 index 0000000..247ba06 --- /dev/null +++ b/Modules/FortranCInterface/my_sub.f @@ -0,0 +1,2 @@ + subroutine my_sub + end diff --git a/Modules/FortranCInterface/mymodule.f90 b/Modules/FortranCInterface/mymodule.f90 new file mode 100644 index 0000000..ef6281a --- /dev/null +++ b/Modules/FortranCInterface/mymodule.f90 @@ -0,0 +1,8 @@ +module mymodule + interface myinterface + module procedure mysub + end interface +contains + subroutine mysub + end subroutine mysub +end module mymodule diff --git a/Modules/FortranCInterface/mymodule_.c b/Modules/FortranCInterface/mymodule_.c new file mode 100644 index 0000000..444953b --- /dev/null +++ b/Modules/FortranCInterface/mymodule_.c @@ -0,0 +1,3 @@ +void mymodule_(void) +{ +} diff --git a/Modules/FortranCInterface/mysub.f b/Modules/FortranCInterface/mysub.f new file mode 100644 index 0000000..1c27ff4 --- /dev/null +++ b/Modules/FortranCInterface/mysub.f @@ -0,0 +1,2 @@ + subroutine mysub + end diff --git a/Modules/FortranCInterface/symbol.c.in b/Modules/FortranCInterface/symbol.c.in new file mode 100644 index 0000000..369fa45 --- /dev/null +++ b/Modules/FortranCInterface/symbol.c.in @@ -0,0 +1,4 @@ +const char* @symbol@(void) +{ + return "INFO:symbol[@symbol@]"; +} |