Types¶
Numeric Types¶
The numeric types usually require no conversion. In this case the type map is mainly used to generate declaration code for wrappers:
type: int
fields:
c_type: int
cxx_type: int
f_type: integer(C_INT)
f_kind: C_INT
f_module:
iso_c_binding:
- C_INT
f_cast: int({f_var}, C_INT)
One case where a conversion is required is when the Fortran argument
is one type and the C++ argument is another. This may happen when an
overloaded function is generated so that a C_INT or C_LONG
argument may be passed to a C++ function function expecting a
long. The f_cast field is used to convert the argument to the
type expected by the C++ function.
Bool¶
The first thing to notice is that i_type is defined. This is
the type used in the Fortran interface for the C wrapper. The type
is logical(C_BOOL) while f_type, the type of the Fortran
wrapper argument, is logical.
The f_statements section describes code to add into the Fortran
wrapper to perform the conversion. c_var and f_var default to
the same value as the argument name. By setting c_local_var, a
local variable is generated for the call to the C wrapper. It will be
named SH_{f_var}.
There is no Fortran intrinsic function to convert between default
logical and logical(C_BOOL). The pre_call and
post_call sections will insert an assignment statement to allow
the compiler to do the conversion.
If a function returns a bool result then a wrapper is always needed
to convert the result. The result section sets need_wrapper
to force the wrapper to be created. By default a function with no
argument would not need a wrapper since there will be no pre_call
or post_call code blocks. Only the C interface would be required
since Fortran could call the C function directly.
See example checkBool.
Char¶
Any C++ function which has char or std::string arguments or
result will create an additional C function which include additional
arguments for the length of the strings. Most Fortran compiler use
this convention when passing CHARACTER arguments. Shroud makes
this convention explicit for two reasons
It allows an interface to be used. Functions with an interface will not pass the hidden, non-standard length argument, depending on compiler.
Returning character argument from C to Fortran is non-portable. Often an additional argument is added for the function result.
The C wrapper will create a NULL terminated copy a string with the intent(in) attribute. The assumption is that the trailing blanks are not part of the data but only padding. Return values and intent(out) arguments add a len annotation with the assumption that the wrapper will copy the result and blank fill the argument so it need to know the declared length.
A buffer for intent(out) arguments is also create which is one longer than the Fortran string length. This allows space for a C terminating NULL. This buffer is passed to the C library which will copy into it. Upon return, the buffer is copied and blank filled into the user’s argument and the intermediate buffer released.
Library functions which return a scalar char have a wrapper generated
which pass a char * argument to the C wrapper where the first
element is assigned ( *arg a.k.a arg[0]). Returning a char
proved to be non-portable while passing the result by reference works
on the tested compilers.
The bufferify function will be named the same as the original function with the option C_bufferify_suffix appended to the end. The Fortran wrapper will use the original function name, but call the C wrapper which accepts the length arguments.
Python wrappers may need an additional attribute for intent(out)
strings to let Shroud know how much space to pass to the function. A
function may pass a char * argument which the C library will copy
into. While this is not a recommened practice since it’s easy to
overwrite memory, Shoud can deal with it by setting the +charlen(n)
attribute where n is the number of character in the array passed to
the function. This is required for Python since strings are inmutable.
The buffer will be converted into a Python str object then returned to
the user. This is not an issue in Fortran since the output buffer is
passed in by the caller and will have a known size.
By default, a Fortran blank input string will be converted to an empty
string before being passed to the C library. i.e. " " in Fortran
is converted to '\0' in C. This behavior can be changed to convert
the empty string into a NULL pointer by setting the +blanknull
attribute. This is often more natural for the C library to indicate the
absence of a value. The option F_blanknull can be used to make this the
default for all const char * arguments.
On some occasions the copy and null terminate behavior is not wanted. For example, to avoid copying a large buffer or the memory must be operated on directly. In this case using the attribute +api(capi) will use the native C API instead of the bufferify API for the argument. The library will need some way to determine the length of the string since it will not be passed to the C wrapper. As an alternative the bufferify function can be avoided altogether by setting the F_create_bufferify_function option to false.
The character type maps use the c_statements section to define code which will be inserted into the C wrapper. These actions vary depending on the intent of in, out, inout and result.
MPI_Comm¶
MPI_Comm is provided by Shroud and serves as an example of how to wrap a non-native type. MPI provides a Fortran interface and the ability to convert MPI_comm between Fortran and C. The type map tells Shroud how to use these routines:
type: MPI_Comm
fields:
cxx_type: MPI_Comm
c_header: mpi.h
c_type: MPI_Fint
f_type: integer
f_kind: C_INT
i_type: integer(C_INT)
i_module:
iso_c_binding:
- C_INT
cxx_to_c: MPI_Comm_c2f({cxx_var})
c_to_cxx: MPI_Comm_f2c({c_var})
This mapping makes the assumption that integer and
integer(C_INT) are the same type.
Typedef¶
A typedef is used to create an alias for another type. Often to create an abstraction for the intented use of the type.
typedef int IndexType;
From the Fortran side, this will create a parameter for the kind parameter.
integer, parameter :: index_type = C_INT
This allows variables to continue to use the typedef.
IndexType arg;
From the Fortran side, this will create a parameter for the kind parameter.
integer(index_type) :: arg
A C wrapper will create another typedef which is accessible from C. A C++ typedef may be in a scope so Shroud will mangle the name to make it accessible at the global level.
typedef int TYP_IndexType;
The name of the generated typedef can be modified using format fields.
- decl: typedef int32_t IndexType2
format:
F_name_typedef: LOCAL_Index_Type
C_name_typedef: LOCAL_IndexType