Skip to content

Commit 7791f2a

Browse files
committed
docs: Render C/F90/F08 bindings in man pages
Use the pympistandard Python module and associated MPI-4.1 MPI Standard JSON definition file to generate bindings -- regular and embiggened -- in the MPI man pages. This commit adds a new submodule: the pympistandard Python module from the MPI Forum repository. Signed-off-by: Jeff Squyres <jeff@squyres.com>
1 parent 120b71b commit 7791f2a

10 files changed

+59169
-78
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,7 @@ docs/_build
516516
docs/_static
517517
docs/_static/css/custom.css
518518
docs/_templates
519+
docs/man-openmpi/man3/bindings/*.rst
519520

520521
# Common Python virtual environment and cache directory names
521522
venv

.gitmodules

+4
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,7 @@
99
[submodule "oac"]
1010
path = config/oac
1111
url = ../../open-mpi/oac
12+
[submodule "3rd-party/pympistandard"]
13+
path = 3rd-party/pympistandard
14+
url = ../../jsquyres/pympistandard.git
15+
branch = pr/small-fix

.readthedocs-pre-create-environment.sh

+3
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,6 @@ PRRTE_RST_TARGET_DIR=docs/prrte-rst-content
2626

2727
cp -rp $SCHIZO_SRC_DIR $SCHIZO_TARGET_DIR
2828
cp -rp $PRRTE_RST_SRC_DIR $PRRTE_RST_TARGET_DIR
29+
30+
cd docs
31+
python3 ./generate-mpi-man3-bindings.py --srcdir . --builddir .

3rd-party/pympistandard

Submodule pympistandard added at b8b0ec5

docs/Makefile.am

+17-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#
22
# Copyright (c) 2022 Cisco Systems, Inc. All rights reserved.
3-
# Copyright (c) 2023-2024 Jeffrey M. Squyres. All rights reserved.
3+
# Copyright (c) 2023-2025 Jeffrey M. Squyres. All rights reserved.
44
#
55
# $COPYRIGHT$
66
#
@@ -54,12 +54,16 @@ RST_SOURCE_FILES = \
5454
$(srcdir)/license/*.rst \
5555
$(srcdir)/man-openmpi/*.rst \
5656
$(srcdir)/man-openmpi/man*/*.rst \
57+
$(srcdir)/man-openmpi/man*/bindings/*.rst \
5758
$(srcdir)/man-openshmem/*.rst \
5859
$(srcdir)/man-openshmem/man*/*.rst
5960

6061
EXTRA_DIST = \
6162
requirements.txt \
6263
no-prrte-content.rst.txt \
64+
generate-mpi-man3-bindings.py \
65+
mpi-standard-apis.json \
66+
man-openmpi/man3/bindings \
6367
html \
6468
man \
6569
$(SPHINX_CONFIG) \
@@ -843,6 +847,10 @@ OMPI_MAN3_RST = $(OMPI_MAN3:%.3=man-openmpi/man3/%.3.rst)
843847
OMPI_MAN3_BUILT = $(OMPI_MAN3:%.3=$(MAN_OUTDIR)/%.3)
844848
OMPI_MAN3_INSTALL_FROM = $(OMPI_MAN3:%.3=$(MAN_INSTALL_FROM)/%.3)
845849

850+
# Use this one file as a sentinel for building all the man page
851+
# bindings files
852+
SENTINEL_OMPI_MAN3_BINDING = man-openmpi/man3/bindings/mpi_init.rst
853+
846854
OMPI_MAN7_RST = $(OMPI_MAN7:%.7=man-openmpi/man7/%.7.rst)
847855
OMPI_MAN7_BUILT = $(OMPI_MAN7:%.7=$(MAN_OUTDIR)/%.7)
848856
OMPI_MAN7_INSTALL_FROM = $(OMPI_MAN7:%.7=$(MAN_INSTALL_FROM)/%.7)
@@ -921,7 +929,7 @@ man: $(ALL_MAN_BUILT)
921929
# Remove the copies of the built HTML and man pages to get back to a
922930
# clean git clone.
923931
maintainer-clean-local:
924-
rm -rf html man
932+
rm -rf html man man-openmpi/man3/bindings
925933

