Updated ABI generation code and new libraries - #13280
Conversation
8fbf968 to
29b1a2f
Compare
da515d4 to
340e7ad
Compare
|
Maybe you should somehow vendor the In short, I think it would be in everyone's convenience to use https://github.com/mpi-forum/mpi-abi-stubs as the "source of truth" for ABI-related stuff, avoiding manual synchronization of handle/constant values. |
a9b105c to
cefbde8
Compare
|
I wonder if we should make the bot not complain about unsigned commits on draft PRs. That would reduce some of the noise on PR's like this. |
cefbde8 to
d5663f7
Compare
Turns out that in commit 6bd36a7 we had a function that is not part of the MPI standard. This showed while working on ABI support - which requires us to pay attention to the truth rather than make stuff up. This commit removes our made up MPI_Session_set_info method. Turns out who ever was doing the fortran bindings knew this wasn't a method in the standard so there's no need to change the fortran bindings. Same thing applies to the man pages. Related to open-mpi#13280 Signed-off-by: Howard Pritchard <howardp@lanl.gov>
65e34c9 to
bd2710f
Compare
|
@hppritcha There is some issue with out-of-source builds, i.e |
|
interesting distcheck didn't check this. |
|
jenkins ci runs make distcheck |
|
The ABI mpi.h header is missing some MPI_T_XXX types. Also, the Status f08/c converters are declared, and they should not. I did the following manual edits to the installed mpi.h header: diff -up ./mpi.h.orig ./mpi.h
--- ./mpi.h.orig 2025-08-28 18:55:49.842968779 +0300
+++ ./mpi.h 2025-08-28 19:03:07.192957305 +0300
@@ -490,6 +490,13 @@ enum {
/* C preprocessor constants and Fortran parameters */
/* $CATEGORY:C_PREPROCESSOR_CONSTANTS_FORTRAN_PARAMETERS$ */
+typedef struct MPI_T_enum_t* MPI_T_enum;
+typedef struct MPI_T_cvar_handle_t* MPI_T_cvar_handle;
+typedef struct MPI_T_pvar_handle_t* MPI_T_pvar_handle;
+typedef struct MPI_T_pvar_session_t* MPI_T_pvar_session;
+typedef struct MPI_T_event_registration_t* MPI_T_event_registration;
+typedef struct MPI_T_event_instance_t* MPI_T_event_instance;
+
/* Handles used in the MPI tool information interface */
#define MPI_T_ENUM_NULL ((MPI_T_enum) 0)
#define MPI_T_CVAR_HANDLE_NULL ((MPI_T_cvar_handle) 0)
@@ -558,20 +565,20 @@ enum {
};
/* Source event ordering guarantees in the MPI tool information interface */
-enum {
+typedef enum MPI_T_source_order {
MPI_T_SOURCE_ORDERED = 1,
MPI_T_SOURCE_UNORDERED = 2,
-};
+} MPI_T_source_order;
/*
* Callback safety requirement levels used in the MPI tool information interface
*/
-enum {
+typedef enum MPI_T_cb_safety {
MPI_T_CB_REQUIRE_NONE = 0x00,
MPI_T_CB_REQUIRE_MPI_RESTRICTED = 0x03,
MPI_T_CB_REQUIRE_THREAD_SAFE = 0x0F,
MPI_T_CB_REQUIRE_ASYNC_SIGNAL_SAFE = 0x3F,
-};
+} MPI_T_cb_safety;
/* Callback functions */
@@ -1107,13 +1114,13 @@ int MPI_Ssend_init(const void* buf, int
int MPI_Ssend_init_c(const void* buf, MPI_Count count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request* request);
int MPI_Start(MPI_Request* request);
int MPI_Startall(int count, MPI_Request array_of_requests[]);
-/* int MPI_Status_c2f(const MPI_Status* c_status, MPI_Fint* f_status);
- */int MPI_Status_c2f08(const MPI_Status* c_status, MPI_F08_status* f08_status);
-int MPI_Status_f082c(const MPI_F08_status* f08_status, MPI_Status* c_status);
-/* int MPI_Status_f082f(const MPI_F08_status* f08_status, MPI_Fint* f_status);
- *//* int MPI_Status_f2c(const MPI_Fint* f_status, MPI_Status* c_status);
- *//* int MPI_Status_f2f08(const MPI_Fint* f_status, MPI_F08_status* f08_status);
- */int MPI_Status_get_error(const MPI_Status* status, int* err);
+// /* int MPI_Status_c2f(const MPI_Status* c_status, MPI_Fint* f_status);
+// */int MPI_Status_c2f08(const MPI_Status* c_status, MPI_F08_status* f08_status);
+// int MPI_Status_f082c(const MPI_F08_status* f08_status, MPI_Status* c_status);
+// /* int MPI_Status_f082f(const MPI_F08_status* f08_status, MPI_Fint* f_status);
+// *//* int MPI_Status_f2c(const MPI_Fint* f_status, MPI_Status* c_status);
+// *//* int MPI_Status_f2f08(const MPI_Fint* f_status, MPI_F08_status* f08_status);
+// */int MPI_Status_get_error(const MPI_Status* status, int* err);
int MPI_Status_get_source(const MPI_Status* status, int* source);
int MPI_Status_get_tag(const MPI_Status* status, int* tag);
int MPI_Status_set_cancelled(MPI_Status* status, int flag);
@@ -1799,13 +1806,13 @@ int PMPI_Ssend_init(const void* buf, int
int PMPI_Ssend_init_c(const void* buf, MPI_Count count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request* request);
int PMPI_Start(MPI_Request* request);
int PMPI_Startall(int count, MPI_Request array_of_requests[]);
-/* int PMPI_Status_c2f(const MPI_Status* c_status, MPI_Fint* f_status);
- */int PMPI_Status_c2f08(const MPI_Status* c_status, MPI_F08_status* f08_status);
-int PMPI_Status_f082c(const MPI_F08_status* f08_status, MPI_Status* c_status);
-/* int PMPI_Status_f082f(const MPI_F08_status* f08_status, MPI_Fint* f_status);
- *//* int PMPI_Status_f2c(const MPI_Fint* f_status, MPI_Status* c_status);
- *//* int PMPI_Status_f2f08(const MPI_Fint* f_status, MPI_F08_status* f08_status);
- */int PMPI_Status_get_error(const MPI_Status* status, int* err);
+// /* int PMPI_Status_c2f(const MPI_Status* c_status, MPI_Fint* f_status);
+// */int PMPI_Status_c2f08(const MPI_Status* c_status, MPI_F08_status* f08_status);
+// int PMPI_Status_f082c(const MPI_F08_status* f08_status, MPI_Status* c_status);
+// /* int PMPI_Status_f082f(const MPI_F08_status* f08_status, MPI_Fint* f_status);
+// *//* int PMPI_Status_f2c(const MPI_Fint* f_status, MPI_Status* c_status);
+// *//* int PMPI_Status_f2f08(const MPI_Fint* f_status, MPI_F08_status* f08_status);
+// */int PMPI_Status_get_error(const MPI_Status* status, int* err);
int PMPI_Status_get_source(const MPI_Status* status, int* source);
int PMPI_Status_get_tag(const MPI_Status* status, int* tag);
int PMPI_Status_set_cancelled(MPI_Status* status, int flag);I'm able to compile (using |
|
@hppritcha Actually, take a look at mpi-forum/mpi-abi-stubs#63 |
5377de6 to
04ff2ff
Compare
|
The installed $ mpicc_abi helloworld.c
$ mpiexec -n 1 ./a.out
[optiplex:00000] *** An error occurred in MPI_Init_thread
[optiplex:00000] *** reported by process [3633774593,0]
[optiplex:00000] *** on a NULL communicator
[optiplex:00000] *** MPI_ERR_ARG: invalid argument of some other kind
[optiplex:00000] *** MPI_ERRORS_ARE_FATAL (processes in this communicator will now abort,
[optiplex:00000] *** and MPI will try to terminate your MPI job as well)
--------------------------------------------------------------------------
prterun has exited due to process rank 0 with PID 0 on node optiplex calling
"abort". This may have caused other processes in the application to be
terminated by signals sent by prterun (as reported here).
-------------------------------------------------------------------------- |
|
@hppritcha The following definitions in the generated /* Predefined functions */
#define MPI_COMM_NULL_COPY_FN ((MPI_Comm_copy_attr_function) 0)
#define MPI_COMM_DUP_FN ((MPI_Comm_copy_attr_function) 1)
#define MPI_COMM_NULL_DELETE_FN ((MPI_Comm_delete_attr_function) 0)
#define MPI_WIN_NULL_COPY_FN ((MPI_Win_copy_attr_function) 0)
#define MPI_WIN_DUP_FN ((MPI_Win_copy_attr_function) 1)
#define MPI_WIN_NULL_DELETE_FN ((MPI_Win_delete_attr_function) 0)
#define MPI_TYPE_NULL_COPY_FN ((MPI_Type_copy_attr_function) 0)
#define MPI_TYPE_DUP_FN ((MPI_Type_copy_attr_function) 1)
#define MPI_TYPE_NULL_DELETE_FN ((MPI_Type_delete_attr_function) 0)
#define MPI_CONVERSION_FN_NULL ((MPI_Datarep_conversion_function) 0)
#define MPI_CONVERSION_FN_NULL_C ((MPI_Datarep_conversion_function_c) 0)
/* Deprecated predefined functions */
#define MPI_NULL_COPY_FN ((MPI_Copy_function) 0)
#define MPI_DUP_FN ((MPI_Copy_function) 1)
#define MPI_NULL_DELETE_FN ((MPI_Delete_function) 0) |
|
PS: You may have a similar problems in some |
|
@hppritcha What's your plan for stuff introduced in MPI 4.1 and MPI 5.0? The generated mpi.h header says This is a list of what I managed to detect as missing from mpi4py's configuration machinery for missing MPI stuff. |
|
Current status regarding mpi4py:
|
|
Thanks for checking this stuff out in its early state @dalcinl. some of the above functions have been implemented but are sitting in various states in PRs. some of these should be defined - like We still need to add some plumbing in the ompi internals for callbacks. that will come in as part of this PR. The NERSC folks would really like ABI working for Doudna so to the extent there's a "plan" it would be nice to get this working sooner than later. |
|
Minor nit: Do you really need/want to install the |
|
Two external MPI libraries are now created: libmpi.la and libmpi_abi.la. Backend code that was originally in libmpi.la has been extracted into libopen_mpi.la, which is installed and linked into both front-end libraries. MCA components and the tests that reference internal OMPI symbols link libopen_mpi explicitly, since the linker does not always pull it in transitively. Parts of the Open MPI C interface are now generated for both the Open MPI ABI and the MPI standard ABI from the same source templates, including new bigcount interfaces. The generation is part of the bindings framework used for Big Count (ompi/mpi/bindings/). To compile standard ABI code, there is a new mpicc_abi compiler wrapper, and pkg-config files (ompi-abi.pc, ompi-abi-c.pc, ompi-abi-cxx.pc) are installed for building against the standard ABI without the wrapper. libmpi_abi carries its own SO version, set by convention across MPI implementations (the MPI standard ABI intentionally does not mandate an SONAME), so that an application can switch between implementations of a given ABI version without recompiling. Signed-off-by: Jake Tronge <jtronge@lanl.gov> Signed-off-by: Howard Pritchard <howardp@lanl.gov> Co-authored-by: Howard Pritchard <howardp@lanl.gov> Signed-off-by: Jeff Squyres <jeff@squyres.com>
This mod switches from using "synthetic" defined values and handles to the ones specified in the MPI 5.1 standard, and bumps the MPI standard version reported by Open MPI to 5.0. The python infrastructure included here generates a "canonical" MPI standard ABI compatible mpi.h using two json files: 1) mpi-standard-abi.json 2) mpi-standard-apis.json 2 is generated as part of building the MPI standard. We import that into our project for use in generating both the mpi.h as well as interface definitions in the man pages. 1 is generated using a separate script that processes the tables in Appendix A of the standard. Ideally this script will be merged into the MPI standard code base at some point. This script is currently at https://github.com/Joe-Downs/mpi-standard/tree/pr/handle-constant-tool/const-tool . It is used to generate the portion of mpi.h where defined values and handles are specified. This commit also enables generation of the abi interfaces and header files by default. Signed-off-by: Joseph Downs <joe.downs@lanl.gov> Co-authored-by: Howard Pritchard <howardp@lanl.gov> Signed-off-by: Jeff Squyres <jeff@squyres.com>
Fill in the parts of the C API surface that the initial standard-ABI work left out: * Handle converter functions. Generate MPI_<Class>_toint() and MPI_<Class>_fromint() for every handle type, in both Open MPI ABI and standard ABI variants, with man pages for each. Support machinery for converting handles that cross the ABI boundary inside callbacks is added to the errhandler, attribute, and op back-ends (a datatype converter function pointer on ompi_op_t, an errhandler converter typedef, and attribute-keyval ABI support). * MPI_T. Convert the MPI_T tool interface sources to generated templates so that libmpi_abi gets standard-ABI MPI_T bindings (mpi/tool/libmpi_mpit_abi.la). * MPI_ERR_ABI. Add the new error class mandated by the ABI chapter, including its Fortran value and man page documentation. * Add the MPI_ABI_VERSION macro to the Open MPI ABI mpi.h. See the discussion at mpi-forum/mpi-issues#1098 * Map optional Fortran COMPLEX datatypes without a Fortran counterpart to OMPI_DATATYPE_MPI_UNAVAILABLE in the internal datatype tables. Fix MPI_Type_size_c to return the full size for big-count datatypes: the type_size.c.in template was unconditionally casting the datatype size to (int) regardless of whether it was generating MPI_Type_size() or MPI_Type_size_c(), truncating sizes larger than INT_MAX. Also fix several correctness bugs found while reviewing this work: * MPI_Request_toint raised MPI_ERR_FILE (a copy-paste from the file converter) instead of MPI_ERR_REQUEST for a NULL request. * Four consecutive entries in the c_header.py DEPRECATED_FUNCTIONS list were missing commas, so Python implicit string concatenation fused them into one token and MPI_DUP_FN, MPI_NULL_COPY_FN, MPI_NULL_DELETE_FN, and MPI_Attr_delete were emitted uncommented into the generated standard-ABI mpi.h. * For DATATYPE_ARRAY_ASYNC and NEIGHBOR_DATATYPE_ARRAY_ASYNC bindings, the converted-datatype temporary array was only freed (or handed to the request) inside the "request still in flight" guard; on every other outcome the array was leaked. * On MPI_Isendrecv_replace's temporary-buffer allocation-failure path, rc was left at MPI_SUCCESS, so the call reported success while *request was never assigned. * Remove a dead "free(helper)" statement placed after the return in the Win delete-attribute wrapper; the helper is already freed by ompi_attribute_keyval_destruct(), so executing the statement would be a double free. Signed-off-by: Howard Pritchard <howardp@lanl.gov> Co-authored-by: Lisandro Dalcin <dalcinl@gmail.com> Co-authored-by: Jeff Squyres <jeff@squyres.com> Signed-off-by: Jeff Squyres <jeff@squyres.com>
Implement the MPI_Abi_* function family from the MPI-5 ABI chapter -- MPI_Abi_get_version, MPI_Abi_get_info, MPI_Abi_get_fortran_info, MPI_Abi_get_fortran_booleans, MPI_Abi_set_fortran_booleans, and MPI_Abi_set_fortran_info -- with C bindings for both libraries, mpif.h and use-mpi-f08 Fortran bindings, man pages, and a make-check unit test for the Fortran-boolean back-end (test/class/ompi_abi_fortran). The default Fortran logical size requires special handling in MPI_Abi_get_fortran_booleans, and the .FALSE. value is now probed coherently with the .TRUE. value: the configure cache-invalidation guard unconditionally unset ompi_cv_fortran_false_value whenever it was "0" -- but 0 is the valid Fortran .FALSE. value on every compiler. Since the .FALSE. value is computed in an AC_CACHE_CHECK keyed on the .TRUE. cache variable, a cached reconfigure left OMPI_FORTRAN_VALUE_FALSE defined to an empty token. Invalidate both cache variables together so they stay coherent. The ompi_abi_get/set_fortran_booleans back-end validates logical_size symmetrically in all builds: a logical_size that is not a power of two returns MPI_ERR_ARG, as the man pages document. The user_logicals[] index is computed by scanning a well-defined bit range with opal_hibit() and bounds-checking the result before it is used, and the 128-bit local declarations use the correct HAVE_INT128_T macro. The man pages document the two constraints the implementation enforces -- logical_size must be a power of two (MPI_ERR_ARG otherwise), and MPI_Abi_set_fortran_booleans may be called at most once (MPI_ERR_ABI on a subsequent call) -- and use the correct parameter names and directions for each binding. Signed-off-by: Howard Pritchard <howardp@lanl.gov> Co-authored-by: Jeff Squyres <jeff@squyres.com> Signed-off-by: Jeff Squyres <jeff@squyres.com>
libopen_mpi is the lower layer, and libmpi / libmpi_abi are the thin front-ends above it. libopen_mpi must therefore never reference the public MPI_* / PMPI_* / MPIX_* / PMPIX_* entry points or the OMPI_* extensions, all of which are defined in the layer above; doing so creates a circular library dependency. Remove the remaining upward references from back-end code: * Add ompi_wtime(), an internal, profiling-neutral equivalent of MPI_Wtime() that uses the same time origin, and call it from the back-end and component code (libnbc, ompio, fcoll, fault-tolerance timing loops) that previously called MPI_Wtime()/PMPI_Wtime(). * Register MPI extension initialization via a callback function pointer handed down from the bindings layer instead of calling up into ompi/mpiext from ompi_instance. * Drop dead MPI_* usage from the comm_method hook. Then enforce the rule: * config/ompi_setup_layering_checks.m4 probes for a linker flag that makes an unresolved symbol in a shared library a hard error and adds it to libopen_mpi's LDFLAGS, so a layering violation fails at link time on platforms whose linker supports it. The --no-undefined probe is skipped on FreeBSD: there the environ global is provided by the executable's C runtime startup objects (crt1.o/Scrt1.o) rather than libc.so, so shared libraries legitimately reference an undefined environ and --no-undefined would break the build. FreeBSD relies on the nm-based audit below instead (as macOS already does). * config/ompi_check_layering.sh is the authoritative nm-based audit, run from an all-local hook after libopen_mpi is built. It also covers static builds -- which have no link step at all -- and still fires if someone "fixes" a link error by putting libmpi on libopen_mpi's link line, which is precisely the regression being guarded against. Signed-off-by: Howard Pritchard <howardp@lanl.gov> Co-authored-by: Jeff Squyres <jeff@squyres.com> Signed-off-by: Jeff Squyres <jeff@squyres.com>
Open MPI builds two C libraries from the same sources: the traditional
library (libmpi, MPI_MAX_OBJECT_NAME == OPAL_MAX_OBJECT_NAME == 64) and
the standard-ABI library (libmpi_abi, MPI_MAX_OBJECT_NAME == 128, the
value mandated by the MPI Forum ABI). The internal object-name storage
for communicators, datatypes, and windows was sized to the traditional
64-byte limit, which is too small for the standard-ABI build and led to
two distinct defects:
1. Heap overflow. In the standard-ABI binding, the generated
MPI_Type_set_name bounded its memset()/copy with the
@MPI_MAX_OBJECT_NAME@ template token, which expands to 128, while
ompi_datatype_t.name[] was char[64]. Every call wrote 128 bytes
into a 64-byte field and corrupted the adjacent object, surfacing
later as a "free(): invalid pointer" abort in MPI_Type_free.
2. Lost conformance. Even with a safe bound, a 64-byte field cannot
hold the full-length names that a standard-ABI application is
entitled to set (up to 128 bytes), so such names would be silently
truncated below what the Forum ABI promises.
Resolve both by storing object names at the ABI maximum everywhere
internally, while preserving the long-standing 64-byte limit on the
traditional Open MPI entry points:
* Introduce OMPI_MPI_MAX_OBJECT_NAME_ABI. It is extracted at
configure time from docs/mpi-standard-abi.json -- the same JSON that
the C binding generator already consumes to emit
MPI_MAX_OBJECT_NAME_ABI_INTERNAL -- so the value has a single source
of truth. The new config/ompi_get_forum_abi_values.m4 macro
(OMPI_GET_FORUM_ABI_VALUES) reads it with the configure-selected
Python (AC_REQUIRE([AM_PATH_PYTHON])), using .get() chaining so the
one-liner contains no square brackets for m4 to consume, and
AC_DEFINEs it into opal_config.h.
* Size ompi_datatype_t.name[], ompi_win_t.w_name[], and the
communicator c_name allocation to OMPI_MPI_MAX_OBJECT_NAME_ABI so
the storage can always hold a full-length ABI name regardless of
which library is being built.
* Use OMPI_MPI_MAX_OBJECT_NAME_ABI for all internal name writes --
automatic communicator naming, datatype duplication/creation, and
the FT/DPM bookkeeping paths -- so nothing internal computes against
the smaller bound.
* Keep the entry points asymmetric and explicit: the traditional
MPI_{Comm,Type,Win}_{set,get}_name continue to honor
OPAL_MAX_OBJECT_NAME (64), while the standard-ABI entry points honor
the Forum ABI maximum (128). The set_name paths pre-truncate the
caller's string into a correctly sized buffer before storing, so an
over-long name is truncated safely (as the standard requires)
instead of overrunning.
* Update ompi/include/ompi/memchecker.h to annotate the full
ABI-sized storage, and correct the communicator annotation, which
now describes a heap pointer rather than an inline array.
Documentation: the man pages for all six MPI_{Comm,Type,Win}_{set,get}_
name functions now describe the Open MPI (64) versus Forum ABI (128)
limits using Sphinx substitutions (|ompi_max_object_name| and
|mpi_abi_max_object_name|) computed in docs/conf.py from opal_config.h
and the standard JSON, so the documented values always track the build.
The accompanying ABI-length round-trip tests are added in a separate
commit.
Signed-off-by: Jeff Squyres <jeff@squyres.com>
Co-authored-by: Jeff Squyres <jeff@squyres.com>
Open MPI now builds a standard-ABI C library (libmpi_abi) alongside its traditional library, together with an mpicc_abi wrapper and a standard ABI header. That ABI layer is a distinct surface: it exposes the MPI Forum ABI header and constants, advertises ABI include and link paths through its wrapper, translates between standard ABI integer handle/sentinel values and Open MPI's internal handle representation, and forwards public MPI_* calls into the existing implementation. None of that was covered by Open MPI's general MPI correctness tests, which exercise the traditional library and assume the implementation beneath the ABI layer is already tested. This adds a dedicated test suite under ompi/test/mpi-abi/ that checks the ABI-facing surface from several directions -- metadata authority, installed artifacts, symbol reachability, handle translation, complete public-API call paths, callback conversion, and cross-implementation compatibility -- without re-testing the underlying MPI algorithms. Passing these tests does not prove every underlying MPI algorithm is correct; it proves the ABI surface is consistent with the standard ABI metadata derived from the MPI standard and can drive the already-tested Open MPI implementation through the ABI path. The runner is a Python program (mpi_abi_tests.py) split across sibling _abi_*.py modules for discovery, manifest, probe generation, fast checks, installed checks, cross-implementation checks, lookup tables, and reporting. Every module, template, and generated test case is listed in EXTRA_DIST so VPATH and distribution-tarball builds can import and run the suite from a read-only source tree; the runner is invoked with "python -B" so it never writes __pycache__ next to the modules in the source tree. Probe bodies are generated from .cbody.in and .prologue.in templates, and each logical probe is compiled into its own executable because MPI process state is undefined after many runtime failures. Reports are written as JSON and text into mode-specific build-tree directories. The suite is wired into Automake so its checks run in CI, and it remains Python 3.7 compatible like the rest of Open MPI's Python tooling. A new top-level requirements.txt unions the per-area docs/requirements.txt and ompi/test/mpi-abi/requirements.txt files, so installing that one file provides every Python package needed both to build the documentation and man pages with Sphinx and to run all of the MPI ABI checks. Three make targets drive the suite, each with different prerequisites and its own results directory: * "make check" runs the fast metadata, manifest, and source checks (the runner's check-fast mode, reached through check-local). These run entirely from the source and build trees and require neither an installed Open MPI nor mpicc_abi nor mpirun, so they are safe in any build environment and participate in the normal recursive make check. They compare the MPI-standard-derived ABI metadata under docs/ against the runner's manifest, classification rules, generated-source contracts, C header constants, and Fortran helper source contracts, catching drift between the ABI description and what the suite believes is implemented, skipped, or still uncovered before anything is installed or launched. Output goes to check-results/. * "make check-abi" runs the installed standard ABI checks against an installed Open MPI. It uses the installed mpicc_abi wrapper, the installed standard ABI header, and installed mpirun, expected on PATH unless overridden by the OMPI_ABI_TEST_* environment or make variables. It verifies that the wrapper advertises the ABI include and link paths, that the installed header declares exactly the implemented standard ABI C APIs with signatures matching the binding metadata (and does not declare non-ABI APIs), and that the ABI library exports the expected MPI_* / PMPI_* symbols. It then exercises the ABI helper conversion functions (MPI_Comm_toint / _fromint, MPI_Type_toint, and their PMPI forms) by round-tripping predefined, null, and dynamic handles, status sentinels, error classes, keyval sentinels, and configured datatype constants; runs real MPI programs built with mpicc_abi and launched with mpirun that validate return codes, output handles, statuses, counts, data movement, object state, request completion, RMA, and MPI-IO results through the ABI entry points; isolates callback and retained-lifetime probes so one callback failure cannot poison other probes; and runs Fortran binding regression checks. Open MPI does not yet provide an ABI-capable Fortran wrapper, so the Fortran checks deliberately record current behavior -- for example MPI_Abi_get_version reporting -1, -1 -- rather than claiming MPI-5 Fortran ABI coverage. That absence is an intentional wait-and-see decision whose rationale is documented in docs/building-apps/mpi-forum-abi.rst. Output goes to check-abi-results/. * "make check-abi-mpich" runs the optional cross-implementation compatibility checks against MPICH, and is the most demanding target. It requires both an installed Open MPI with standard ABI support and an installed MPICH built with MPI Forum ABI support (for MPICH 5.0.x, configured with --enable-mpi-abi so it installs mpicc_abi, mpi_abi.h, and libmpi_abi). MPICH's normal internal ABI is not the MPI Forum ABI, and neither implementation's plain mpicc is a substitute, so the runner discovers and classifies the MPI Forum ABI wrappers and launchers before selecting them; explicit MPICH_ABI_TEST_* and OMPI_ABI_TEST_* overrides are honored as operator intent and validated rather than silently falling back to another tool on PATH. Because invoking this target is an explicit request for compatibility results, missing or invalid prerequisites are reported as failures, not skips. The target records both ABI directions -- compile with MPICH and run against Open MPI's ABI runtime, and compile with Open MPI's mpicc_abi and run against MPICH -- after first compiling and launching a one-rank MPI_Init / MPI_Finalize sanity program with each implementation's own wrapper, launcher, and ABI library so that broken local launchers are not misreported as ABI mismatches. For each cross-direction executable it sanitizes the platform runtime library path (LD_LIBRARY_PATH on Linux; DYLD_LIBRARY_PATH plus rewriting the embedded ABI dylib load commands on macOS) so a binary compiled against one implementation cannot load a stale libmpi from the shell environment at run time, and it applies MPICH transport defaults (FI_PROVIDER=tcp with a non-loopback, non-tunnel IPv4 interface for ch4:ofi builds; UCX_TLS=self,sm for ch4:ucx builds) for local one- and two-rank jobs. It treats libmpi_abi as the sole MPI Forum ABI library per MPI-5.0 section 21.2.1 and validates the PMPI alternate entry points required by section 16.2.1 as symbols and as calls through libmpi_abi. Output goes to check-abi-mpich-results/. The check-abi and check-abi-mpich targets are also defined at the top of the tree, where they recurse into ompi/test/mpi-abi for the OMPI project and otherwise print a SKIP message. All three targets additionally skip cleanly when configure did not find a usable Python. Signed-off-by: Jeff Squyres <jeff@squyres.com> Co-authored-by: Howard Pritchard <howardp@lanl.gov>
Open MPI v6.0.0 adds support for the MPI Forum (standard) ABI defined
by MPI-5.0 for C applications, alongside Open MPI's own long-standing
ABI. The user-facing documentation did not yet describe this new,
separate binary interface: how to build against it, its current
limitations, or how it relates to Open MPI's existing ABI-compatibility
guarantees. This adds and reorganizes that documentation.
High points of the documentation in this commit:
* A new "Building MPI applications using the MPI Forum ABI" page
(docs/building-apps/mpi-forum-abi.rst) explaining what the MPI Forum
ABI is, that it is new in v6.0.0 and distinct from the Open MPI ABI,
and its limitations: the application must be dynamically linked, run
with a matching launcher, and written in C.
* How to build and run standard-ABI C applications with the mpicc_abi
wrapper and libmpi_abi -- the wrapper adds the standard ABI header
directory ($prefix/include/standard_abi) and links libmpi_abi -- plus
the --showme flags and the effect of configuring with
--disable-standard-abi.
* How to check ABI support at run time with MPI_Abi_get_version, which
reports version 1.0 from libmpi_abi but -1, -1 from the normal libmpi,
because the normal library uses Open MPI's own ABI rather than the
standard ABI.
* A clean separation of the two ABIs across the existing pages: the
abi-compatibility.rst page is rescoped to the Open MPI ABI and
cross-references the new page; version-numbering.rst distinguishes the
Open MPI ABI from the MPI Forum ABI and moves its release-series ABI
details into abi-compatibility.rst; and both pages state that the two
ABIs are not interchangeable.
* A "danger" warning that object files or libraries built against
different MPI ABIs must not be mixed in one executable, with the
concrete unsupported mpicc_abi / mpicc / mpifort combinations and the
rule to use one ABI consistently for every MPI-using object.
* The intentional decision not to ship a Fortran standard ABI yet (no
mpifort_abi wrapper, no libmpifort_abi): a documented wait-and-see
approach taken while no other implementation supports the Fortran ABI
and the MPI Forum is still converging on it.
* Reference documentation for the Open MPI MPI_Abi_* query/helper
routines: man pages for MPI_Abi_get_version, MPI_Abi_get_info,
MPI_Abi_{get,set}_fortran_booleans, and MPI_Abi_{get,set}_fortran_info
describing their Open MPI behavior; the mpicc_abi wrapper in the
wrapper-compiler man page; and the standard-ABI configure option in
the configure CLI options.
* Release-notes and v6.0.x changelog entries announcing MPI-5.0
standard ABI support for C applications and noting the absence of a
Fortran ABI wrapper.
Signed-off-by: Jeff Squyres <jeff@squyres.com>
Add CI coverage for the new MPI Standard ABI library:
* ompi_mpi4py.yaml: also run the mpi4py test suite against
libmpi_abi, not just the regular libmpi.
* ompi-pr-builds.yaml: run the MPI Standard ABI test suite
(make check-abi) as part of the ompi-pr-builds workflow.
ompi/test/mpi-abi: XFAIL the datarep cross probe against the MPICH runtime
MPICH does not implement user-defined datarep conversions. Its
MPI_Register_datarep() fails with
MPI_REGISTER_DATAREP(3042): Read and Write datarep conversions are
currently not supported by MPI-IO
and reports that as error class MPI_ERR_CONVERSION rather than as
MPI_ERR_UNSUPPORTED_DATAREP or MPI_ERR_UNSUPPORTED_OPERATION. The
callback_datarep probe only recognizes the latter two as "unsupported",
so it exits 2 and check-abi-mpich records a hard failure.
This is not a cross-ABI problem: a program compiled with MPICH's own
mpicc_abi and run under MPICH fails in exactly the same way. The failure
is a limitation of the MPICH runtime, not of Open MPI or of the MPI Forum
ABI.
Reported upstream as pmodels/mpich#7873. If
MPICH returns MPI_ERR_UNSUPPORTED_DATAREP, the probe takes its existing
77 skip path and this XFAIL should be removed.
Add XFAIL as a first-class result -- distinct from SKIP, which means the
probe declined to run, and from FAIL, which means something is wrong with
us -- and mark this probe as an expected failure when MPICH provides the
runtime. Keying it on the run implementation (rather than on the probe
alone) means it can only ever excuse a MPICH-runtime limitation; a real
regression on the Open MPI side still fails.
Note that the key is the probe's exit code 2, which means "registration
failed with something other than the two unsupported classes". That is
the narrowest key the probe's exit codes offer, but it is broader than
the upstream bug: it would also absorb a future genuine MPICH datarep
registration failure.
XFAIL is reported in its own colour and with its own reason code, so the
known limitation stays visible instead of vanishing into the skip count.
Signed-off-by: Jeff Squyres <jeff@squyres.com>
The MPI Forum ABI requires the public MPI_* symbols to be weak
definitions. When an application is linked against an implementation
whose libmpi_abi exports MPI_* weak -- as MPICH's does -- the linker
records a weak-def (coalesced) bind, and (at least on macOS) the loader
will only satisfy such a bind from another weak definition; a strong one
is rejected outright:
dyld: Symbol not found: _MPI_Send
Expected as weak-def export from some loaded dylib
Open MPI's libmpi_abi exported MPI_* strong on macOS, so an application
compiled with MPICH's mpicc_abi could not run against Open MPI's
libmpi_abi at all -- precisely the portability the standardized ABI
exists to provide, and in the direction that matters most for adoption.
On Linux this already worked by accident: where weak aliases are
available the MPI_* alias is itself a weak definition. The problem is
confined to the platforms where weak aliases are not available and the
bindings are therefore compiled a second time to produce MPI_* -- that
separately-compiled copy was strong. Mark it weak.
This touches libmpi_abi only; libmpi's symbols are unchanged. The
hand-written files shared with libmpi (pcontrol.c and the MPI_T
bindings) are guarded on OMPI_NO_MPI_PROTOTYPES, which is defined only
for the libmpi_abi compiles.
With this, check-abi-mpich's MPICH-compiled / Open-MPI-run direction goes
from failing to 61 PASS / 0 FAIL on macOS.
ABI: make the libmpi MPI_* symbols weak too
Commit "ABI: make the libmpi_abi MPI_* symbols weak" did this for
libmpi_abi, where the MPI Forum ABI requires it. Do the same for libmpi,
so that both libraries present the public MPI_* symbols the same way, and
so that Open MPI matches the scheme MPICH now uses: strong PMPI_*, weak
MPI_*.
Weak MPI_* is also what lets a PMPI profiling library supply a strong
MPI_* that overrides ours while still reaching the back end through
PMPI_*. Where weak aliases are available (Linux) the MPI_* alias was
already a weak definition, so this is a no-op there; where they are not
(macOS) the bindings are compiled a second time to produce MPI_*, and it
is that separately-compiled copy that was strong. Mark it weak.
This keeps the macOS compile-everything-twice scheme intact; removing it
is a separate step.
The four MPI_*_F90 accessors in ompi/mpi/fortran/base (MPI_WTIME_F90 and
friends) are deliberately left strong: they have no PMPI_* counterpart,
are not part of the profiling interface, and are not MPI Forum ABI
symbols.
After this, on macOS libmpi exports 698/698 of its C MPI_* weak and all
698 PMPI_* strong, and libmpi_abi is unchanged at 657/657 weak.
Signed-off-by: Jeff Squyres <jeff@squyres.com>
Where weak aliases are unavailable, Open MPI compiled every C binding a second time, with OMPI_BUILD_MPI_PROFILING=0, purely to produce the public MPI_* symbols; the first compile produced PMPI_*. That is what the libmpi_c_noprofile, libmpi_c_abi_noprofile, libmpi_mpit_noprofile and libmpi_mpit_abi_noprofile convenience libraries were for. Now that MPI_* are weak symbols rather than weak aliases, the second compile is unnecessary: the profiling compile can emit both. Emit a weak MPI_* definition that forwards to the strong PMPI_* one, and delete the four *_noprofile libraries. This is the scheme MPICH uses -- on arm64 the resulting MPI_Send is a weak symbol whose entire body is a single branch instruction to PMPI_Send. Note that a weak *alias* is not an option here: Mach-O cannot express one. There is no way to mark a ".set" alias as a weak definition (verified against ld64: .weak_definition, .weak_reference and #pragma weak all leave the alias strong), which is precisely why the second compile existed. The forwarding definition is guarded on !OPAL_HAVE_WEAK_ALIASES, since where aliases *are* available (ELF) the alias already is the weak MPI_* definition and a second definition would be a duplicate symbol. MPI_Pcontrol is variadic, so its arguments cannot be forwarded. Open MPI's implementation ignores them and returns MPI_SUCCESS, and MPICH's weak MPI_Pcontrol does the same, so the wrapper does that directly. Add __opal_attribute_weak__ for the plain weak attribute; OPAL previously had only __opal_attribute_weak_alias__. This covers the C bindings (generated, hand-written, and MPI_T). The Fortran mpif-h bindings still compile twice: they are 443 hand-written files, each exposing four name-mangled entry points, so converting them means roughly 1,772 forwarding definitions and wants a generator rather than a hand edit. BUILD_MPI_BINDINGS_LAYER therefore survives, now used only by Fortran. Verified on macOS (single compile; MPI_* 698/698 weak in libmpi, 657/657 in libmpi_abi) and Linux (unchanged; the wrapper is correctly suppressed): examples, make check, make check-abi, make check-abi-mpich, and PMPI interposition all pass. ABI: compile the mpif.h bindings once, not twice This finishes what the previous commit started for the C bindings. Where weak aliases are unavailable, every mpif.h binding was compiled a second time, with OMPI_BUILD_MPI_PROFILING=0, purely to emit the public MPI_* Fortran entry points; the profiling compile emitted PMPI_* and renamed the implementation to pompi_x_f. The bodies were compiled twice. Emit the MPI_* entry point from the profiling compile instead, as a weak definition forwarding to the same implementation the strong PMPI_* entry point calls, and delete the second compile. The implementation keeps its ompi_x_f name and is no longer renamed. Add OMPI_GENERATE_WEAK_F77_BINDINGS alongside OMPI_GENERATE_F77_BINDINGS. Like its sibling it emits a single entry point, in whichever name-mangling scheme the Fortran compiler uses; it just marks it weak. Twelve bindings (MPI_Aint_add and friends) spell their entry points out longhand because the macro does not cover non-void return types; those are marked weak directly. With only one compile left, the profile/ subdirectory has no reason to exist: its entire apparatus -- the 441 p*.c symlinks, the duplicate linked_files list, and the symlink rule -- existed only to compile the same basenames a second time with different flags. Compile the real sources directly in mpif-h/ (with OMPI_BUILD_MPI_PROFILING=1) instead, and delete profile/ entirely. The sources move back into the library's _SOURCES list, which also makes them distributed again -- the previous arrangement compiled them only as nodist_ symlinks, so "make dist" silently shipped no mpif.h binding sources at all. psizeof_f.f90 generation moves up alongside sizeof_f.f90, and the BUILD_PMPI_FORTRAN_MPIFH_BINDINGS_LAYER conditional (now identical to OMPI_BUILD_FORTRAN_MPIFH_BINDINGS) is gone. register_datarep_f.c needed a fix: its OBJ_CLASS_INSTANCE was guarded on "!OMPI_BUILD_MPI_PROFILING || OPAL_HAVE_WEAK_ALIASES", i.e. it was emitted by whichever compile was not the profiling one. With only one compile left that guard emitted it nowhere, and the Fortran bindings failed at run time with a missing ompi_intercept_extra_state_t_class. The bindings are now compiled exactly once, so the guard is gone. With C and Fortran both converted, OMPI_PROFILING_COMPILE_SEPARATELY is always 0 and its three AM_CONDITIONALs (BUILD_MPI_BINDINGS_LAYER, COMPILE_PROFILING_SEPARATELY, BUILD_MPI_FORTRAN_MPIFH_BINDINGS_LAYER) are gone. A compiler with neither weak symbols nor weak aliases can no longer build the profiling interface, so configure now says so explicitly rather than silently producing a broken library. ompi/test/mpi-abi: the mpif.h ABI helper check looks for each helper's source in mpif-h/Makefile.am, which once again lists every binding source directly. Verified on macOS (mpif.h MPI_* now weak: 457 weak entry points, 613 strong PMPI_*) and Linux (unchanged; the weak wrapper is correctly suppressed where weak aliases exist): fresh VPATH builds on both, the Fortran examples under mpirun -np 2, and a "make dist" tarball that ships exactly the 441 binding sources with no profile/ remnants. ftmpi: compile the MPIX_* bindings once; remove the profile/ dirs These were the last two profile/ subdirectories in the tree. ompi/mpiext/ftmpi/c compiled every binding twice: once in c/ with OMPI_BUILD_MPI_PROFILING=0 to emit a strong MPIX_* symbol, and once in c/profile/ (via p*.c symlinks) with OMPI_BUILD_MPI_PROFILING=1 to emit the strong PMPIX_* symbol plus a weak MPIX_* alias. Both copies were always built and both linked into libmpiext_ftmpi_c.la, so the strong MPIX_* from the non-profiling compile always won over the weak alias -- which also meant PMPI-based tools could never actually intercept the MPIX_* calls. Convert to the same single-compile scheme the generated C bindings use: compile once with OMPI_BUILD_MPI_PROFILING=1, emitting the strong PMPIX_* entry point and a weak MPIX_* -- via a weak alias where the platform has them, and via a weak forwarding definition where it does not (e.g., macOS). Interception now works for MPIX_* too. ompi/mpiext/ftmpi/use-mpi-f08/profile/ held hand-written PMPIX_*_f08 wrapper copies of the MPIX_*_f08 wrappers. Fortran has no weak symbols, so both wrappers must be spelled out; fold each PMPIX_*_f08 subroutine into the same file as its MPIX_*_f08 sibling and delete the subdirectory. Also remove the now-stale profile/ .gitignore entries for the ompi tree (ompi/mpi/c/profile, ompi/mpi/tool/profile, and the use-mpi-f08/profile leftovers referred to directories that no longer exist; the oshmem entries remain because that build still creates its profile/ directories at build time). Signed-off-by: Jeff Squyres <jeff@squyres.com>
The nineteen MPI_T tool sources whose C prototypes are ABI-neutral (category_*, *_get_index, *_get_num, finalize, init_thread, source_get_timestamp) were compiled verbatim into libmpi_abi. Their prototypes need no translation, but their values do: they returned OMPI-valued MPI_T error classes (e.g. MPI_T_ERR_NOT_INITIALIZED is 55 internally but 1003 in the MPI Forum ABI), and MPI_T_init_thread passed thread levels through unconverted in both directions (OMPI uses 0..3 where the ABI defines 1024/2048/4096). An ABI application comparing returns against the standard constants, or reading "provided", got wrong values. Convert them to .c.in templates like the rest of ompi/mpi/tool: the bodies are unchanged, the PROTOTYPE lines use the existing ERROR_CLASS, TS_LEVEL/TS_LEVEL_OUT, PVAR_CLASS, and ELEMENT_COUNT types, and the generated MPI Forum ABI wrappers now perform the error-class, thread- level, and pvar-class conversions. This retires the interface_profile_sources_np list entirely (and, while touching the list plumbing, replaces an AI-tooling-addressed comment with a normal explanation of why the generated list is spelled out for BSD make). Verified on macOS and Linux: full build, make check, make check-abi (85 PASS / 0 FAIL / 3 SKIP), and make check-abi-mpich (154/0/3). Signed-off-by: Jeff Squyres <jeff@squyres.com>
In Open MPI v6.0, 138 predefined MPI symbols (e.g., ompi_mpi_comm_world, ompi_mpi_comm_self, predefined datatypes, and operators) were relocated from libmpi to the new libopen_mpi library to support the MPI standard ABI implementation. This change broke backward compatibility on Darwin with applications compiled against Open MPI v5.x that directly reference these symbols through libmpi. This commit implements platform-specific symbol re-export mechanisms to restore backward compatibility: - macOS: Uses -Wl,-reexport-lopen_mpi to create LC_REEXPORT_DYLIB dependency, making libopen_mpi symbols available through libmpi at runtime via the dynamic linker. configure.ac now detects the platform and linker capabilities, setting Automake conditionals (OMPI_REEXPORT_MACOS and OMPI_REEXPORT_VERSION_SCRIPT) that control the linking strategy in ompi/Makefile.am. The -reexport_library probe runs only on Darwin. A new test under ompi/test/reexport/ verifies that symbols resolve correctly through libmpi at runtime; it validates the exact shared library produced by the current build (passed through the environment by the test harness) instead of hard-coding sonames. This allows v5.x-compiled applications to run with v6.0 libraries without recompilation, while maintaining the architectural benefits of the libopen_mpi separation. On macOS, libopen_mpi is deliberately NOT in libmpi's LIBADD: the -reexport-lopen_mpi flag both links and re-exports it, and if the library also appeared in LIBADD, ld64 would record an ordinary LC_LOAD_DYLIB reference instead of LC_REEXPORT_DYLIB. Because that flag is invisible to libtool, libmpi.la must list libopen-pal.la explicitly; otherwise libtool omits opal/.libs from the runtime search path of uninstalled programs that link only libmpi.la, and "make check" fails before "make install" (which also breaks the inner check run of "make distcheck"). Drop the symbol re-export machinery on ELF platforms The v5.x-compatibility re-export of libopen_mpi's predefined MPI handle symbols (ompi_mpi_comm_world and friends) through libmpi is only needed on macOS, where the Mach-O two-level namespace records which library each symbol was found in at link time. On ELF platforms the global symbol namespace is flat: at run time the dynamic linker resolves a v5.x binary's references from any loaded library, and libmpi's DT_NEEDED dependency on libopen_mpi guarantees libopen_mpi is loaded. No re-export mechanism is needed at all, and ompi/test/reexport's symbol-resolution test passes unchanged with the version script removed. The --version-script implementation was also actively harmful: it attached an OMPI_6.0 version tag to every symbol libmpi exports. Open MPI has never shipped versioned symbols, so this broke consumers that parse symbol tables (mpi4py's test_mpiapi.py fails on the "MPI_Send@OMPI_6.0" references of anything compiled against the library), and it meant that libraries built against a versioned libmpi could not link against an unversioned rebuild. Introducing symbol versioning would be an ABI policy decision in its own right and should not ride in as a side effect of a compatibility mechanism. Remove the version-script configure probe, the OMPI_REEXPORT_VERSION_SCRIPT conditional, and the libmpi_symbol_exports.ver script (whose curated symbol list had already been reduced to an export-everything placeholder). The macOS -Wl,-reexport-lopen_mpi mechanism is unchanged. Signed-off-by: Howard Pritchard <howardp@lanl.gov> Signed-off-by: Jeff Squyres <jeff@squyres.com>
|
@jsquyres Given that you guys are dealing with macOS and are not afraid of adding platform-specific stuff, there is a thing I would like to point out. As a consequence of using libtool versioning with 1:0:0, the ABI library will get a current_version and compatibility_version of 2.0.0. You can double-check running https://github.com/mpi-forum/mpi-abi-stubs/blob/main/Makefile#L48C13-L48C41 Using 0 (zero) for the version numbers basically tells the dynamic linker to not perform any version compatibility check when the library is loaded at runtime. I think that is what we want, major version compatibility is enforced via SONAME, just like in Linux. Recent versions of macOS (circa 2020) removed the compatibility version checks for shared libraries, the dynamic linker simply ignores these version numbers. Still, it may be good to set these current/compatibility versions to 0.0.0 for cleanliness, such that these numbers to not propagate to other executables and libraries linked against |
|
@dalcinl Gotcha. I understand what you're asking for, and why. The problem is that Libtool unconditionally emits its own computed So we'd be building on undocumented linker behavior to fix something that, as you note yourself, has been cosmetic since dyld stopped enforcing these checks circa macOS 11. If a future ld starts hard-erroring on the repeated option (as it already does for some others), every macOS build breaks for a hygiene win. That makes this feel a little shaky. |
I understand. However, I would still go for it. If things change in a different path (e.g. version checks being somehow reintroduced but Apple or third party tools), then we end up with published broken binaries. Maybe a configure test can be run in advance to check whether the linker accepts the duplicated -xxx_version options with different values? What about patching the generated It is unfortunate that I'm not so good at autotools to experiment and provide a working patch. |
|
We do carry a few Libtool patches, but I admit that I'm fairly wary about adding any more. Libtool even had a release recently (July 2026) -- we haven't tried to port our existing patches to it (I admit I'm a little scared). |
|
@dalcinl i think we need to pursue your points in a discussion about a MPI forum side document. |
|
@hppritcha I you could keep track of all the points I already forgot, I'm happy to help. |
|
I am thinking claude or other agent may be able to write a draft side document for MPI implementors to iterate on, the trick will be finding the various places in issues and PR comments that points of concern were raised. |
|
To backport this PR to v6.0.x:
|
Implement the MPI-5 c ABI functionality.
Two external MPI libraries are now created: libmpi.so and libmpi_abi.so. Backend code that was originally in libmpi.la has been extracted into a libopen-mpi.la to be linked in to both libraries.
Almost all of the Open MPI C interface is now being generated from templates processed by the binding infrastructure.
The binding infrastructure introduced to support big count has been extended to generate code to support the MPI ABI specification. The bindings infrastructure is also used to generate the MPI ABI compliant mpi.h header file, as well as the converter functions to translate between OMPI and MPI ABI constants.
Before attempting to review this PR it would probably be good to become familiar with the MPI-5 ABI chapter and also to peruse the README ((ompi/mpi/README_ABI.md) included in this PR.
A few todos left:
todos for follow-up PRs:
MPI_Abi_set_fortran_infoandMPI_Abi_set_fortran_booleans.This PR supercedes #12033
Fixes #14243