Skip to content

Commit

Permalink
ompi_setup_fc.m4: use -Wl,-ld_classic if supported
Browse files Browse the repository at this point in the history
Per open-mpi#12427, on MacOS, add
-Wl,-ld_classic to the Fortran wrapper compiler if that flag is
needed.

Specifically, Open MPI has used -Wl,-commons,use_dylibs for decades to
support common symbols (e.g., MPI_BOTTOM) in the Fortran bindings.
There is a window of Xcode versions where this switch was effectively
disabled; it effectively required the additional -Wl,-ld_classic
switch to force the use of the "old" Apple linker (that still
supported -Wl,-commons,use_dylibs).  Update the configury to test
whether we need -Wl,-ld_classic or not.

Signed-off-by: Jeff Squyres <[email protected]>
  • Loading branch information
jsquyres committed Jul 7, 2024
1 parent 8b7e577 commit 9ef1042
Showing 1 changed file with 162 additions and 14 deletions.
176 changes: 162 additions & 14 deletions config/ompi_setup_fc.m4
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,168 @@ AC_DEFUN_ONCE([_OMPI_SETUP_FC_COMPILER],[

#############################################################################

dnl On macOS with Xcode, test whether -Wl,-commons,use_dylibs works
dnl by itself or whether it also needs -Wl,-ld_classic.
dnl
dnl * It seems to always work (by itself) when building static
dnl libraries.
dnl * It seems to fail (by itself) when building shared libraries for
dnl certain versions of Xcode. In these failure scenarios, we add
dnl -Wl,-ld_classic to make it work.
dnl
dnl Note: the -ld_classic flag works with both static and shared
dnl libraries, so it is safe to always do this test -- even if
dnl we are only building static libraries.
dnl
dnl The history is that for a long time (decades),
dnl -Wl,-commons,use_dylibs worked by itself. But then Apple decided
dnl to remove support for it, and cause link-time errors with MPI
dnl Fortran sentinel values (e.g., MPI_BOTTOM) because they are
dnl implemented with Fortran common blocks. Later, Xcode v16
dnl (re)added support for -Wl,commons,use_dylibs again. Hence, there
dnl is a window of a few versions of Xcode that need the additional
dnl -Wl,ld_classic flag to link/work properly.
dnl
dnl We have to use a slightly complex test code that will actually
dnl fail if the version of Xcode being used requires -Wl,-ld_classic
dnl with -Wl,-commons,use_dylibs.
dnl
dnl 1. Build a shared library (with C source code) with a public
dnl symbol that can be used as a Fortran common block symbol.
dnl 2. Compile a Fortran program that calls a function in the shared
dnl library, and link it against the shared library.
dnl
dnl Note: This is a linker test; we are checking to see if this all
dnl compiles and links properly. The logic in the C / Fortran code
dnl below specifically does not test for correctness because we do not
dnl actually run the code.
AC_DEFUN([_OMPI_SETUP_FC_XCODE_COMMONS_LDFLAGS],[
OPAL_VAR_SCOPE_PUSH([xcode_flags])

# This variable is used by the invoking macro to display the
# results via AC RESULT (just to keep the symmetry of
# MSG_CHECKING / RESULT in the same upper-level macro).
OMPI_FORTRAN_WRAPPER_FLAGS=

xcode_flags="-Wl,-commons,use_dylibs"
_OMPI_SETUP_FC_XCODE_COMMONS_LDFLAGS_BACKEND(
[$xcode_flags],
[OMPI_FORTRAN_WRAPPER_FLAGS=$xcode_flags], [])
AS_IF([test -z "$OMPI_FORTRAN_WRAPPER_FLAGS"],
[xcode_flags="-Wl,-commons,use_dylibs -Wl,-ld_classic"
_OMPI_SETUP_FC_XCODE_COMMONS_LDFLAGS_BACKEND(
[$xcode_flags],
[OMPI_FORTRAN_WRAPPER_FLAGS=$xcode_flags], [])])
AS_IF([test -z "$OMPI_FORTRAN_WRAPPER_FLAGS"],
[OMPI_FORTRAN_WRAPPER_FLAGS="none"])

OPAL_VAR_SCOPE_POP
])

dnl Companion to _OMPI SETUP_FC_XCODE_COMMONS_LDFLAGS;
dnl see that macro for an explanation of this macro.
dnl
dnl $1: LDFLAGS to test
dnl $2: action to perform upon success
dnl $3: action to perform upon failure
AC_DEFUN([_OMPI_SETUP_FC_XCODE_COMMONS_LDFLAGS_BACKEND],[
OPAL_VAR_SCOPE_PUSH([xcode_happy xcode_dir LDFLAGS_save_xcode LIBS_save_xcode])

xcode_dir=conftest.$$
rm -rf $xcode_dir
mkdir -p $xcode_dir
cd $xcode_dir

LIBS_save_xcode=$LIBS
LDFLAGS_save_xcode=$LDFLAGS
LDFLAGS="$LDFLAGS -L. $1"

# Note: we use COMPILE_IFELSE and LANG_SOURCE below, which assume
# that confdefs.h exists. This is being invoked extremely early
# in the configure sequence, so we haven't AC DEFINE'ed anything
# yet, and therefore confdefs.h won't be automatically created
# yet. So we'll make an empty confdefs.h to avoid some error
# messages (it'll be removed with the whole tempdir, later).
touch confdefs.h

# Step 1: make a C library with some public symbols
xcode_happy=0
AC_LANG_PUSH([C])
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
/* Must end the symbol in _ (remember: we are specifically targeting
the MacOS compilation environment, so it is ok to target a specific
Fortran symbol convention), otherwise the Fortran linker will not
find it, and will just create a new Fortran symbol for it */
int ompi_mpi_bottom_ = 42;

void ompi_init_f(int *bogus);

/* Empty / useless function that still ensures that this compilation
unit will not be optimized out */
void ompi_init_f(int *bogus)
{
*bogus = ompi_mpi_bottom_;
}
]])],
[ # If the above compiled successfully, Then use
# conftest.OBJEXT to make the library. Note that
# conftest.OBJEXT will automatically be deleted upon exit of
# COMPILE_IFELSE.
OPAL_LOG_COMMAND([$CC -dynamiclib -Wl,-undefined -Wl,dynamic_lookup $LDFLAGS conftest.$OBJEXT -o libconftest.dylib],
[xcode_happy=1])])
AC_LANG_POP

