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.

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:

.. code-block:: c

    #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:

.. code-block:: c

    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.

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.F90``
* ``ompi/mpi/fortran/use-mpi-f08/base/api_f08_generated.c``
* ``ompi/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).

.. _Fortran 2018: https://fortranwiki.org/fortran/show/Fortran+2018

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.

Shared definitions: one source of truth
---------------------------------------

Two different generators emit the MPI Forum (standard) ABI, and they are
driven by different inputs:

* ``bindings.py`` (with the ``ompi_bindings`` package) generates the bindings
  themselves, from the ``.c.in`` templates.
* ``c_header.py`` generates the ABI ``mpi.h``, from ``pympistandard`` plus the
  ABI JSON.

Anything the two must agree on |mdash| the ``_ABI_INTERNAL`` name-mangling
suffix, the opaque handle types, the list of deprecated/removed symbols that
are pruned from the ABI |mdash| therefore lives in
``ompi_bindings/consts.py``, which is the single source of truth.  Do not
define such a value a second time in ``c_header.py``: the two generators would
then be free to drift, and the emitted header would stop matching the emitted
bindings.

The tests described below enforce this, including a check that the deprecated
list does not drift away from the ``__mpi_interface_deprecated__`` and
``__mpi_interface_removed__`` markers in ``ompi/include/mpi.h.in``.

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:

.. code-block:: sh

   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** |mdash| the ``NAME``, ``NAME:COUNT``, and
  ``NAME:COUNT:OUTCOUNT`` forms.
* **Name mangling** |mdash| ``MPI_Xxx`` / ``PMPI_Xxx`` / ``_c`` bigcount
  suffixes, and the ``_ABI_INTERNAL`` suffix used to keep the standard ABI
  names from colliding with Open MPI's own.
* **Prototype classification** |mdash| the predicates that decide whether a
  function gets a bigcount variant or needs user-callback wrappers.
* **Template rendering** |mdash| that representative templates render through
  *both* the ``ompi`` and ``standard`` ABI paths without raising, and that the
  standard ABI output calls the internal ``ompi_abi_*`` shim rather than the
  public ``MPI_*`` 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.

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.

The Three Fortran Binding Layers
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

1. **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.

2. **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.

3. **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 in
   ``mpi-ignore-tkr-interfaces.h.in``.

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.

For mpif.h Layer
""""""""""""""""

1. **Create the wrapper:** Add ``<function_name>_f.c`` in
   ``ompi/mpi/fortran/mpif-h/``. This file:

   * Includes ``ompi_config.h`` first
   * Includes ``ompi/mpi/fortran/mpif-h/bindings.h``
   * Uses ``OMPI_GENERATE_F77_BINDINGS`` to generate the strong ``PMPI_*``
     entry points in all name-mangling variants
   * Uses ``OMPI_GENERATE_WEAK_F77_BINDINGS`` to generate weak ``MPI_*``
     entry points that forward to ``PMPI_*`` (on platforms without weak
     aliases, this emits a weak symbol; where weak aliases exist, the
     macro in ``bindings.h`` already 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_IGNORE`` and similar special constants

2. **Update Makefile.am:** Add the new ``.c`` file to
   ``lib@OMPI_LIBMPI_NAME@_mpifh_la_SOURCES`` in
   ``ompi/mpi/fortran/mpif-h/Makefile.am``, maintaining alphabetical order.

3. **Update prototypes:** Add the function prototype to
   ``ompi/mpi/fortran/mpif-h/prototypes_mpi.h`` using the ``PN2()`` macro:

   .. code-block:: c

      PN2(void, MPI_Function_name, mpi_function_name, MPI_FUNCTION_NAME,
          (MPI_Fint *arg1, MPI_Fint *arg2, MPI_Fint *ierr));

For use mpi_f08 Layer
""""""""""""""""""""""

1. **Create the template:** Add ``<function_name>.c.in`` in
   ``ompi/mpi/fortran/use-mpi-f08/``. This file:

   * Contains a ``PROTOTYPE`` declaration (see existing files for syntax)
   * Uses placeholders like ``@INNER_CALL@`` that the build system expands
   * Handles type conversions for Fortran 2008 types
   * Manages ``MPI_F08_STATUS_IGNORE`` and similar constants

2. **Update prototype list:** Add the template filename to
   ``prototype_files`` in
   ``ompi/mpi/fortran/use-mpi-f08/Makefile.prototype_files``, maintaining
   alphabetical order.

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/``.

1. **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.

2. **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.h`` file
   with correct ``!DIR$ IGNORE_TKR`` directives. This file is compiled twice
   during the build: once with ``OMPI_BUILD_MPI_PROFILING`` defined to
   generate ``PMPI_*`` interfaces, and once without the define to generate
   ``MPI_*`` interfaces.

3. **Check PMPI support:** Verify both ``MPI_*`` and ``PMPI_*`` interfaces
   are generated for the new function.

Key Conventions for Fortran Bindings
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

* **Function naming:** The C wrapper in mpif.h uses the prefix
  ``ompi_<function_name>_f()``. The ``OMPI_GENERATE_F77_BINDINGS`` macro
  provides the strong ``PMPI_*`` entry points in various case/underscore
  combinations (``PMPI_FUNCTION_NAME``, ``pmpi_function_name``,
  ``pmpi_function_name_``, ``pmpi_function_name__``). The
  ``OMPI_GENERATE_WEAK_F77_BINDINGS`` macro provides weak ``MPI_*`` entry
  points that forward to the strong ``PMPI_*`` 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 strong
  ``PMPI_*`` entry points and weak ``MPI_*`` entry points in a single
  compilation. Where weak aliases are available (ELF), the weak ``MPI_*``
  is a zero-cost alias to ``PMPI_*``; on platforms without weak aliases
  (e.g., macOS), the weak ``MPI_*`` is a forwarding definition. The
  ``profile/`` 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 integers
  * ``OMPI_LOGICAL_2_INT()`` / ``OMPI_INT_2_LOGICAL()`` for logicals
  * ``PMPI_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.

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_Send`` or ``__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 weak ``MPI_Send`` can be a forwarding
  function that calls ``PMPI_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__``.

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.

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.
