Skip to content

Convert some Perl build scripts to Python #13231

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions autogen.pl
Original file line number Diff line number Diff line change
@@ -10,8 +10,8 @@
# Copyright (c) 2015-2022 IBM Corporation. All rights reserved.
# Copyright (c) 2020 Amazon.com, Inc. or its affiliates.
# All Rights reserved.
#
# Copyright (c) 2025 Nanook Consulting All rights reserved.
# Copyright (c) 2025 Jeffrey M. Squyres. All rights reserved.
# $COPYRIGHT$
#
# Additional copyrights may follow
@@ -1609,7 +1609,7 @@ sub replace_config_sub_guess {
# sync).

my @scripts;
push(@scripts, "ompi/include/mpif-values.pl");
push(@scripts, "ompi/include/mpif-values.py");

foreach my $s (@scripts) {
verbose "=== $s\n";
40 changes: 40 additions & 0 deletions config/ompi_fortran_get_alignment.m4
Original file line number Diff line number Diff line change
@@ -10,6 +10,8 @@ dnl Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
dnl University of Stuttgart. All rights reserved.
dnl Copyright (c) 2004-2005 The Regents of the University of California.
dnl All rights reserved.
dnl Copyright (c) 2025 Research Organization for Information Science
dnl and Technology (RIST). All rights reserved.
dnl Copyright (c) 2010-2012 Cisco Systems, Inc. All rights reserved.
dnl $COPYRIGHT$
dnl
@@ -178,3 +180,41 @@ end program]])],
AS_VAR_COPY([$2], [type_var])
AS_VAR_POPDEF([type_var])dnl
])dnl