# Now compile and link a Fortran program against this shared
# library.
AC_LANG_PUSH([Fortran])
AS_IF([test $xcode_happy -eq 1],
[LIBS="$LIBS -lconftest"
AC_LINK_IFELSE([AC_LANG_SOURCE([
program test
integer :: mpi_bottom
common/ompi_mpi_bottom/mpi_bottom

interface
subroutine ompi_init(bogus) BIND(C, name="ompi_init_f")
implicit none
integer bogus
end subroutine ompi_init
end interface

integer bogus
call ompi_init(bogus)
end program
])],

[],
[xcode_happy=0])])
AC_LANG_POP

# Exit the temp dir
cd ..
rm -rf $xcode_dir

# LIBS was set specifically for the artificial conditions of this
# test, so reset it
LIBS=$LIBS_save_xcode

AS_IF([test $xcode_happy -eq 1],
[$2],
[ # If we failed the test, reset LDFLAGS back to its
# original value (if we passed the test, we'll leave
# LDFLAGS modified with the new flags so that we use them
# to build Open MPI).
LDFLAGS=$LDFLAGS_xcode_save
$3])

OPAL_VAR_SCOPE_POP
])

#############################################################################

# General Fortran compiler setup
AC_DEFUN([OMPI_SETUP_FC],[
OPAL_VAR_SCOPE_PUSH([ompi_fc_happy LDFLAGS_save fc_version])
OPAL_VAR_SCOPE_PUSH([ompi_fc_happy LDFLAGS_save fc_version OMPI_FORTRAN_WRAPPER_FLAGS])

# Force the intro banner to be displayed first
AC_REQUIRE([_OMPI_SETUP_FC_BANNER])
Expand Down Expand Up @@ -226,23 +385,12 @@ I = 3]])],
])
])

# Per #1982, on OS X, we may need some esoteric linker flags in the
# Per Trac #1982, on OS X, we may need some esoteric linker flags in the
# Fortran wrapper compiler.
AC_MSG_CHECKING([to see if mpifort compiler needs additional linker flags])
case "$host" in
*apple-darwin*)
# Test whether -Wl,-commons,use_dylibs works; if it does, use it.
LDFLAGS_save=$LDFLAGS
LDFLAGS="$LDFLAGS -Wl,-commons,use_dylibs"
AC_LANG_PUSH([Fortran])
AC_LINK_IFELSE([AC_LANG_SOURCE([[program test
integer :: i
end program]])],
[OMPI_FORTRAN_WRAPPER_FLAGS="-Wl,-commons,use_dylibs"
OPAL_WRAPPER_FLAGS_ADD([FCFLAGS], [$OMPI_FORTRAN_WRAPPER_FLAGS])],
[OMPI_FORTRAN_WRAPPER_FLAGS=none])
AC_LANG_POP([Fortran])
LDFLAGS=$LDFLAGS_save
_OMPI_SETUP_FC_XCODE_COMMONS_LDFLAGS
AC_MSG_RESULT([$OMPI_FORTRAN_WRAPPER_FLAGS])
;;
*)
Expand Down

0 comments on commit 9ef1042

Please sign in to comment.