diff --git a/Modules/FortranCInterface.cmake b/Modules/FortranCInterface.cmake new file mode 100644 index 000000000..9f86acb75 --- /dev/null +++ b/Modules/FortranCInterface.cmake @@ -0,0 +1,135 @@ +# FortranCInterface.cmake +# +# This file defines the function create_fortran_c_interface. +# this function is used to create a configured header file +# that contains a mapping from C to a Fortran function using +# the correct name mangling scheme as defined by the current +# fortran compiler. +# +# The function tages a list of functions and the name of +# a header file to configure. +# +# This file also defines some helper functions that are used +# to detect the fortran name mangling scheme used by the +# current Fortran compiler. +# test_fortran_mangling - test a single fortran mangling +# discover_fortran_mangling - loop over all combos of fortran +# name mangling and call test_fortran_mangling until one of them +# works. +# + +function(test_fortran_mangling PREFIX ISUPPER POSTFIX RESULT) + if(ISUPPER) + set(FUNCTION "${PREFIX}SUB${POSTFIX}") + else(ISUPPER) + set(FUNCTION "${PREFIX}sub${POSTFIX}") + endif(ISUPPER) + # create a fortran file with sub called sub + # + set(TMP_DIR + "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckFortranLink") + file(REMOVE_RECURSE "${TMP_DIR}") + file(WRITE "${TMP_DIR}/test.f" + " + subroutine sub + end subroutine sub + " + ) + message(STATUS "checking Fortran linkage: ${FUNCTION}") + file(WRITE "${TMP_DIR}/ctof.c" + " + extern ${FUNCTION}(); + int main() { ${FUNCTION}(); return 0;} + " + ) + file(WRITE "${TMP_DIR}/CMakeLists.txt" + " + project(testf C Fortran) + add_library(flib test.f) + add_executable(ctof ctof.c) + target_link_libraries(ctof flib) + " + ) + set(FORTRAN_NAME_MANGLE_TEST FALSE) + try_compile(FORTRAN_NAME_MANGLE_TEST "${TMP_DIR}" "${TMP_DIR}" + testf + OUTPUT_VARIABLE output) + if(FORTRAN_NAME_MANGLE_TEST) + set(${RESULT} TRUE PARENT_SCOPE) + else() + set(${RESULT} FALSE PARENT_SCOPE) + endif() +endfunction(test_fortran_mangling) + +function(discover_fortran_mangling prefix isupper suffix found ) + foreach(pre "_" "" "__") + foreach(isup TRUE FALSE) + foreach(post "" "_") + set(worked FALSE) + test_fortran_mangling("${pre}" ${isup} "${post}" worked ) + if(worked) + message(STATUS "found Fotran linkage") + set(${isupper} "${isup}" PARENT_SCOPE) + set(${prefix} "${pre}" PARENT_SCOPE) + set(${suffix} "${post}" PARENT_SCOPE) + set(${found} TRUE PARENT_SCOPE) + return() + endif() + endforeach() + endforeach() + endforeach() + set(${found} FALSE PARENT_SCOPE) +endfunction(discover_fortran_mangling) + +function(create_fortran_c_interface NAMESPACE FUNCTIONS HEADER) + if(NOT FORTRAN_C_MANGLING_FOUND) + discover_fortran_mangling(prefix isupper suffix found) + if(NOT found) + message(SEND_ERROR "Could not find fortran c name mangling.") + return() + endif(NOT found) + set(FORTRAN_C_PREFIX "${prefix}" CACHE INTERNAL + "PREFIX for Fortran to c name mangling") + set(FORTRAN_C_SUFFIX "${suffix}" CACHE INTERNAL + "SUFFIX for Fortran to c name mangling") + set(FORTRAN_C_MANGLING_UPPERCASE ${isupper} CACHE INTERNAL + "Was fortran to c mangling found" ) + set(FORTRAN_C_MANGLING_FOUND TRUE CACHE INTERNAL + "Was fortran to c mangling found" ) + endif(NOT FORTRAN_C_MANGLING_FOUND) + foreach(f ${${FUNCTIONS}}) + if(${FORTRAN_C_MANGLING_UPPERCASE}) + string(TOUPPER "${f}" ff) + else() + string(TOLOWER "${f}" ff) + endif() + set(function "${FORTRAN_C_PREFIX}${ff}${FORTRAN_C_SUFFIX}") + set(HEADER_CONTENT "${HEADER_CONTENT} +#define ${NAMESPACE}${f} ${function} +") + endforeach(f) + configure_file( + "${CMAKE_ROOT}/Modules/FortranCInterface.h.in" + ${HEADER} @ONLY) + message(STATUS "created ${HEADER}") +endfunction() + +# TODO +# need to add support for module linking +# module test_interface +# +# interface dummy +# module procedure module_function +# end interface +# +# contains +# +# subroutine module_function +# end subroutine +# +# end module test_interface +# +# produces this: +# __test_interface_MOD_module_function +# +# diff --git a/Modules/FortranCInterface.h.in b/Modules/FortranCInterface.h.in new file mode 100644 index 000000000..02501758f --- /dev/null +++ b/Modules/FortranCInterface.h.in @@ -0,0 +1,9 @@ +/* This file is automatically generated by CMake, DO NOT EDIT. + It contains a mapping from Fortran functions so they can + be called from C or C++. */ + + +@HEADER_CONTENT@ + + +