926934
# If we're doing a VPATH build, we may have "html" and "man"
927935
# directories in the build tree (e.g., if we did "make dist"). Remove
@@ -998,10 +1006,16 @@ $(builddir)/schizo-ompi-rst-content/schizo-ompi-cli.rstxt: $(srcdir)/no-prrte-co
9981006
cp -pf $(srcdir)/no-prrte-content.rst.txt "$@"
9991007
endif
10001008

1009+
$(SENTINEL_OMPI_MAN3_BINDING): generate-mpi-man3-bindings.py
1010+
$(SENTINEL_OMPI_MAN3_BINDING): mpi-standard-apis.json
1011+
$(OMPI_V_GEN) $(PYTHON3) $(srcdir)/generate-mpi-man3-bindings.py \
1012+
--srcdir $(srcdir) --builddir $(builddir)
1013+
10011014
$(ALL_MAN_BUILT): $(builddir)/prrte-rst-content
10021015
$(ALL_MAN_BUILT): $(builddir)/schizo-ompi-rst-content/schizo-ompi-cli.rstxt
10031016
$(ALL_MAN_BUILT): $(RST_SOURCE_FILES) $(IMAGE_SOURCE_FILES)
10041017
$(ALL_MAN_BUILT): $(TEXT_SOURCE_FILES) $(SPHINX_CONFIG)
1018+
$(ALL_MAN_BUILT): $(SENTINEL_OMPI_MAN3_BINDING)
10051019

10061020
# Render the RST source into both 1) full HTML docs and 2) nroff man
10071021
# pages.
@@ -1039,6 +1053,7 @@ $(ALL_MAN_BUILT): $(TEXT_SOURCE_FILES) $(SPHINX_CONFIG)
10391053
# changed. We're going to overwrite any local changes in the build
10401054
# tree, but you shouldn't be editing the build tree, anyway. So --
10411055
# good enough.
1056+
10421057
$(ALL_MAN_BUILT):
10431058
$(OMPI_V_SPHINX_COPYRST) if test "$(srcdir)" != "$(builddir)"; then \
10441059
len=`echo "$(srcdir)/" | wc -c`; \

docs/generate-mpi-man3-bindings.py

