Fortran¶
This section discusses Fortran specific wrapper details. This will also include some C wrapper details since some C wrappers are created specificially to be called by Fortran.
Wrapper¶
As each function declaration is parsed a format dictionary is created with fields to describe the function and its arguments. The fields are then expanded into the function wrapper.
The template for Fortran code showing names which may be controlled directly by the input YAML file:
module {F_module_name}
! use_stmts
implicit none
abstract interface
subprogram {F_abstract_interface_subprogram_template}
type :: {F_abstract_interface_argument_template}
end subprogram
end interface
interface
{F_C_pure_clause} {F_C_subprogram} {F_C_name}
{F_C_result_clause} bind(C, name="{C_name}")
! arg_f_use
implicit none
! arg_c_decl
end {F_C_subprogram} {F_C_name}
end interface
interface {F_name_generic}
module procedure {F_name_impl}
end interface {F_name_generic}
contains
{F_subprogram} {F_name_impl}
declare
pre_call
call
post_call
end {F_subprogram} {F_name_impl}
end module {F_module_name}
Class¶
Use of format fields for creating class wrappers.
type, bind(C) :: {F_capsule_data_type}
type(C_PTR) :: addr = C_NULL_PTR ! address of C++ memory
integer(C_INT) :: idtor = 0 ! index of destructor
end type {F_capsule_data_type}
type {F_derived_name}
type({F_capsule_data_type}) :: {F_derived_member}
contains
procedure :: {F_name_function} => {F_name_impl}
generic :: {F_name_generic} => {F_name_function}, ...
! F_name_getter, F_name_setter, F_name_instance_get as underscore_name
procedure :: [F_name_function_template] => [F_name_impl_template]
end type {F_derived_name}
Types¶
The typemap provides several fields used to convert between Fortran and C.
type fields¶
f_c_module¶
Fortran modules needed for type in the interface. A dictionary keyed on the module name with the value being a list of symbols. Similar to f_module. Defaults to None.
f_c_type¶
Type declaration for bind(C)
interface.
Defaults to None which will then use f_type.
f_cast¶
Expression to convert Fortran type to C type.
This is used when creating a Fortran generic functions which
accept several type but call a single C function which expects
a specific type.
For example, type int
is defined as int({f_var}, C_INT)
.
This expression converts f_var to a integer(C_INT)
.
Defaults to {f_var} i.e. no conversion.
f_derived_type¶
Fortran derived type name. Defaults to None which will use the C++ class name for the Fortran derived type name.
f_kind¶
Fortran kind of type. For example, C_INT
or C_LONG
.
Defaults to None.
f_module¶
Fortran modules needed for type in the implementation wrapper. A dictionary keyed on the module name with the value being a list of symbols. Defaults to None.:
f_module:
iso_c_binding:
- C_INT
f_type¶
Name of type in Fortran. ( integer(C_INT)
)
Defaults to None.
f_to_c¶
None Expression to convert from Fortran to C.
f_args¶
None Argument in Fortran wrapper to call C.
Predefined Types¶
Int¶
An int
argument is converted to Fortran with the typemap:
type: int
fields:
f_type: integer(C_INT)
f_kind: C_INT
f_module:
iso_c_binding:
- C_INT
f_cast: int({f_var}, C_INT)
Pointers¶
When a function returns a pointer to a POD type several Fortran
interfaces are possible. When a function returns an int *
the
simplest result is to return a type(C_PTR)
. This is just the raw
pointer returned by C++. It’s also the least useful to the caller
since it cannot be used directly.
If the C++ library function can also provide the length of the
pointer, then its possible to return a Fortran POINTER
or
ALLOCATABLE
variable. This allows the caller to directly use the
returned value of the C++ function. However, there is a price; the
user will have to release the memory if owner(caller) is set. To
accomplish this with POINTER
arguments, an additional argument is
added to the function which contains information about how to delete
the array. If the argument is declared Fortran ALLOCATABLE
, then
the value of the C++ pointer are copied into a newly allocated Fortran
array. The C++ memory is deleted by the wrapper and it is the callers
responsibility to deallocate
the Fortran array. However, Fortran
will release the array automatically under some conditions when the
caller function returns. If owner(library) is set, the Fortran
caller never needs to release the memory.
See Memory Management for details of the implementation.
Functions with void *
arguments are treated differently. A
type(C_PTR)
will be passed by value. For a void **
argument,
the type(C_PTR)
will be passed by reference (the default). This
will allow the C wrapper to assign a value to the argument.
- decl: void passVoidStarStar(void *in+intent(in), void **out+intent(out))
Creates the Fortran interface:
subroutine pass_void_star_star(in, out) &
bind(C, name="passVoidStarStar")
use iso_c_binding, only : C_PTR
implicit none
type(C_PTR), value, intent(IN) :: in
type(C_PTR), intent(OUT) :: out
end subroutine pass_void_star_star
A void pointer may also be used in a C function when any type may be
passed in. The attribute assumedtype can be used to declare a
Fortran argument as assumed-type: type(*)
.
- decl: int passAssumedType(void *arg+assumedtype)
function pass_assumed_type(arg) &
result(SHT_rv) &
bind(C, name="passAssumedType")
use iso_c_binding, only : C_INT, C_PTR
implicit none
type(*) :: arg
integer(C_INT) :: SHT_rv
end function pass_assumed_type
Standard type-bound procedures¶
Several type bound procedures can be created to make it easier to use class from Fortran.
Usually the F_derived_name is constructed from wrapped C++ constructor. It may also be useful to take a pointer to a C++ struct and explicitly put it into a the derived type. The functions F_name_instance_get and F_name_instance_set can be used to access the pointer directly.
Two predicate function are generated to compare derived types:
interface operator (.eq.)
module procedure class1_eq
module procedure singleton_eq
end interface
interface operator (.ne.)
module procedure class1_ne
module procedure singleton_ne
end interface
contains
function {F_name_scope}eq(a,b) result (rv)
use iso_c_binding, only: c_associated
type({F_derived_name}), intent(IN) ::a,b
logical :: rv
if (c_associated(a%{F_derived_member}%addr, b%{F_derived_member}%addr)) then
rv = .true.
else
rv = .false.
endif
end function {F_name_scope}eq
function {F_name_scope}ne(a,b) result (rv)
use iso_c_binding, only: c_associated
type({F_derived_name}), intent(IN) ::a,b
logical :: rv
if (.not. c_associated(a%{F_derived_member}%addr, b%{F_derived_member}%addr)) then
rv = .true.
else
rv = .false.
endif
end function {F_name_scope}ne