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 arg

Pass a numeric value to C. The attribute intent(in) is defaulted. The Fortran 2003 attribute VALUE is 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 *arg

Scalar call-by-reference. const pointers 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 as arg(:). 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 ALLOCATABLE to the argument, then use the ALLOCATE statment 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 POINTER to a scalar. See example getPtrToScalar.

int **arg +intent(out)+dimension(ncount)

Return a pointer in an argument. This is converted into a Fortran POINTER to 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 using c_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. The type(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 using c_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 for char **. See example checkInt2d.

int &min +intent(out)

A declaration to a scalar gets converted into pointers in the C wrapper. See example getMinMax.

int *&arg

Return a pointer in an argument. From Fortran, this is the same as int **arg. See above examples.

Numeric Functions

int *func()

Return a Fortran POINTER to a scalar. See example returnIntPtrToScalar.

int *func() +dimension(10)

Return a Fortran POINTER to 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 POINTER to 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 a type(C_PTR), ALLOCATABLE or 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 arg

Non-pointer arguments default to intent(IN). See example checkBool.

Char

Fortran, C, and C++ each have their own semantics for character variables.

  • Fortran character variables know their length and are blank filled

  • C char * variables are assumed to be NULL terminated.

  • C++ std::string know their own length and can provide a NULL terminated 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 *arg

Create a NULL terminated string in Fortran using trim(arg)//C_NULL_CHAR and pass to C. Since the argument is const, it is treated as intent(in). A bufferify function is not required to convert the argument. This is the same as char *arg+intent(in). See example acceptName.

char *arg

Pass a char pointer to a function which assign to the memory. arg must be NULL terminated by the function. Add the intent(out) attribute. The bufferify function will then blank-fill the string to the length of the Fortran CHARACTER(*) 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 larg

Similar to above, but pass in the length of arg. The argument larg does not need to be passed to Fortran explicitly since its value is implied. The implied attribute is defined to use the len Fortran intrinsic to pass the length of arg as the value of larg: 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 NULL terminated strings. Shroud takes an array of CHARACTER(len=*) arg(:) and creates the C data structure by copying the data and adding the terminating NULL. 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 POINTER attribute which points to the same memory. The length of the string is based on the strlen of the argument. See example fetchCharPtrLibrary.

std::string

std::string & arg

arg will default to intent(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 CHARACTER value. 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 ALLOCATABLE CHARACTER variable. 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 CHARACTER argument 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> &arg

arg defaults to intent(in) since it is const. See example vector_sum.

std::vector<int> &arg

See 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 *arg

If the intent is to be able to pass any variable to the function, add the +assumedtype attribute. type(*) is only available with TS 29113. The Fortran wrapper will only accept scalar arguments. To pass an array, add the dimension attribute See examples passAssumedType and passAssumedTypeDim.

void *arg

Passes the value of a type(C_PTR) argument. See example passVoidStarStar.

void **arg

Used to return a void * from a function in an argument. Passes the address of a type(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.