+179
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
#!/usr/bin/env python3
2+
#
3+
# Copyright (c) 2025 Jeffrey M. Squyres. All rights reserved.
4+
#
5+
# $COPYRIGHT$
6+
#
7+
# Additional copyrights may follow
8+
#
9+
# $HEADER$
10+
#
11+
12+
# Script to create RST files containing the C, F90, and F80 bindings
13+
# that will be included in each of the MPI API man pages. We generate
14+
# the bindings using the official MPI Forum python library to read the
15+
# API JSON that was generated when building the MPI Forum standard
16+
# LaTeX document and then emit the bindings.
17+
#
18+
# Using this method, we can emit both "regular" and "embiggened"
19+
# versions of each API (if an "embiggened" version exists).
20+
21+
import os
22+
import sys
23+
import textwrap
24+
import argparse
25+
26+
from pathlib import Path
27+
28+
def generate(func_name, output_dir):
29+
global std
30+
31+
# Sanity check
32+
func_name = func_name.lower()
33+
if not func_name in std.PROCEDURES:
34+
print(f"ERROR: Don't know {func_name}")
35+
return
36+
37+
# Get the data for the bindings
38+
data = std.PROCEDURES[func_name]
39+
40+
# Make an array of strings to emit into the output RST file.
41+
blank = ''
42+
out = []
43+
44+
out.append('SYNTAX')
45+
out.append('------')
46+
out.append(blank)
47+
48+
# C bindings
49+
out.append('C Syntax')
50+
out.append('^^^^^^^^')
51+
out.append(blank)
52+
out.append('.. code-block:: c')
53+
out.append(blank)
54+
55+
binding = data.express.iso_c
56+
line = textwrap.fill(str(binding), width=72,
57+
initial_indent=' ',
58+
subsequent_indent = ' ')
59+
out.append(line)
60+
out.append(blank)
61+
if data.has_embiggenment():
62+
binding = data.express.embiggen.iso_c
63+
line = textwrap.fill(str(binding), width=72,
64+
initial_indent=' ',
65+
subsequent_indent = ' ')
66+
out.append(line)
67+
out.append(blank)
68+
69+
# F90 bindings
70+
# Note: the f90 bindings were not embiggened
71+
out.append('Fortran Syntax')
72+
out.append('^^^^^^^^^^^^^^')
73+
out.append(blank)
74+
out.append('.. code-block:: fortran')
75+
out.append(blank)
76+
out.append(' USE MPI')
77+
out.append(" ! or the older form: INCLUDE 'mpif.h'")
78+
79+
binding = data.express.f90
80+
lines = str(binding).split('\n')
81+
for line in lines:
82+
out.append(f' {line}')
83+
out.append(blank)
84+
85+
# F08 bindings
86+
out.append('Fortran 2008 Syntax')
87+
out.append('^^^^^^^^^^^^^^^^^^^')
88+
out.append(blank)
89+
out.append('.. code-block:: fortran')
90+
out.append(blank)
91+
out.append(' USE mpi_f08')
92+
93+
binding = data.express.f08
94+
lines = str(binding).split('\n')
95+
for line in lines:
96+
out.append(f' {line}')
97+
out.append(blank)
98+
99+
if data.has_embiggenment():
100+
binding = data.express.embiggen.f08
101+
lines = str(binding).split('\n')
102+
for line in lines:
103+
out.append(f' {line}')
104+
out.append(blank)
105+
106+
# Write the output file -- but only if it has changed
107+
old_content = None
108+
new_content = '\n'.join(out)
109+
output_file = os.path.join(output_dir, f'{func_name}.rst')
110+
if os.path.exists(output_file):
111+
with open(output_file) as fp:
112+
old_content = fp.read()
113+
114+
if old_content != new_content:
115+
with open(output_file, 'w') as fp:
116+
fp.write('\n'.join(out))
117+
print(f'Wrote {output_file}')
118+
119+
#----------------
120+
121+
def setup_cli():
122+
parser = argparse.ArgumentParser(description="Generate C/F90/F08 bindings for RST")
123+
124+
parser.add_argument('--srcdir',
125+
required=True,
126+
help='Build source dir')
127+
parser.add_argument('--builddir',
128+
required=True,
129+
help='Build build dir')
130+
131+
args = parser.parse_args()
132+
return args
133+
134+
#----------------
135+
136+
def main():
137+
args = setup_cli()
138+
139+
src_dir = os.path.abspath(args.srcdir)
140+
build_dir = os.path.abspath(args.builddir)
141+
142+
# A bit of a hack to load the pympistandard module, which is in
143+
# the Open MPI '3rd-party" tree.
144+
pympistandard_dir = Path(os.path.join(src_dir, '..', '3rd-party',
145+
'pympistandard', 'src')).resolve()
146+
147+
sys.path.insert(0, str(pympistandard_dir))
148+
global std
149+
import pympistandard as std
150+
151+
# This is the JSON file with all the MPI standard APIs. This is
152+
# not currently officially distributed by the MPI Forum, so it was
153+
# obtained by checking out the relevant branch from
154+
# https://github.com/mpi-forum/mpi-standard/ and doing a build.
155+
# This will create a file named apis.json. Copy that here to this
156+
# tree.
157+
mpi_standard_json = os.path.abspath(os.path.join(src_dir,
158+
'mpi-standard-apis.json'))
159+
std.use_api_version(1, given_path=mpi_standard_json)
160+
161+
# We need to write all of these into the build tree. See
162+
# docs/Makefile.am for a fuller explaination: all RST files are
163+
# copied to the build tree, and we build there.
164+
output_dir = os.path.join(build_dir, 'man-openmpi', 'man3', 'bindings')
165+
if not os.path.exists(output_dir):
166+
os.makedirs(output_dir)
167+
168+
# Now we finally generate the files. Iterate over all the MPI
169+
# procedures and generate a binding file for each one of them.
170+
#for func_name in std.PROCEDURES:
171+
# generate(func_name, output_dir)
172+
173+
# PROOF OF CONCEPT: Just generate 2 binding files for now -- to be
174+
# replaced with the above loop.
175+
generate("mpi_init", output_dir)
176+
generate("mpi_send", output_dir)
177+
178+
if __name__ == "__main__":
179+
main()

