Preprocessing

Shroud can insert preprocessing directives into the generated source to implement conditional compilation. This allows the wrapper to be generated once, and the source distributed, then compiled to include only the features available. For example, with or without MPI.

Most Fortran compiles have an option to use a variant of the C preprocessor before compiling the source. To aid portability, only #if and #endif are added to the Fortran source.

It may be useful to set the option F_filename_suffix to F. This will cause most compilers to process the Fortran souce with cpp before compilation. The alternative is to pass a flag explicit to the compiler such as -fpp for intel or -cpp for gfortran.

The fortran_header field can be added to the YAML file to insert #include directives at the top of the Fortran source files.

The main feature in Shroud is the cpp_if field for functions and types. But the user is always free to add explicit preprocessing directives via a splicer block.

Functions

- decl: void testmpi(MPI_Comm comm)
  format:
    function_suffix: _mpi
  cpp_if: ifdef HAVE_MPI
- decl: void testmpi()
  format:
    function_suffix: _serial
  cpp_if: ifndef HAVE_MPI

The function wrappers will be created within #ifdef/#endif directives. This includes the C wrapper, the Fortran interface and the Fortran wrapper. The generated Fortran interface will be:

    interface testmpi
#ifdef HAVE_MPI
        module procedure testmpi_mpi
#endif
#ifndef HAVE_MPI
        module procedure testmpi_serial
#endif
    end interface testmpi

Class generic type-bound function will also insert conditional compilation directives:

- decl: class ExClass3
  cpp_if: ifdef USE_CLASS3
  declarations:
  - decl: void exfunc()
    cpp_if: ifdef USE_CLASS3_A
  - decl: void exfunc(int flag)
    cpp_if: ifndef USE_CLASS3_A

The generated type will be:

    type exclass3
        type(SHROUD_capsule_data), private :: cxxmem
    contains
        procedure :: exfunc_0 => exclass3_exfunc_0
        procedure :: exfunc_1 => exclass3_exfunc_1
#ifdef USE_CLASS3_A
        generic :: exfunc => exfunc_0
#endif
#ifndef USE_CLASS3_A
        generic :: exfunc => exfunc_1
#endif
    end type exclass3

A cpp_if field in a class will add a conditional directive around the entire class.

Finally, cpp_if can be used with types. This would be required in the first example since mpi.h should only be included when USE_MPI is defined:

typemaps:
- type: MPI_Comm
  fields:
    cpp_if: ifdef USE_MPI

The typemaps field can only appear at the outermost layer and is used to augment existing typemaps.