| # 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. |
| # discover_fortran_module_mangling - try different types of |
| # fortran modle name mangling to find one that works |
| # |
| # |
| # |
| # this function tests a single fortran mangling. |
| # CODE - test code to try should define a subroutine called "sub" |
| # PREFIX - string to put in front of sub |
| # POSTFIX - string to put after sub |
| # ISUPPER - if TRUE then sub will be called as SUB |
| # DOC - string used in status checking Fortran ${DOC} linkage |
| # SUB - the name of the SUB to call |
| # RESULT place to store result TRUE if this linkage works, FALSE |
| # if not. |
| # |
| function(test_fortran_mangling CODE PREFIX ISUPPER POSTFIX DOC SUB RESULT) |
| if(ISUPPER) |
| string(TOUPPER "${SUB}" sub) |
| else(ISUPPER) |
| string(TOLOWER "${SUB}" sub) |
| endif(ISUPPER) |
| set(FUNCTION "${PREFIX}${sub}${POSTFIX}") |
| # 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" "${CODE}" ) |
| message(STATUS "checking Fortran ${DOC} 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) |
| |
| # this function discovers the name mangling scheme used |
| # for functions in a fortran module. |
| function(discover_fortran_module_mangling prefix suffix found) |
| set(CODE |
| " |
| module test_interface |
| interface dummy |
| module procedure sub |
| end interface |
| contains |
| subroutine sub |
| end subroutine |
| end module test_interface |
| ") |
| set(worked FALSE) |
| foreach(interface |
| "test_interface$" |
| "TEST_INTERFACE_mp_" |
| "_test_interface__" |
| "__test_interface__" |
| "__test_interface_NMOD_" |
| "__test_interface_MOD_") |
| test_fortran_mangling("${CODE}" "${interface}" |
| ${FORTRAN_C_MANGLING_UPPERCASE} "" "module" "sub" worked) |
| if(worked) |
| # if this is the upper case module match then |
| # lower case it for the extraction of pre and post strings |
| if("${interface}" MATCHES "TEST_INTERFACE") |
| string(TOLOWER "${interface}" interface) |
| endif() |
| string(REGEX REPLACE "(.*)test_interface(.*)" "\\1" pre "${interface}") |
| string(REGEX REPLACE "(.*)test_interface(.*)" "\\2" post "${interface}") |
| set(${prefix} "${pre}" PARENT_SCOPE) |
| set(${suffix} "${post}" PARENT_SCOPE) |
| set(${found} TRUE PARENT_SCOPE) |
| return() |
| endif(worked) |
| endforeach(interface) |
| if(NOT worked) |
| message(STATUS "Failed to find C binding to Fortran module functions.") |
| set(${prefix} "BROKEN_C_FORTRAN_MODULE_BINDING" PARENT_SCOPE) |
| set(${suffix} "BROKEN_C_FORTRAN_MODULE_BINDING" PARENT_SCOPE) |
| set(${found} FALSE PARENT_SCOPE) |
| endif(NOT worked) |
| endfunction(discover_fortran_module_mangling) |
| |
| |
| function(discover_fortran_mangling prefix isupper suffix extra_under_score |
| found ) |
| set(CODE |
| " |
| subroutine sub |
| end subroutine sub |
| ") |
| foreach(post "_" "") |
| foreach(isup FALSE TRUE) |
| foreach(pre "" "_" "__") |
| set(worked FALSE) |
| test_fortran_mangling("${CODE}" "${pre}" ${isup} |
| "${post}" "function" sub worked ) |
| if(worked) |
| message(STATUS "found Fortran function linkage") |
| set(${isupper} "${isup}" PARENT_SCOPE) |
| set(${prefix} "${pre}" PARENT_SCOPE) |
| set(${suffix} "${post}" PARENT_SCOPE) |
| set(${found} TRUE PARENT_SCOPE) |
| set(CODE |
| " |
| subroutine my_sub |
| end subroutine my_sub |
| ") |
| set(worked FALSE) |
| test_fortran_mangling("${CODE}" "${pre}" ${isup} |
| "${post}" "function with _ " my_sub worked ) |
| if(worked) |
| set(${extra_under_score} FALSE PARENT_SCOPE) |
| else(worked) |
| test_fortran_mangling("${CODE}" "${pre}" ${isup} |
| "${post}_" "function with _ " my_sub worked ) |
| if(worked) |
| set(${extra_under_score} TRUE PARENT_SCOPE) |
| endif(worked) |
| endif(worked) |
| 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) |
| # find regular fortran function mangling |
| discover_fortran_mangling(prefix isupper suffix extra_under found) |
| if(NOT found) |
| message(SEND_ERROR "Could not find fortran c name mangling.") |
| return() |
| endif(NOT found) |
| # find fortran module function mangling |
| 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_EXTRA_UNDERSCORE ${extra_under} CACHE INTERNAL |
| "If a function has a _ in the name does the compiler append an extra _" ) |
| set(FORTRAN_C_MANGLING_FOUND TRUE CACHE INTERNAL |
| "Was fortran to c mangling found" ) |
| set(prefix ) |
| set(suffix ) |
| set(found FALSE) |
| # only try this if the compiler is F90 compatible |
| if(CMAKE_Fortran_COMPILER_SUPPORTS_F90) |
| discover_fortran_module_mangling(prefix suffix found) |
| endif(CMAKE_Fortran_COMPILER_SUPPORTS_F90) |
| if(found) |
| message(STATUS "found Fortran module linkage") |
| else(found) |
| message(STATUS "Failed to find Fortran module linkage") |
| endif(found) |
| set(FORTRAN_C_MODULE_PREFIX "${prefix}" CACHE INTERNAL |
| "PREFIX for Fortran to c name mangling") |
| set(FORTRAN_C_MODULE_SUFFIX "${suffix}" CACHE INTERNAL |
| "SUFFIX for Fortran to c name mangling") |
| set(FORTRAN_C_MODULE_MANGLING_FOUND ${found} CACHE INTERNAL |
| "Was for Fortran to c name mangling found for modules") |
| endif(NOT FORTRAN_C_MANGLING_FOUND) |
| foreach(f ${${FUNCTIONS}}) |
| if(FORTRAN_C_MANGLING_UPPERCASE) |
| string(TOUPPER "${f}" fcase) |
| else() |
| string(TOLOWER "${f}" fcase) |
| endif() |
| if("${f}" MATCHES ":") |
| string(REGEX REPLACE "(.*):(.*)" "\\1" module "${f}") |
| string(REGEX REPLACE "(.*):(.*)" "\\2" function "${f}") |
| string(REGEX REPLACE "(.*):(.*)" "\\1" module_case "${fcase}") |
| string(REGEX REPLACE "(.*):(.*)" "\\2" function_case "${fcase}") |
| set(HEADER_CONTENT "${HEADER_CONTENT} |
| #define ${NAMESPACE}${module}_${function} ${FORTRAN_C_MODULE_PREFIX}${module_case}${FORTRAN_C_MODULE_SUFFIX}${function_case} |
| ") |
| else("${f}" MATCHES ":") |
| set(function "${FORTRAN_C_PREFIX}${fcase}${FORTRAN_C_SUFFIX}") |
| if("${f}" MATCHES "_" AND FORTRAN_C_MANGLING_EXTRA_UNDERSCORE) |
| set(function "${function}_") |
| endif("${f}" MATCHES "_" AND FORTRAN_C_MANGLING_EXTRA_UNDERSCORE) |
| set(HEADER_CONTENT "${HEADER_CONTENT} |
| #define ${NAMESPACE}${f} ${function} |
| ") |
| endif("${f}" MATCHES ":") |
| endforeach(f) |
| configure_file( |
| "${CMAKE_ROOT}/Modules/FortranCInterface.h.in" |
| ${HEADER} @ONLY) |
| message(STATUS "created ${HEADER}") |
| endfunction() |
| |