13.13. C and Fortran Bindings
The C and Fortran (mpi_f08) bindings are generated from Python code in
ompi/mpi/bindings. Both the language bindings are generated from
template files for each function. In the C case, each template file corresponds
to a single generated C file, while in the Fortran case there are three major
files generated for all functions.
The Python code depends on special prototype lines used with both the C and Fortran bindings. These “prototypes” are designed to be easy to parse and use specific type constants that can be mapped directly to the expanded language-specific code, error-handling, and conversion code.
13.13.1. C Bindings
This will walk through adding (or converting) a plain-C binding into a templated version controlled by the script.
As an example, for MPI_Send you might have a C file that looks something
like this:
#include "ompi_config.h"
...other includes...
int MPI_Send(const void *buf, int count, MPI_Datatype datatype, int dest,
int tag, MPI_Comm comm)
{
...internal checks...
return internal_mpi_send(buf, count, datatype, dest, tag, comm);
}
To convert this to a template, you will have to first ensure that only a single
function is defined in the file, removing or abstracting out static functions,
and separating multiple definitions, such as MPI_Send and MPI_Isend,
into different files. The template should also not include any macro-processing
that attempts to change the name of the function or parameter types; this code
should be generated by the script, or abstracted into header files that can
work easily with multiple functions.
At this point, the template should look like the example above, with a “header” section, with simple includes or macros, maybe a static global, and the function definition and nothing else.
The next step is to convert the signature line into the prototype format that
the script expects. For MPI_Send, this should look something like this:
PROTOTYPE ERROR_CLASS send(BUFFER buf, COUNT count, DATATYPE type, RANK dest,
TAG tag, COMM comm)
Notice how the function name is changed, the MPI_ prefix removed and the
rest converted to lowercase, and also how each parameter is simplified into a
TYPE name format, where the TYPE conforms to an allowed list in
ompi/mpi/bindings/ompi_bindings/c_type.py. For newer functions and types,
you may have to extend the c_type.py file with a new class showing how to
handle the type.
The final step is to update Makefile.am, adding the template name, in this
case send.c.in, to the prototype_sources variable, and the generated
file name, generated_send.c, to interface_profile_sources. The
generated file name must be of the form generated_${basename}.c, where
${basename} is the name of the template file stripped of all extensions.
13.13.2. Fortran Bindings
Adding new Fortran bindings follows a similar process to the C version above.
All new interfaces are actually based on a single C-template file following the
same format as the C interface templates. However, the C file generated will
use Fortran-specific arguments, including CFI_* arguments, when TS 29113 is
enabled, MPI_Fint * arguments in other cases, and others specific to how
the Fortran MPI types are defined. Most of these files perform Fortran-specific
error handling, Fortran-to-C type conversion, and other necessary steps before
calling the actually C bindings with the proper arguments.
These templates are used not only to generate a C backing file for the Fortran code, but also the Fortran interface definitions and the Fortran subroutines corresponding to the generated C file. These are output in three separate files:
ompi/mpi/fortran/use-mpi-f08/api_f08_generated.F90ompi/mpi/fortran/use-mpi-f08/base/api_f08_generated.compi/mpi/fortran/use-mpi-f08/mod/mpi-f08-interfaces-generated.h
The Fortran file api_f08_generated.F90 contains all the internal subroutine
definitions, each of which makes a call into corresponding C functions. The
internal subroutine names are mapped to the external interface, including
multiple interfaces for the bigcount version of functions, in
mpi-f08-interfaces-generated.h. The C file api_f08_generated.c
basically contains a concatenation of all fully expanded C templates.
These files contain preprocessing directives to ensure they can support
compilers with and without TS 29113 support, allowing use of
CFI_cdesc_t types when available (see Fortran 2018 for more details).
If a new type needs to be added, then one will need to extend
fortran_type.py in ompi/mpi/bindings/ompi_bindings with an additional
type class specifying how to handle the type in the above generated files,
including any required key-value attributes for more complicated types. New
types use a Type base class with functions that can be implemented by
derived classes, each returning expanded Fortran or C code.
13.13.4. Unit-testing the generator
The generator is covered by unit tests in
ompi/test/bindings-generator/test_bindings_generator.py, which run as part of
make check (and therefore in CI). They are plain Python: they import
ompi_bindings straight out of the source tree and render a handful of real
.c.in templates in memory. Nothing is compiled, no MPI is launched, and no
build products are needed, so you can also run them directly against a source
tree that has never been built:
shell$ python3 ompi/test/bindings-generator/test_bindings_generator.py
The tests cover the parts of the generator that are pure and deterministic, and where a defect would otherwise only surface as a compile error in the generated code (or, for a naming or casing mistake, not until run time):
Prototype parameter parsing — the
NAME,NAME:COUNT, andNAME:COUNT:OUTCOUNTforms.Name mangling —
MPI_Xxx/PMPI_Xxx/_cbigcount suffixes, and the_ABI_INTERNALsuffix used to keep the standard ABI names from colliding with Open MPI’s own.Prototype classification — the predicates that decide whether a function gets a bigcount variant or needs user-callback wrappers.
Template rendering — that representative templates render through both the
ompiandstandardABI paths without raising, and that the standard ABI output calls the internalompi_abi_*shim rather than the publicMPI_*symbol.
If you add a new type to the Type hierarchy, a new prototype form, or a new
code-emission path, add a test here as well.
13.13.5. Adding New Fortran Interfaces
Open MPI supports multiple Fortran binding layers beyond the modern use
mpi_f08 interface described above. Adding a new MPI function requires updating
all applicable layers. The MPI standard defines Fortran interfaces for most
functions, and Open MPI implements these across three main Fortran binding
systems. This section describes the complete pattern for adding new Fortran
bindings.
13.13.5.1. The Three Fortran Binding Layers
mpif.h (
ompi/mpi/fortran/mpif-h/) — The original Fortran 77 interface. Functions are hand-written C wrappers that convert between Fortran and C types.use mpi_f08 (
ompi/mpi/fortran/use-mpi-f08/) — The modern Fortran 2008 interface with full type safety. Uses template files (.c.in) processed by the build system to generate type-specific variants. This is the interface described in the main section above.use mpi (ignore TKR) (
ompi/mpi/fortran/use-mpi-ignore-tkr/) — An alternative Fortran 90/95 interface using compiler directives to ignore type/kind/rank checks. Interface declarations are inmpi-ignore-tkr-interfaces.h.in.
13.13.5.2. Checklist for Adding a New Fortran Function
When adding a new MPI function that has Fortran bindings (nearly all functions except C-specific ones), you must update multiple files across the layers. Use existing functions as templates.
13.13.5.2.1. For mpif.h Layer
Create the wrapper: Add
<function_name>_f.cinompi/mpi/fortran/mpif-h/. This file:Includes
ompi_config.hfirstIncludes
ompi/mpi/fortran/mpif-h/bindings.hUses
OMPI_GENERATE_F77_BINDINGSto generate the strongPMPI_*entry points in all name-mangling variantsUses
OMPI_GENERATE_WEAK_F77_BINDINGSto generate weakMPI_*entry points that forward toPMPI_*(on platforms without weak aliases, this emits a weak symbol; where weak aliases exist, the macro inbindings.halready emitted the alias)Defines the wrapper function
ompi_<function_name>_f()Converts Fortran types to C types using
PMPI_Status_f2c(),OMPI_FINT_2_INT(),OMPI_INT_2_FINT(), etc.Calls the C implementation (typically
PMPI_<Function_name>())Must handle
MPI_STATUS_IGNOREand similar special constants
Update Makefile.am: Add the new
.cfile tolib@OMPI_LIBMPI_NAME@_mpifh_la_SOURCESinompi/mpi/fortran/mpif-h/Makefile.am, maintaining alphabetical order.Update prototypes: Add the function prototype to
ompi/mpi/fortran/mpif-h/prototypes_mpi.husing thePN2()macro:PN2(void, MPI_Function_name, mpi_function_name, MPI_FUNCTION_NAME, (MPI_Fint *arg1, MPI_Fint *arg2, MPI_Fint *ierr));
13.13.5.2.2. For use mpi_f08 Layer
Create the template: Add
<function_name>.c.ininompi/mpi/fortran/use-mpi-f08/. This file:Contains a
PROTOTYPEdeclaration (see existing files for syntax)Uses placeholders like
@INNER_CALL@that the build system expandsHandles type conversions for Fortran 2008 types
Manages
MPI_F08_STATUS_IGNOREand similar constants
Update prototype list: Add the template filename to
prototype_filesinompi/mpi/fortran/use-mpi-f08/Makefile.prototype_files, maintaining alphabetical order.
13.13.5.2.3. For use mpi (ignore TKR) Layer
The use mpi (ignore TKR) interface declarations are generated from the
binding metadata, similar to the use mpi_f08 layer. The interface
declarations live in generated .h.in files under
ompi/mpi/fortran/use-mpi-ignore-tkr/.
Ensure the binding metadata is complete: The Python generator in
ompi/mpi/bindings/reads the MPI function signatures and generates interface declarations for all three Fortran layers. If the mpif.h and use mpi_f08 layers are complete, the use mpi layer should be generated automatically.Verify generated interfaces: After building, check that the new function appears in the generated
ompi/mpi/fortran/use-mpi-ignore-tkr/mpi-ignore-tkr-interfaces-generated.hfile with correct!DIR$ IGNORE_TKRdirectives. This file is compiled twice during the build: once withOMPI_BUILD_MPI_PROFILINGdefined to generatePMPI_*interfaces, and once without the define to generateMPI_*interfaces.Check PMPI support: Verify both
MPI_*andPMPI_*interfaces are generated for the new function.
13.13.5.3. Key Conventions for Fortran Bindings
Function naming: The C wrapper in mpif.h uses the prefix
ompi_<function_name>_f(). TheOMPI_GENERATE_F77_BINDINGSmacro provides the strongPMPI_*entry points in various case/underscore combinations (PMPI_FUNCTION_NAME,pmpi_function_name,pmpi_function_name_,pmpi_function_name__). TheOMPI_GENERATE_WEAK_F77_BINDINGSmacro provides weakMPI_*entry points that forward to the strongPMPI_*symbols.Profiling (PMPI) support: All bindings must support the PMPI profiling interface. Open MPI compiles each mpif.h binding exactly once (with
OMPI_BUILD_MPI_PROFILING=1), emitting both the strongPMPI_*entry points and weakMPI_*entry points in a single compilation. Where weak aliases are available (ELF), the weakMPI_*is a zero-cost alias toPMPI_*; on platforms without weak aliases (e.g., macOS), the weakMPI_*is a forwarding definition. Theprofile/subdirectory no longer exists because a second compilation is not necessary.Type conversions: Use the provided macros:
OMPI_INT_2_FINT()/OMPI_FINT_2_INT()for integersOMPI_LOGICAL_2_INT()/OMPI_INT_2_LOGICAL()for logicalsPMPI_Status_f2c()/PMPI_Status_c2f()for MPI_Status
Special constants: Check for Fortran special constants like
OMPI_IS_FORTRAN_STATUS_IGNORE()before dereferencing pointers.Error codes: Always set
*ierr = OMPI_INT_2_FINT(c_ierr)to return errors to Fortran in the correct format.
13.13.5.4. Weak Symbols vs. Weak Aliases
Open MPI distinguishes between weak symbols and weak aliases:
A weak alias is a linker directive (e.g.,
#pragma weak MPI_Send = PMPI_Sendor__attribute__((weak, alias("PMPI_Send")))) that makes one symbol name resolve to another at link time, with zero runtime cost. Weak aliases are supported on ELF platforms (Linux, most Unix) but not on macOS / Mach-O.A weak symbol is a symbol marked with the weak attribute (e.g.,
__attribute__((weak))), which allows it to be overridden by a strong definition at link time. On macOS, a weakMPI_Sendcan be a forwarding function that callsPMPI_Send; this has a trivial runtime cost (one branch instruction) but works everywhere.
Open MPI’s configure terminology and preprocessor macros use “weak alias”
consistently: OPAL_HAVE_WEAK_ALIASES,
__opal_attribute_weak_alias__, --enable-weak-aliases. The plain weak
symbol attribute is __opal_attribute_weak__.
13.13.5.5. Build System Interaction
After adding Fortran bindings, the build system must be regenerated (see the
Open MPI developer documentation on modifying the configure/build system).
Template files (.c.in) are processed during the build to generate multiple
type-specific wrapper functions for the Fortran 2008 interface.
Parameter naming validation: The build system includes
check_fortran_param_names.py which validates that Fortran interface
parameter names comply with the MPI standard. This check runs automatically
during the build for both use mpi_f08 and use mpi layers. If you add
a new function, ensure parameter names match the standard exactly.
Testing: After adding bindings, compile a simple Fortran test program
that uses the new function with each interface (use mpi_f08, use mpi,
and include 'mpif.h') to verify all layers work correctly. Test both the
MPI_* and PMPI_* entry points to verify profiling interface support.
13.13.6. Other Considerations
Keep in mind that the generated files will not be deleted with a make clean
or make distclean; instead use make maintainer-clean to delete those.