CMake/Modules/FortranCInterface.cmake

217 lines
7.4 KiB
CMake
Raw Normal View History

2008-10-27 22:23:14 +03:00
# 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.
2008-10-28 04:42:41 +03:00
# discover_fortran_module_mangling - try different types of
# fortran modle name mangling to find one that works
2008-10-27 22:23:14 +03:00
#
2008-10-28 04:42:41 +03:00
#
#
# 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
2008-10-28 04:42:41 +03:00
# RESULT place to store result TRUE if this linkage works, FALSE
# if not.
#
function(test_fortran_mangling CODE PREFIX ISUPPER POSTFIX DOC SUB RESULT)
2008-10-27 22:23:14 +03:00
if(ISUPPER)
string(TOUPPER "${SUB}" sub)
else(ISUPPER)
string(TOLOWER "${SUB}" sub)
2008-10-27 22:23:14 +03:00
endif(ISUPPER)
set(FUNCTION "${PREFIX}${sub}${POSTFIX}")
2008-10-27 22:23:14 +03:00
# create a fortran file with sub called sub
#
set(TMP_DIR
"${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckFortranLink")
file(REMOVE_RECURSE "${TMP_DIR}")
2008-10-28 04:42:41 +03:00
file(WRITE "${TMP_DIR}/test.f" "${CODE}" )
message(STATUS "checking Fortran ${DOC} linkage: ${FUNCTION}")
2008-10-27 22:23:14 +03:00
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)
2008-10-28 04:42:41 +03:00
# 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
")
foreach(interface
"test_interface$"
2008-10-29 18:50:20 +03:00
"__test_interface_NMOD_"
2008-10-28 04:42:41 +03:00
"__test_interface_MOD_")
test_fortran_mangling("${CODE}" "${interface}"
${FORTRAN_C_MANGLING_UPPERCASE} "" "module" "sub" worked)
2008-10-28 04:42:41 +03:00
if(worked)
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)
endfunction(discover_fortran_module_mangling)
function(discover_fortran_mangling prefix isupper suffix extra_under_score
found )
2008-10-28 04:42:41 +03:00
set(CODE
"
subroutine sub
end subroutine sub
")
2008-10-29 17:58:40 +03:00
foreach(post "_" "")
foreach(isup FALSE TRUE)
foreach(pre "" "_" "__")
2008-10-27 22:23:14 +03:00
set(worked FALSE)
test_fortran_mangling("${CODE}" "${pre}" ${isup}
"${post}" "function" sub worked )
2008-10-27 22:23:14 +03:00
if(worked)
2008-10-28 04:42:41 +03:00
message(STATUS "found Fortran function linkage")
2008-10-27 22:23:14 +03:00
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()
2008-10-27 22:23:14 +03:00
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)
2008-10-28 04:42:41 +03:00
# find regular fortran function mangling
discover_fortran_mangling(prefix isupper suffix extra_under found)
2008-10-27 22:23:14 +03:00
if(NOT found)
message(SEND_ERROR "Could not find fortran c name mangling.")
return()
endif(NOT found)
2008-10-28 04:42:41 +03:00
# find fortran module function mangling
2008-10-27 22:23:14 +03:00
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 _" )
2008-10-27 22:23:14 +03:00
set(FORTRAN_C_MANGLING_FOUND TRUE CACHE INTERNAL
"Was fortran to c mangling found" )
2008-10-28 04:42:41 +03:00
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)
2008-10-28 04:42:41 +03:00
if(found)
message(STATUS "found Fortran module linkage")
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 TRUE CACHE INTERNAL
"SUFFIX for Fortran to c name mangling")
else(found)
set(FORTRAN_C_MODULE_MANGLING_FOUND FALSE CACHE INTERNAL
"SUFFIX for Fortran to c name mangling")
endif(found)
2008-10-27 22:23:14 +03:00
endif(NOT FORTRAN_C_MANGLING_FOUND)
foreach(f ${${FUNCTIONS}})
if(${FORTRAN_C_MANGLING_UPPERCASE})
string(TOUPPER "${f}" ff)
else()
string(TOLOWER "${f}" ff)
endif()
2008-10-28 04:42:41 +03:00
if("${f}" MATCHES ":")
string(REGEX REPLACE "(.*):(.*)" "\\1" module "${f}")
string(REGEX REPLACE "(.*):(.*)" "\\2" function "${f}")
set(HEADER_CONTENT "${HEADER_CONTENT}
#define ${NAMESPACE}${module}_${function} ${FORTRAN_C_MODULE_PREFIX}${module}${FORTRAN_C_MODULE_SUFFIX}${function}
")
else("${f}" MATCHES ":")
set(function "${FORTRAN_C_PREFIX}${ff}${FORTRAN_C_SUFFIX}")
if("${f}" MATCHES "_" AND FORTRAN_C_MANGLING_EXTRA_UNDERSCORE)
set(function "${function}_")
endif("${f}" MATCHES "_" AND FORTRAN_C_MANGLING_EXTRA_UNDERSCORE)
2008-10-28 04:42:41 +03:00
set(HEADER_CONTENT "${HEADER_CONTENT}
2008-10-27 22:23:14 +03:00
#define ${NAMESPACE}${f} ${function}
")
2008-10-28 04:42:41 +03:00
endif("${f}" MATCHES ":")
2008-10-27 22:23:14 +03:00
endforeach(f)
configure_file(
"${CMAKE_ROOT}/Modules/FortranCInterface.h.in"
${HEADER} @ONLY)
message(STATUS "created ${HEADER}")
endfunction()