docs/man-openmpi/man3/MPI_Init.3.rst

+1-35
Original file line numberDiff line numberDiff line change
@@ -8,41 +8,7 @@ MPI_Init
88
99
:ref:`MPI_Init` |mdash| Initializes the MPI execution environment
1010

11-
12-
SYNTAX
13-
------
14-
15-
16-
C Syntax
17-
^^^^^^^^
18-
19-
.. code-block:: c
20-
21-
#include <mpi.h>
22-
23-
int MPI_Init(int *argc, char ***argv)
24-
25-
26-
Fortran Syntax
27-
^^^^^^^^^^^^^^
28-
29-
.. code-block:: fortran
30-
31-
USE MPI
32-
! or the older form: INCLUDE 'mpif.h'
33-
MPI_INIT(IERROR)
34-
INTEGER IERROR
35-
36-
37-
Fortran 2008 Syntax
38-
^^^^^^^^^^^^^^^^^^^
39-
40-
.. code-block:: fortran
41-
42-
USE mpi_f08
43-
MPI_Init(ierror)
44-
INTEGER, OPTIONAL, INTENT(OUT) :: ierror
45-
11+
.. include:: ./bindings/mpi_init.rst
4612

4713
INPUT PARAMETERS
4814
----------------

docs/man-openmpi/man3/MPI_Send.3.rst

+1-41
Original file line numberDiff line numberDiff line change
@@ -8,47 +8,7 @@ MPI_Send
88
99
:ref:`MPI_Send` |mdash| Performs a standard-mode blocking send.
1010

11-
12-
SYNTAX
13-
------
14-
15-
16-
C Syntax
17-
^^^^^^^^
18-
19-
.. code-block:: c
20-
21-
#include <mpi.h>
22-
23-
int MPI_Send(const void *buf, int count, MPI_Datatype datatype, int dest,
24-
int tag, MPI_Comm comm)
25-
26-
27-
Fortran Syntax
28-
^^^^^^^^^^^^^^
29-
30-
.. code-block:: fortran
31-
32-
USE MPI
33-
! or the older form: INCLUDE 'mpif.h'
34-
MPI_SEND(BUF, COUNT, DATATYPE, DEST, TAG, COMM, IERROR)
35-
<type> BUF(*)
36-
INTEGER COUNT, DATATYPE, DEST, TAG, COMM, IERROR
37-
38-
39-
Fortran 2008 Syntax
40-
^^^^^^^^^^^^^^^^^^^
41-
42-
.. code-block:: fortran
43-
44-
USE mpi_f08
45-
MPI_Send(buf, count, datatype, dest, tag, comm, ierror)
46-
TYPE(*), DIMENSION(..), INTENT(IN) :: buf
47-
INTEGER, INTENT(IN) :: count, dest, tag
48-
TYPE(MPI_Datatype), INTENT(IN) :: datatype
49-
TYPE(MPI_Comm), INTENT(IN) :: comm
50-
INTEGER, OPTIONAL, INTENT(OUT) :: ierror
51-
11+
.. include:: ./bindings/mpi_send.rst
5212

5313
INPUT PARAMETERS
5414
----------------

0 commit comments

Comments
 (0)