Declarations¶
In order for Shroud to create an idiomatic wrapper, it needs to know how arguments are intended to be used. This information is supplied via attributes. This section describes how to describe the arguments to Shroud in order to implement the desired semantic.
No Arguments¶
A C function with no arguments and which does not return a value, can
be “wrapped” by creating a Fortran interface which allows the function
to be called directly. A C++ function will require an extern C
function to create an C wrapper to deal with the C++ name mangling.
An example is detailed at NoReturnNoArguments.
Numeric Arguments¶
Integer and floating point numbers are supported by the
interoperabilty with C feature of Fortran 2003. This includes the
integer types short, int, long and long long.
Size specific types int8_t, int16_t, int32_t, and
int64_t are also supported.
Floating point types are float and double.
Note
Fortran has no support for unsigned types.
size_t will be the correct number of bytes, but
will be signed.
In the following examples, int can be replaced by any numeric type.
int argPass a numeric value to C. The attribute
intent(in)is defaulted. The Fortran 2003 attributeVALUEis used to change from Fortran’s default call-by-reference to C’s call-by-value. This argument can be called directly by Fortran and no C wrapper is necessary. See example PassByValue.const int *argScalar call-by-reference.
constpointers are defaulted to+intent(in).int *arg +intent(out)If the intent is to return a scalar value from a function, add the
intent(out)attribute. See example PassByReference.const int *arg +rank(1)The
rank(1)attribute will create an assumed-shape Fortran dimension for the argument asarg(:). The C library function needs to have some way to determine the length of the array. The length could be assumed by the library function. A better option is to add another argument which will explicitly pass the length of the array from Fortran -int larg+implied(size(arg)). An implied argument will not be part of the wrapped API but will still be passed to the C++ function. See example Sum.int *arg +intent(out)+deref(allocatable)+dimension(n)Adds the Fortran attribute
ALLOCATABLEto the argument, then use theALLOCATEstatment to allocate memory using dimension attribute as the shape. See example truncate_to_int.int **arg +intent(out)Return a pointer in an argument. This is converted into a Fortran
POINTERto a scalar. See example getPtrToScalar.int **arg +intent(out)+dimension(ncount)Return a pointer in an argument. This is converted into a Fortran
POINTERto an array by the dimension attribute. See example getPtrToDynamicArray.int **arg +intent(out)+deref(raw)Return a pointer in an argument. The Fortran argument will be a
type(C_PTR). This gives the caller the flexibility to dereference the pointer themselves usingc_f_pointer. This is useful when the shape is not know when the function is called. See example getRawPtrToFixedArray.int ***arg +intent(out)Pointers nested to a deeper level are treated as a Fortran
type(C_PTR)argument. This gives the user the most flexibility. Thetype(C_PTR)can be passed back to to library which should know how to cast it. There is no checks on the pointer before passing it to the library so it’s very easy to pass bad values. The user can also explicitly dereferences the pointers usingc_f_pointer. See example getRawPtrToInt2d.int **arg +intent(in)Multiple levels of indirection are converted into a
type(C_PTR)argument. See below for an exception forchar **. See example checkInt2d.int &min +intent(out)A declaration to a scalar gets converted into pointers in the C wrapper. See example getMinMax.
int *&argReturn a pointer in an argument. From Fortran, this is the same as
int **arg. See above examples.
Numeric Functions¶
int *func()Return a Fortran
POINTERto a scalar. See example returnIntPtrToScalar.int *func() +dimension(10)Return a Fortran
POINTERto an array with a fixed length. See example returnIntPtrToFixedArray.int *func() +deref(scalar)Return a scalar. See example returnIntScalar.
int *ReturnIntPtrDimPointer(int *len+intent(out)+hidden) +dimension(len) +deref(pointer)Return a Fortran
POINTERto an array with a variable length. The length is returned in the argument len. It is marked hidden since it is not required for the Fortran or Python API. The returned array will know its length. See example ReturnIntPtrDimPointer The deref attribute can be changed to return atype(C_PTR),ALLOCATABLEor a scalar. See example ReturnIntPtrDimAlloc
Bool¶
C and C++ functions with a bool argument generate a Fortran wrapper with
a logical argument. One of the goals of Shroud is to produce an
idiomatic interface. Converting the types in the wrapper avoids the
awkwardness of requiring the Fortran user to passing in
.true._c_bool instead of just .true..
Using an integer for a bool argument is not portable since
some compilers use 1 for .true. and others use -1.
bool argNon-pointer arguments default to
intent(IN). See example checkBool.
Char¶
Fortran, C, and C++ each have their own semantics for character variables.
Fortran
charactervariables know their length and are blank filledC
char *variables are assumed to beNULLterminated.C++
std::stringknow their own length and can provide aNULLterminated pointer.
It is not sufficient to pass an address between Fortran and C++ like
it is with other native types. In order to get idiomatic behavior in
the Fortran wrappers it is often necessary to copy the values. This
is to account for blank filled vs NULL terminated.
const char *argCreate a
NULLterminated string in Fortran usingtrim(arg)//C_NULL_CHARand pass to C. Since the argument isconst, it is treated asintent(in). A bufferify function is not required to convert the argument. This is the same aschar *arg+intent(in). See example acceptName.char *argPass a
charpointer to a function which assign to the memory.argmust beNULLterminated by the function. Add the intent(out) attribute. The bufferify function will then blank-fill the string to the length of the FortranCHARACTER(*)argument. It is the users responsibility to avoid overwriting the argument. See example returnOneName.Fortran must provide a CHARACTER argument which is at least as long as the amount that the C function will write into. This includes space for the terminating NULL which will be converted into a blank for Fortran.
char *arg, int largSimilar to above, but pass in the length of
arg. The argumentlargdoes not need to be passed to Fortran explicitly since its value is implied. The implied attribute is defined to use thelenFortran intrinsic to pass the length ofargas the value oflarg:char *arg+intent(out), int larg+implied(len(arg)). See example ImpliedTextLen.char **names +intent(in)This is a standard C idiom for an array of
NULLterminated strings. Shroud takes an array ofCHARACTER(len=*) arg(:)and creates the C data structure by copying the data and adding the terminatingNULL. See example acceptCharArrayIn.char **arg +intent(out)The argument will return the address of a character array which is owned by the library. The user will not need to release the memory. The Fortran wrapper will use a variable with the
POINTERattribute which points to the same memory. The length of the string is based on thestrlenof the argument. See example fetchCharPtrLibrary.
std::string¶
std::string & argargwill default tointent(inout). See example acceptStringReference.
char functions¶
Functions which return a char * provide an additional challenge.
Taken literally they should return a type(C_PTR). And if you call
the C library function via the interface, that’s what you get. However,
Shroud provides several options to provide a more idiomatic usage.
Each of these declaration call identical C++ functions but they are wrapped differently.
char *getConstCharPtrLen(void) +len(30)Create a Fortran function which returns a predefined
CHARACTERvalue. The size is determined by the len argument on the function. This is useful when the maximum size is already known. Works with Fortran 90. See example getConstCharPtrLen.char *getConstCharPtrAlloc(void)Return a pointer and convert into an
ALLOCATABLECHARACTERvariable. Fortran 2003 is required. The Fortran application is responsible to release the memory. However, this may be done automatically by the Fortran runtime. See example getConstCharPtrAlloc.char *getConstCharPtrAsCopyArg(void) +funcarg+deref(copy)Create a Fortran subroutine with an additional
CHARACTERargument for the C function result. Any size character string can be returned limited by the size of the Fortran argument. The argument is defined by the +funcarg(output) format string. If no name is provided with +funcarg then option F_result_as_arg is used. See example getConstCharPtrAsCopyArg.
string functions¶
Functions which return std::string values are similar but must provide the
extra step of converting the result into a char *.
const string &See example getConstStringRefAlloc.
std::vector¶
A std::vector argument for a C++ function can be created from a
Fortran array. The address and size of the array is extracted and
passed to the C wrapper to create the std::vector
const std::vector<int> &argargdefaults tointent(in)since it is const. See example vector_sum.std::vector<int> &argSee example vector_iota_out.
See example vector_iota_out_alloc.
See example vector_iota_inout_alloc.
On intent(in), the std::vector constructor copies the values
from the input pointer. With intent(out), the values are copied
after calling the function.
Note
With intent(out), if vector_iota changes the size of
arg to be longer than the original size of the Fortran
argument, the additional values will not be copied.
Void Pointers¶
The Fortran 2003 stardard added the type(C_PTR) derived type
which is used to hold a C void *.
Fortran is not able to directly dereference type(C_PTR) variables.
The function c_f_pointer must be used.
void *argIf the intent is to be able to pass any variable to the function, add the
+assumedtypeattribute.type(*)is only available with TS 29113. The Fortran wrapper will only accept scalar arguments. To pass an array, add thedimensionattribute See examples passAssumedType and passAssumedTypeDim.void *argPasses the value of a
type(C_PTR)argument. See example passVoidStarStar.void **argUsed to return a
void *from a function in an argument. Passes the address of atype(C_PTR)argument. See example passVoidStarStar.
Function Pointers¶
C or C++ arguments which are pointers to functions are supported.
The function pointer type is wrapped using a Fortran abstract interface.
Only C compatible arguments in the function pointer are supported since
the function will be called by the wrapped library.
To be portable, functions passed to the library must have the BIND(C)
attribute.
int (*incr)(int)Create a Fortran abstract interface for the function pointer. Only functions which match the interface can be used as a dummy argument. See example callback1.
void (*incr)()Adding the funptr attribute will allow any function to be passed. In C this is accomplished by using a cast in the wrapped library.
The intent and value attributes may be used on arguments of the function pointer.
The abstract interface is named from option
F_abstract_interface_subprogram_template which defaults to
{F_name_api}_{argname} where argname is the name of the
function argument.
If the function pointer uses an abstract declarator
(no argument name), the argument name is created from option
F_abstract_interface_argument_template which defaults to
arg{index} where index is the 0-based argument index.
When a name is given to a function pointer argument,
it is always used in the abstract interface.
To change the name of the subprogram or argument, change the option. There are no format fields F_abstract_interface_subprogram or F_abstract_interface_argument since they vary by argument (or argument to an argument):
options:
F_abstract_interface_subprogram_template: custom_funptr
F_abstract_interface_argument_template: XX{index}arg
To allow any function to be passed, the funptr attribute can be
added. This will not use an abstract interface. Instead the
argument will be defined as type(C_FUNPTR) from the
iso_c_binding module. However, it requires the caller to use
C_FUNLOC to pass down the function address. All interface
information is lost and the C library is expected to know how to deal
with arbitrary function pointers.
See example callback1_funptr.
The external attribute can be added to define the argument with
an EXTERNAL statement. This can be made to work for some situations.
However, it is not portable between compilers. The Fortran standard does
not allow EXTERNAL arguments in a bind(C) subprogram.
A Fortran wrapper function is created with an EXTERNAL
declaration for the argument.
The C function is called via an abstract interace with the bind(C) attribute.
Struct¶
See example passStruct1.
See example passStructByValue.