summaryrefslogtreecommitdiffstats
path: root/Modules/FortranCInterface.cmake
blob: 9f86acb75d25ad06b65f4aedf2d3844169d52e7d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
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
#
#