# OMPI_FORTRAN_GET_COMMON_ALIGNMENT(variable to set)
# ------------------------------------------
AC_DEFUN([OMPI_FORTRAN_GET_COMMON_ALIGNMENT],[
AS_IF([test $OMPI_TRY_FORTRAN_BINDINGS -gt $OMPI_FORTRAN_NO_BINDINGS],
[AC_CACHE_CHECK([alignment of Fortran common], ompi_cv_fortran_common_alignment,
[AC_LANG_PUSH([Fortran])
AC_LINK_IFELSE([AC_LANG_SOURCE([[ program falignment
CHARACTER A,B
COMMON /AA/A
COMMON /BB/B
OPEN(UNIT=10, FILE="conftestval")
if (LOC(A) > LOC(B)) then
write (10,'(I5)') LOC(A)-LOC(B)
else
write (10,'(I5)') LOC(B)-LOC(A)
endif
CLOSE(10)

end program]])],
[AS_IF([test "$cross_compiling" = "yes"],
[AC_MSG_ERROR([Can not determine common alignment when cross-compiling])],
[OPAL_LOG_COMMAND([./conftest],
[AS_VAR_SET(ompi_cv_fortran_common_alignment, [`cat conftestval`])],
[AC_MSG_ERROR([Could not determine common alignment])])])],

[AC_MSG_WARN([Could not determine common alignment])
AC_MSG_WARN([See config.log for details])
AC_MSG_ERROR([Cannot continue])])
rm -rf conftest* *.mod 2> /dev/null
AC_LANG_POP([Fortran])])

AS_VAR_COPY([$1], [ompi_cv_fortran_common_alignment])],
[AC_MSG_CHECKING([Fortran common alignment])
$1=0
AC_MSG_RESULT([skipped])])

])dnl
5 changes: 4 additions & 1 deletion config/ompi_setup_mpi_fortran.m4
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@ dnl Copyright (c) 2006-2008 Sun Microsystems, Inc. All rights reserved.
dnl Copyright (c) 2006-2007 Los Alamos National Security, LLC. All rights
dnl reserved.
dnl Copyright (c) 2009 Oak Ridge National Labs. All rights reserved.
dnl Copyright (c) 2014-2021 Research Organization for Information Science
dnl Copyright (c) 2014-2025 Research Organization for Information Science
dnl and Technology (RIST). All rights reserved.
dnl Copyright (c) 2016-2022 IBM Corporation. All rights reserved.
dnl Copyright (c) 2018 FUJITSU LIMITED. All rights reserved.
@@ -138,6 +138,9 @@ AC_DEFUN([OMPI_SETUP_MPI_FORTRAN],[
AC_DEFINE([ompi_fortran_bogus_type_t], [int],
[A bogus type that allows us to have sentinel type values that are still valid])

OMPI_FORTRAN_GET_COMMON_ALIGNMENT([OMPI_FORTRAN_COMMON_ALIGNMENT])
AC_SUBST([OMPI_FORTRAN_COMMON_ALIGNMENT])

# We want to set the #define's for all of these, so invoke the macros
# regardless of whether we have F77 support or not.
OMPI_FORTRAN_CHECK([CHARACTER], [yes],
3 changes: 2 additions & 1 deletion ompi/communicator/comm_init.c
Original file line number Diff line number Diff line change
@@ -27,6 +27,7 @@
* reserved.
* Copyright (c) 2023-2024 Advanced Micro Devices, Inc. All rights reserved.
* Copyright (c) 2023 NVIDIA Corporation. All rights reserved.
* Copyright (c) 2025 Jeffrey M. Squyres. All rights reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
@@ -453,7 +454,7 @@ static void ompi_comm_construct(ompi_communicator_t* comm)
comm->c_index_vec = NULL;

/*
* magic numerology - see TOPDIR/ompi/include/mpif-values.pl
* magic numerology - see TOPDIR/ompi/include/mpif-values.py
*/
idx = (comm == (ompi_communicator_t*)ompi_mpi_comm_world_addr) ? 0 :
(comm == (ompi_communicator_t*)ompi_mpi_comm_self_addr) ? 1 :
3 changes: 2 additions & 1 deletion ompi/datatype/ompi_datatype_module.c
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@
* Copyright (c) 2016-2018 FUJITSU LIMITED. All rights reserved.
* Copyright (c) 2018-2021 Triad National Security, LLC. All rights
* reserved.
* Copyright (c) 2025 Jeffrey M. Squyres. All rights reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
@@ -566,7 +567,7 @@ int32_t ompi_datatype_init( void )
} while(0)

/*
* This MUST match the order of ompi/include/mpif-values.pl
* This MUST match the order of ompi/include/mpif-values.py
* Any change will break binary compatibility of Fortran programs.
*/
MOOG(datatype_null, 0);
24 changes: 14 additions & 10 deletions ompi/include/Makefile.am
Original file line number Diff line number Diff line change
@@ -11,10 +11,11 @@
# All rights reserved.
# Copyright (c) 2006-2015 Cisco Systems, Inc. All rights reserved.
# Copyright (c) 2009-2011 Oak Ridge National Labs. All rights reserved.
# Copyright (c) 2014-2021 Research Organization for Information Science
# Copyright (c) 2014-2025 Research Organization for Information Science
# and Technology (RIST). All rights reserved.
# Copyright (c) 2018 FUJITSU LIMITED. All rights reserved.
# Copyright (c) 2022 IBM Corporation. All rights reserved.
# Copyright (c) 2025 Jeffrey M. Squyres. All rights reserved.
# $COPYRIGHT$
#
# Additional copyrights may follow
@@ -66,7 +67,7 @@ endif

include ompi/Makefile.am

# This is complicated, but mpif-values.pl generates several
# This is complicated, but mpif-values.py generates several
# mpif-*.h files in this directory (during autogen.pl).
# Hence, if any of those files change, it's safer to just force the
# user to re-autogen.
@@ -75,17 +76,17 @@ include ompi/Makefile.am
# @ echo "ERROR: you must re-run autogen.pl (sorry!)"
# @ exit 1

EXTRA_DIST = $(headers) mpif-values.pl
EXTRA_DIST = $(headers) mpif-values.py

#
# mpif-sizeof.h is generated based on some results from configure tests.
#

sizeof_pl=$(top_srcdir)/ompi/mpi/fortran/base/gen-mpi-sizeof.pl
sizeof_py=$(top_srcdir)/ompi/mpi/fortran/base/gen-mpi-sizeof.py
mpif-sizeof.h: $(top_builddir)/config.status
mpif-sizeof.h: $(sizeof_pl)
mpif-sizeof.h: $(sizeof_py)
mpif-sizeof.h:
$(OMPI_V_GEN) $(sizeof_pl) \
$(OMPI_V_GEN) $(python) $(sizeof_py) \
--header=$@ --ierror=mandatory \
--maxrank=$(OMPI_FORTRAN_MAX_ARRAY_RANK) \
--generate=$(OMPI_FORTRAN_BUILD_SIZEOF) \
@@ -102,15 +103,18 @@ mpif-sizeof.h:
# results from configure tests.
#

mpif_mangling_pl=$(top_srcdir)/ompi/mpi/fortran/base/gen-mpi-mangling.pl
mpif_mangling_py=$(top_srcdir)/ompi/mpi/fortran/base/gen-mpi-mangling.py
mpif-c-constants-decl.h: $(top_builddir)/config.status
mpif-c-constants-decl.h: $(mpif_mangling_pl)
mpif-c-constants-decl.h: $(mpif_mangling_py)
mpif-c-constants-decl.h:
$(OMPI_V_GEN) $(mpif_mangling_pl) \
$(OMPI_V_GEN) $(python) $(mpif_mangling_py) \
--caps $(OMPI_FORTRAN_CAPS) \
--plain $(OMPI_FORTRAN_PLAIN) \
--single $(OMPI_FORTRAN_SINGLE_UNDERSCORE) \
--double $(OMPI_FORTRAN_DOUBLE_UNDERSCORE)
--double $(OMPI_FORTRAN_DOUBLE_UNDERSCORE) \
--status-size $(OMPI_FORTRAN_STATUS_SIZE) \
--align $(OMPI_FORTRAN_COMMON_ALIGNMENT)


if WANT_INSTALL_HEADERS
ompidir = $(ompiincludedir)
15 changes: 8 additions & 7 deletions ompi/include/mpi.h.in
Original file line number Diff line number Diff line change
@@ -28,6 +28,7 @@
* Copyright (c) 2018-2022 Triad National Security, LLC. All rights
* reserved.
* Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved
* Copyright (c) 2025 Jeffrey M. Squyres. All rights reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
@@ -538,9 +539,9 @@ typedef MPI_Win_errhandler_function MPI_Win_errhandler_fn
* Miscellaneous constants
*
* NOTE: Many of the integer constants below *also* appear in
* ompi/include/mpif-values.pl. If you change any of these integer
* ompi/include/mpif-values.py. If you change any of these integer
* values below, make sure to also change the corresponding values in
* mpif-values.pl.
* mpif-values.py.
*/
#define MPI_ANY_SOURCE -1 /* match any source rank */
#define MPI_PROC_NULL -2 /* rank of null process */
@@ -583,7 +584,7 @@ typedef MPI_Win_errhandler_function MPI_Win_errhandler_fn
* Constants for C code to access elements in Fortran MPI status array.
*
* NOTE: The MPI_F_SOURCE, MPI_F_TAG, MPI_F_ERROR are intentionally 1
* smaller than their Fortran equivalents in mpif-values.pl (because C
* smaller than their Fortran equivalents in mpif-values.py (because C
* is 0-indexed and Fortran is 1-indexed).
*/
#define MPI_F_STATUS_SIZE OMPI_FORTRAN_STATUS_SIZE /* Size of Fortran MPI status array */
@@ -761,7 +762,7 @@ enum {
* Comparison results. Don't change the order of these, the group
* comparison functions rely on it.
* Do not change the order of these without also modifying
* mpif-values.pl.
* mpif-values.py.
*/
enum {
MPI_IDENT,
@@ -773,7 +774,7 @@ enum {
/*
* MPI_Init_thread constants
* Do not change the order of these without also modifying
* mpif-values.pl.
* mpif-values.py.
*/
enum {
MPI_THREAD_SINGLE,
@@ -785,7 +786,7 @@ enum {
/*
* Datatype combiners.
* Do not change the order of these without also modifying
* mpif-values.pl.
* mpif-values.py.
*/
enum {
MPI_COMBINER_NAMED,
@@ -837,7 +838,7 @@ enum {
/*
* Communicator split type constants.
* Do not change the order of these without also modifying
* mpif-values.pl.
* mpif-values.py.
*/
enum {
MPI_COMM_TYPE_SHARED,
3 changes: 2 additions & 1 deletion ompi/include/mpif-sentinels.h
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@
! All rights reserved.
! Copyright (c) 2006-2012 Cisco Systems, Inc. All rights reserved.
! Copyright (c) 2009 Oak Ridge National Labs. All rights reserved.
! Copyright (c) 2025 Jeffrey M. Squyres. All rights reserved.
! $COPYRIGHT$
!
! Additional copyrights may follow
@@ -26,7 +27,7 @@
!
! - the "mpi" module bindings
! - the "mpi_f08" module bindings
! - ompi/mpi/fortran/base/gen-mpi-mangling.pl
! - ompi/mpi/fortran/base/gen-mpi-mangling.py
!

! MPI_BOTTOM is only used where choice buffers can be used (meaning
571 changes: 0 additions & 571 deletions ompi/include/mpif-values.pl

This file was deleted.

567 changes: 567 additions & 0 deletions ompi/include/mpif-values.py

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions ompi/mpi/fortran/base/Makefile.am
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@
# Copyright (c) 2006-2015 Cisco Systems, Inc. All rights reserved.
# Copyright (c) 2015-2017 Research Organization for Information Science
# and Technology (RIST). All rights reserved.
# Copyright (c) 2025 Jeffrey M. Squyres. All rights reserved.
# $COPYRIGHT$
#
# Additional copyrights may follow
@@ -24,8 +25,8 @@ noinst_LTLIBRARIES =
EXTRA_DIST = \
attr-fn-int-callback-interfaces.h \
conversion-fn-null-int-interface.h \
gen-mpi-sizeof.pl \
gen-mpi-mangling.pl
gen-mpi-sizeof.py \
gen-mpi-mangling.py

#-----------------------------------------------------------------------------

206 changes: 0 additions & 206 deletions ompi/mpi/fortran/base/gen-mpi-mangling.pl

This file was deleted.

213 changes: 213 additions & 0 deletions ompi/mpi/fortran/base/gen-mpi-mangling.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
#!/usr/bin/env python3
#
# Copyright (c) 2015-2025 Research Organization for Information Science
# and Technology (RIST). All rights reserved.
# Copyright (c) 2015-2020 Cisco Systems, Inc. All rights reserved.
# Copyright (c) 2025 Jeffrey M. Squyres. All rights reserved.
# $COPYRIGHT$
#
# Subroutine to generate a bunch of Fortran declarations and symbols
#

import argparse
import os
import sys

from pathlib import Path

# File names
file_c_constants_decl = "mpif-c-constants-decl.h"
file_c_constants = "mpif-c-constants.h"
file_f08_types = "mpif-f08-types.h"

# Header comment block
header_comment = """/*
* Copyright (c) 2015-2025 Research Organization for Information Science
* and Technology (RIST). All rights reserved.
* Copyright (c) 2015-2020 Cisco Systems, Inc. All rights reserved.
* $COPYRIGHT$
*
* This file was generated by gen-mpi-mangling.py.
*/
"""

fortran_header_comment = """!
! Copyright (c) 2015-2025 Research Organization for Information Science
! and Technology (RIST). All rights reserved.
! Copyright (c) 2015-2020 Cisco Systems, Inc. All rights reserved.
! $COPYRIGHT$
!
! This file was generated by gen-mpi-mangling.py.
!"""

def get_fortran_constants(args):
return {
'bottom': {
'c_type': "MPI_Fint",
'c_name': "mpi_fortran_bottom",
'f_type': "integer",
'f_name': "MPI_BOTTOM",
},
'in_place': {
'c_type': "MPI_Fint",
'c_name': "mpi_fortran_in_place",
'f_type': "integer",
'f_name': "MPI_IN_PLACE",
},
'unweighted': {
'c_type': "MPI_Fint",
'c_name': "mpi_fortran_unweighted",
'f_type': "integer, dimension(1)",
'f_name': "MPI_UNWEIGHTED",
},
'weights_empty': {
'c_type': "MPI_Fint",
'c_name': "mpi_fortran_weights_empty",
'f_type': "integer, dimension(1)",
'f_name': "MPI_WEIGHTS_EMPTY",
},
'argv_null': {
'c_type': "char",
'c_name': "mpi_fortran_argv_null",
'f_type': "character, dimension(1)",
'f_name': "MPI_ARGV_NULL",
},
'argvs_null': {
'c_type': "char",
'c_name': "mpi_fortran_argvs_null",
'f_type': "character, dimension(1, 1)",
'f_name': "MPI_ARGVS_NULL",
},
'errcodes_ignore': {
'c_type': "MPI_Fint",
'c_name': "mpi_fortran_errcodes_ignore",
'f_type': "integer, dimension(1)",
'f_name': "MPI_ERRCODES_IGNORE",
},
'status_ignore': {
'c_type': "MPI_Fint",
'c_dim' : f"[{args.status_size}]",
'c_name': "mpi_fortran_status_ignore",
'f_type': "type(MPI_STATUS)",
'f_name': "MPI_STATUS_IGNORE",
},
'statuses_ignore': {
'c_type': "MPI_Fint",
'c_dim' : f"[{args.status_size}]",
'c_name': "mpi_fortran_statuses_ignore",
'f_type': "type(MPI_STATUS)",
'f_name': "MPI_STATUSES_IGNORE(1)",
},
}

def mangle(name, mangling_type):
# Mangles a C name based on the chosen Fortran mangling scheme
if mangling_type == 'plain':
return name
elif mangling_type == 'caps':
return name.upper()
elif mangling_type == 'single':
return name + "_"
elif mangling_type == 'double':
return name + "__"
else:
raise ValueError("Unknown name mangling type")

def gen_c_constants_decl(mangling_type, fortran_constants, args):
# Generates the mpif-c-constants-decl.h file
with open(file_c_constants_decl, "w") as f:
f.write("/* WARNING: This is a generated file! Edits will be lost! */\n")
f.write(header_comment)
f.write("\n/* Note that the rationale for the types of each of these variables is\n")
f.write(" discussed in ompi/include/mpif-common.h. Do not change the types\n")
f.write(" without also changing ompi/runtime/ompi_mpi_init.c and\n")
f.write(" ompi/include/mpif-common.h. */\n\n")

for key in sorted(fortran_constants.keys()):
const = fortran_constants[key]
mangled_name = mangle(const['c_name'], mangling_type)
dim = const.get('c_dim', '')
f.write(f"extern {const['c_type']} {mangled_name}{dim};\n")
f.write(f"#define OMPI_IS_FORTRAN_{key.upper()}(addr) \\\n")
f.write(f" (addr == (void*) &{mangled_name})\n\n")

def gen_c_constants(mangling_type, fortran_constants, args):
# Generates the mpif-c-constants.h file
with open(file_c_constants, "w") as f:
f.write("/* WARNING: This is a generated file! Edits will be lost! */\n")
f.write(header_comment)
f.write("\n")

for key in sorted(fortran_constants.keys()):
const = fortran_constants[key]
align = f" __opal_attribute_aligned__({args.align}) " if args.align else ' '
dim = const.get('c_dim', '')
mangled_name = mangle(const['c_name'], mangling_type)
f.write(f"{const['c_type']}{align}{mangled_name}{dim};\n")

def gen_f08_types(mangling_type, fortran_constants):
# Generates the mpif-f08-types.h file
with open(file_f08_types, "w") as f:
f.write("! WARNING: This is a generated file! Edits will be lost! */\n")
f.write(fortran_header_comment)
f.write("\n\n")

for key in sorted(fortran_constants.keys()):
const = fortran_constants[key]
mangled_name = mangle(const['c_name'], mangling_type)
f.write(f"{const['f_type']}, bind(C, name=\"{mangled_name}\") :: {const['f_name']}\n")


def main():
parser = argparse.ArgumentParser(description="Generate Fortran MPI mangling header files.")
parser.add_argument('--caps', type=int, default=0,
help='Use uppercase mangling')
parser.add_argument('--plain', type=int, default=0,
help='Use plain mangling (no change)')
parser.add_argument('--single', type=int, default=0,
help='Use single underscore suffix mangling')
parser.add_argument('--double', type=int, default=0,
help='Use double underscore suffix mangling')
parser.add_argument('--status-size', type=int, default=0,
help='Length of the Fortran MPI_Status array')
parser.add_argument('--align', type=int, default=0,
help='Alignment of Fortran intengers')

args = parser.parse_args()

if args.caps + args.plain + args.single + args.double > 1:
print("Cannot enable more than one mangling style")
exit(1)

mangling_type = None
if args.caps:
mangling_type = 'caps'
elif args.plain:
mangling_type = 'plain'
elif args.single:
mangling_type = 'single'
elif args.double:
mangling_type = 'double'

# If no mangling type is selected, create empty files
if mangling_type is None:
print("No Fortran mangling scheme specified. Creating empty files.")
Path(file_c_constants_decl).touch()
Path(file_c_constants).touch()
Path(file_f08_types).touch()
sys.exit(0)

# Generate the files based on the selected mangling type
try:
fortran_constants = get_fortran_constants(args)
gen_c_constants_decl(mangling_type, fortran_constants, args)
gen_c_constants(mangling_type, fortran_constants, args)
gen_f08_types(mangling_type, fortran_constants)
print(f"Generated files with '{mangling_type}' mangling.")
sys.exit(0)
except Exception as e:
print(f"Error generating files: {e}", file=sys.stderr)
sys.exit(1)

if __name__ == "__main__":
main()
283 changes: 0 additions & 283 deletions ompi/mpi/fortran/base/gen-mpi-sizeof.pl

This file was deleted.

328 changes: 328 additions & 0 deletions ompi/mpi/fortran/base/gen-mpi-sizeof.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,328 @@
#!/usr/bin/env python3
#
# Copyright (c) 2014-2015 Cisco Systems, Inc. All rights reserved.
# Copyright (c) 2015-2021 Research Organization for Information Science
# and Technology (RIST). All rights reserved.
# Copyright (c) 2022 IBM Corporation. All rights reserved.
# Copyright (c) 2025 Jeffrey M. Squyres. All rights reserved.
# $COPYRIGHT$
#
# Script to generate the overloaded MPI_SIZEOF interfaces and
# subroutine bodies for both the mpi and mpi_f08 modules.
#
# This script won't really be necessary (i.e., be a whole lot simpler)
# when Fortran compilers uniformly supprort TS 29113 -- i.e., they
# support dimension(..). Using dimension(..), you can have just *one*
# procedure for every type, and dimension(..) will resolve to both
# scalars and all possible ranks.
#
# But for the meantime, we generate for all ranks so that we support
# as many compilers as possible. :-\ (we don't check the compiler and
# see if it supports dimension(..) and do a different generation based
# on that, because we already have a zillion different options in the
# Fortran support -- let's just do MPI_Sizeof this one way in the name
# of simplicity...).
#

import argparse
import sys
import os
import copy

from pathlib import Path

# Global dictionary to store subroutine templates
subs = {}
indent = " "

# --- Helper Functions ---

def queue_sub(f_type, suffix, import_type=None, mpi_version=0, request_deprecate=False):
# Creates and stores a template for a Fortran subroutine
global subs
# Leave off the MPI/PMI prefix; we'll add that when outputting
sub_name = f"Sizeof_{suffix}"

# Make a dictionary for this subroutine
subr = {}
subr['name'] = sub_name
start = f"{indent}SUBROUTINE ^PREFIX^{sub_name}^RANK^(x, size, ierror)\n"
if import_type:
start += f"{indent} USE, INTRINSIC :: iso_fortran_env, ONLY: {import_type.upper()}\n"

# For long type names and large ranks, this first line gets very
# long and only narrowly squeezed in before 72 columns. Use no
# whitespace.
start += f"{indent}{f_type.upper()}^DIMENSION^::x\n"
start += f"{indent} INTEGER, INTENT(OUT) :: size\n"
start += f"{indent} INTEGER^IERROR_OPTIONAL^, INTENT(OUT) :: ierror"
subr['start'] = start

subr['middle'] = f"{indent} size = storage_size(x) / 8\n"
subr['middle'] += f"{indent} ^IERROR_STATEMENT^ierror = 0"

if mpi_version >= 4 and request_deprecate:
subr['end'] = f"!GCC$ ATTRIBUTES DEPRECATED :: ^PREFIX^{sub_name}^RANK^\n"
else:
subr['end'] = ""
subr['end'] += f"{indent}END SUBROUTINE ^PREFIX^{sub_name}^RANK^"

# Save it in the overall dictionary
subs[sub_name] = subr

def generate(prefix, sub_name, rank, want_body, optional_ierror_param, optional_ierror_statement):
# Generates the Fortran code for a specific subroutine
global subs
if sub_name not in subs:
# This can happen if a type was conditionally excluded
return ""

# Deep copy the template
subr = copy.deepcopy(subs[sub_name])

# Make the initial version
str_out = subr['start'] + "\n"
if want_body:
str_out += "\n" + subr['middle'] + "\n"
str_out += subr['end'] + "\n"

# Substitute in the relevant parameters
str_out = str_out.replace('^PREFIX^', prefix)
str_out = str_out.replace('^IERROR_OPTIONAL^', optional_ierror_param)
str_out = str_out.replace('^IERROR_STATEMENT^', optional_ierror_statement)


# If rank is 0, generate a scalar version. Otherwise, generate an
# array version.
if rank == 0:
str_out = str_out.replace('^RANK^', '_scalar')
str_out = str_out.replace('^DIMENSION^', '')
else:
str_out = str_out.replace('^RANK^', f'_r{rank}')
# Generate dimension string like "1,"*(rank-1) + "*"
dim = ",".join(['1'] * (rank - 1))
if rank > 1:
dim += ","
dim += "*" # Add the final asterisk
str_out = str_out.replace('^DIMENSION^', f', DIMENSION({dim})')


# All done
return str_out

def output_content(f, prefix, want_bodies, maxrank, optional_ierror_param, optional_ierror_statement):
# Writes the generated content (interfaces or bodies) to the file object
global subs
global indent

if not want_bodies:
f.write(f"{indent}INTERFACE {prefix}Sizeof\n\n")

# Print all the module procedure lines
for sub_name in sorted(subs.keys()):
rank = 0
while rank <= maxrank:
str_generated = generate(prefix, sub_name, rank, want_bodies,
optional_ierror_param, optional_ierror_statement)
if str_generated: # Only write if generate didn't return empty
f.write(str_generated + "\n")
rank += 1

if not want_bodies:
f.write(f"{indent}END INTERFACE {prefix}Sizeof\n\n")

def output_file(filename, want_bodies, args):
# Generates and writes the complete output file
global indent

# Determine optional ierror parts
optional_ierror_param = ""
optional_ierror_statement = ""
if args.ierror and args.ierror.lower() == "optional":
optional_ierror_param = ", OPTIONAL"
optional_ierror_statement = "IF (present(ierror)) "


try:
# Delete existing file first, like Perl's unlink
if os.path.exists(filename):
os.unlink(filename)

with open(filename, "w") as f:
f.write("""! -*- f90 -*-
! WARNING: This is a generated file! Edits will be lost!
!
! Copyright (c) 2014-2015 Cisco Systems, Inc. All rights reserved.
! Copyright (c) 2015-2021 Research Organization for Information Science
! and Technology (RIST). All rights reserved.
! Copyright (c) 2022 IBM Corporation. All rights reserved.
! $COPYRIGHT$
!
! This file was generated by gen-mpi-sizeof.py for all the MPI_SIZEOF
! interface possibilities for intrinsic types. Once TS 29113 is
! supported in all compilers, we can simply have *one* procedure for
! each type and use dimension(..) to indicate scalars+all array ranks.
! But until more compilers support this, we simply generate a
! procedure for scalars and all possible ranks in an attempt to
! support lots of Fortran compilers.
""")

# Only output if the generate arg is True. Otherwise, output an
# empty .h file (that is still safe to include by mpif.h, but
# won't include the MPI_SIZEOF interface block).
if args.generate:
# Call queue_sub for all required types *before* outputting
for size in [8, 16, 32, 64]:
queue_sub(f"integer(int{size})", f"int{size}", f"int{size}", args.mpi_version, args.request_deprecate)

for size in [16, 32, 64, 128]:
# Check conditions before queueing real types
queue_real = True
if size == 16 and not args.real2 and not args.iso_real16:
queue_real = False
if size == 128 and not args.real16:
queue_real = False
if queue_real:
queue_sub(f"real(real{size})", f"real{size}", f"real{size}", args.mpi_version, args.request_deprecate)

# Check conditions before queueing complex types
queue_complex = True
if size == 16 and not args.complex4 and not args.iso_real16:
queue_complex = False
if size == 128 and not args.complex32:
queue_complex = False
if queue_complex:
queue_sub(f"complex(real{size})", f"complex{size}", f"real{size}", args.mpi_version, args.request_deprecate)

# Handle special non-ISO types if needed
if args.real2 and not args.iso_real16:
queue_sub("real*2", "real16", mpi_version=args.mpi_version, request_deprecate=args.request_deprecate) # No import_type for non-standard
# Assume complex*4 goes with real*2 if iso_real16 is not used
if args.complex4 and not args.iso_real16:
queue_sub("complex*4", "complex16", mpi_version=args.mpi_version, request_deprecate=args.request_deprecate) # No import_type for non-standard

queue_sub("character", "character", mpi_version=args.mpi_version, request_deprecate=args.request_deprecate) # No iso_fortran_env needed
queue_sub("logical", "logical", mpi_version=args.mpi_version, request_deprecate=args.request_deprecate) # No iso_fortran_env needed


# --- Generate Content ---
if not want_bodies or (want_bodies and args.mpi):
output_content(f, "MPI_", want_bodies, args.maxrank,
optional_ierror_param, optional_ierror_statement)
if not want_bodies or (want_bodies and args.pmpi):
output_content(f, "PMPI_", want_bodies, args.maxrank,
optional_ierror_param, optional_ierror_statement)
else:
# Sad panda message
f.write("""! *** ATTENTION!
!
! Sad panda.
!
! This compiler does not support the Right Stuff to enable MPI_SIZEOF.
! Specifically: we need support for the INTERFACE keyword,
! ISO_FORTRAN_ENV, and the STORAGE_SIZE() intrinsic on all types.
! Apparently, this compiler does not support both of those things, so
! this file will be (effectively) blank (i.e., we didn't bother
! generating the necessary stuff for MPI_SIZEOF because the compiler
! doesn't support
! it).
!
! If you want support for MPI_SIZEOF, please use a different Fortran
! compiler to build Open MPI.
""")
if want_bodies:
name = "pompi_sad_panda" if args.pmpi else "ompi_sad_panda"
f.write(f"""!
! Dummy subroutine, just so that there is *some* Fortran in this file
! (this is defensive programming: since the Fortran compiler doesn't
! support enough mojo, configure should set some AM_CONDITIONALs such
! that this file should not end up being compiled, but just in case
! that logic changes someday and this file *does* end up getting
! compiled, make sure that it's not entirely empty because some
! compilers are unhappy if there are no Fortran statements in this
! file).
subroutine {name}()
implicit none
print *, 'Open MPI is a sad panda because your Fortran compiler'
print *, 'does not support enough Fortran mojo for MPI_SIZEOF'
end subroutine {name}
""")
except IOError as e:
print(f"Error writing to file {filename}: {e}", file=sys.stderr)
sys.exit(1)

# --- Main Execution ---

def main():
parser = argparse.ArgumentParser(description="Generate Fortran MPI_SIZEOF interfaces and implementations.")

# File outputs
parser.add_argument("--header",
help="Filename for the interface header output.")
parser.add_argument("--impl",
help="Filename for the implementation subroutine output.")

# Control flags
parser.add_argument("--generate", type=int, default=0,
help="Actually generate MPI_SIZEOF (otherwise output 'sad panda').")
parser.add_argument("--ierror", choices=['optional', 'mandatory'],
help="How to handle the ierror parameter.")
parser.add_argument("--maxrank", type=int, default=7,
help="Maximum array rank to generate (default: 7, must be >=4, <=15).")
parser.add_argument("--mpi", action='store_true',
help="Generate MPI_ prefixed routines (for --impl).")
parser.add_argument("--pmpi", action='store_true',
help="Generate PMPI_ prefixed routines (for --impl).")
parser.add_argument("--request_deprecate", type=int, default=0,
help="Add GCC DEPRECATED attribute if MPI version >= 4")
parser.add_argument("--mpi_version", type=int, default=3,
help="MPI Standard version (e.g., 3 or 4)")

# Type support flags
parser.add_argument("--complex32", type=int, default=0,
help="Enable Complex*32 support (real128).")
parser.add_argument("--complex4", type=int, default=0,
help="Enable Complex*4 support (real16).")
parser.add_argument("--real16", type=int, default=0,
help="Enable Real*16 support (real128).")
parser.add_argument("--real2", type=int, default=0,
help="Enable Real*2 support (real16).")
parser.add_argument("--iso_real16", type=int, default=0,
help="Use ISO_FORTRAN_ENV real16 (overrides real2/complex4 if both specified).")

args = parser.parse_args()

# --- Argument Validation ---
if not args.header and not args.impl:
parser.error("Must specify --header and/or --impl filenames to output.")

if args.generate:
if not args.ierror:
parser.error("--ierror must be specified when --generate is used.")
if not (4 <= args.maxrank <= 15):
parser.error("--maxrank must be >= 4 and <= 15.")
if args.impl and not args.mpi and not args.pmpi:
parser.error("Must specify --pmpi and/or --mpi if --impl is specified.")
# Note: The Perl script checked for presence of all type flags,
# but argparse with action='store_true' defaults them to False if not given.
# The logic in output_file now handles the conditional generation based
# on these boolean flags.

# --- File Generation ---
if args.header:
print(f"Generating header file: {args.header}")
output_file(args.header, want_bodies=False, args=args)

if args.impl:
print(f"Generating implementation file: {args.impl}")
output_file(args.impl, want_bodies=True, args=args)

print("Done.")
sys.exit(0)

if __name__ == "__main__":
main()
7 changes: 4 additions & 3 deletions ompi/mpi/fortran/mpif-h/Makefile.am
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@
# Copyright (c) 2018 FUJITSU LIMITED. All rights reserved.
# Copyright (c) 2021-2022 Triad National Security, LLC. All rights
# reserved.
# Copyright (c) 2025 Jeffrey M. Squyres. All rights reserved.
#
# $COPYRIGHT$
#
@@ -115,12 +116,12 @@ nodist_libmpi_mpifh_sizeof_la_SOURCES = sizeof_f.f90
lib@OMPI_LIBMPI_NAME@_mpifh_la_LIBADD += libmpi_mpifh_sizeof.la
endif

sizeof_pl = $(top_srcdir)/ompi/mpi/fortran/base/gen-mpi-sizeof.pl
sizeof_py = $(top_srcdir)/ompi/mpi/fortran/base/gen-mpi-sizeof.py

sizeof_f.f90: $(top_builddir)/config.status
sizeof_f.f90: $(sizeof_pl)
sizeof_f.f90: $(sizeof_py)
sizeof_f.f90:
$(OMPI_V_GEN) $(sizeof_pl) \
$(OMPI_V_GEN) $(python) $(sizeof_py) \
--impl=$@ --ierror=mandatory --mpi \
--maxrank=$(OMPI_FORTRAN_MAX_ARRAY_RANK) \
--generate=$(OMPI_FORTRAN_BUILD_SIZEOF) \
7 changes: 4 additions & 3 deletions ompi/mpi/fortran/mpif-h/profile/Makefile.am
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@
# Copyright (c) 2018 FUJITSU LIMITED. All rights reserved.
# Copyright (c) 2019-2022 Triad National Security, LLC. All rights
# reserved.
# Copyright (c) 2025 Jeffrey M. Squyres. All rights reserved.
# $COPYRIGHT$
#
# Additional copyrights may follow
@@ -486,12 +487,12 @@ nodist_libmpi_mpifh_psizeof_la_SOURCES = psizeof_f.f90
libmpi_mpifh_pmpi_la_LIBADD += libmpi_mpifh_psizeof.la
endif

sizeof_pl=$(top_srcdir)/ompi/mpi/fortran/base/gen-mpi-sizeof.pl
sizeof_py=$(top_srcdir)/ompi/mpi/fortran/base/gen-mpi-sizeof.py

psizeof_f.f90: $(top_builddir)/config.status
psizeof_f.f90: $(sizeof_pl)
psizeof_f.f90: $(sizeof_py)
psizeof_f.f90:
$(OMPI_V_GEN) $(sizeof_pl) \
$(OMPI_V_GEN) $(python) $(sizeof_py) \
--impl=$@ --ierror=mandatory --pmpi \
--maxrank=$(OMPI_FORTRAN_MAX_ARRAY_RANK) \
--generate=$(OMPI_FORTRAN_BUILD_SIZEOF) \
15 changes: 8 additions & 7 deletions ompi/mpi/fortran/use-mpi-f08/Makefile.am
Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@
# reserved.
# Copyright (c) 2020 Sandia National Laboratories. All rights reserved.
# Copyright (c) 2022 IBM Corporation. All rights reserved.
# Copyright (c) 2025 Jeffrey M. Squyres. All rights reserved.
#
# $COPYRIGHT$
#
@@ -79,12 +80,12 @@ mpi-f08.lo: sizeof_f08.h
# configure tests.
#

sizeof_pl=$(top_srcdir)/ompi/mpi/fortran/base/gen-mpi-sizeof.pl
sizeof_py=$(top_srcdir)/ompi/mpi/fortran/base/gen-mpi-sizeof.py

sizeof_f08.h: $(top_builddir)/config.status
sizeof_f08.h: $(sizeof_pl)
sizeof_f08.h: $(sizeof_py)
sizeof_f08.h:
$(OMPI_V_GEN) $(sizeof_pl) \
$(OMPI_V_GEN) $(python) $(sizeof_py) \
--header=$@ --ierror=optional \
--maxrank=$(OMPI_FORTRAN_MAX_ARRAY_RANK) \
--generate=$(OMPI_FORTRAN_BUILD_SIZEOF) \
@@ -97,9 +98,9 @@ sizeof_f08.h:
--request_deprecate=$(OMPI_FORTRAN_HAVE_ATTR_DEPRECATED)

sizeof_f08.f90: $(top_builddir)/config.status
sizeof_f08.f90: $(sizeof_pl)
sizeof_f08.f90: $(sizeof_py)
sizeof_f08.f90:
$(OMPI_V_GEN) $(sizeof_pl) \
$(OMPI_V_GEN) $(python) $(sizeof_py) \
--impl=$@ --ierror=optional --mpi \
--maxrank=$(OMPI_FORTRAN_MAX_ARRAY_RANK) \
--generate=$(OMPI_FORTRAN_BUILD_SIZEOF) \
@@ -110,9 +111,9 @@ sizeof_f08.f90:
--complex32=$(OMPI_HAVE_FORTRAN_COMPLEX32)

psizeof_f08.f90: $(top_builddir)/config.status
psizeof_f08.f90: $(sizeof_pl)
psizeof_f08.f90: $(sizeof_py)
psizeof_f08.f90:
$(OMPI_V_GEN) $(sizeof_pl) \
$(OMPI_V_GEN) $(python) $(sizeof_py) \
--impl=$@ --ierror=optional --pmpi \
--maxrank=$(OMPI_FORTRAN_MAX_ARRAY_RANK) \
--generate=$(OMPI_FORTRAN_BUILD_SIZEOF) \
11 changes: 6 additions & 5 deletions ompi/mpi/fortran/use-mpi-ignore-tkr/Makefile.am
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@
#
# Copyright (c) 2018 FUJITSU LIMITED. All rights reserved.
# Copyright (c) 2022 IBM Corporation. All rights reserved.
# Copyright (c) 2025 Jeffrey M. Squyres. All rights reserved.
# $COPYRIGHT$
#
# Additional copyrights may follow
@@ -93,12 +94,12 @@ lib@OMPI_LIBMPI_NAME@_usempi_ignore_tkr_la_LDFLAGS = \
# configure tests.
#

sizeof_pl=$(top_srcdir)/ompi/mpi/fortran/base/gen-mpi-sizeof.pl
sizeof_py=$(top_srcdir)/ompi/mpi/fortran/base/gen-mpi-sizeof.py

mpi-ignore-tkr-sizeof.h: $(top_builddir)/config.status
mpi-ignore-tkr-sizeof.h: $(sizeof_pl)
mpi-ignore-tkr-sizeof.h: $(sizeof_py)
mpi-ignore-tkr-sizeof.h:
$(OMPI_V_GEN) $(sizeof_pl) \
$(OMPI_V_GEN) $(python) $(sizeof_py) \
--header=$@ --ierror=mandatory \
--maxrank=$(OMPI_FORTRAN_MAX_ARRAY_RANK) \
--generate=$(OMPI_FORTRAN_BUILD_SIZEOF) \
@@ -111,9 +112,9 @@ mpi-ignore-tkr-sizeof.h:
--request_deprecate=$(OMPI_FORTRAN_HAVE_ATTR_DEPRECATED)

mpi-ignore-tkr-sizeof.f90: $(top_builddir)/config.status
mpi-ignore-tkr-sizeof.f90: $(sizeof_pl)
mpi-ignore-tkr-sizeof.f90: $(sizeof_py)
mpi-ignore-tkr-sizeof.f90:
$(OMPI_V_GEN) $(sizeof_pl) \
$(OMPI_V_GEN) $(python) $(sizeof_py) \
--impl=$@ --ierror=mandatory --mpi --pmpi \
--maxrank=$(OMPI_FORTRAN_MAX_ARRAY_RANK) \
--generate=$(OMPI_FORTRAN_BUILD_SIZEOF) \