I am trying to understand the solution I was provided to a problem I encountered while compiling an MPI program using intel compilers (see Solved: Error: Symbol ‘mpi_gather’ referenced at (1) not found in module ‘mpi’ - Intel Community). For a simple test program like,
! @file test_mpi.f90
program test_mpi
use mpi, only: mpi_gather, mpi_init, mpi_finalize
end program
and attempting to compile with intel compilers
. /opt/intel/oneapi/setvars.sh
which mpif90
# /opt/intel/oneapi/mpi/2021.14/bin/mpif90
mpif90 --version
# GNU Fortran (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0
# Copyright (C) 2023 Free Software Foundation, Inc.
# This is free software; see the source for copying conditions. There is NO
# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
mpif90 test_mpi.f90
the resulting error is
Error: Symbol ‘mpi_gather’ referenced at (1) not found in module ‘mpi’
It turns out, the solution to this problem is to simply remove the mpi_gather routine from the only args list, however, the mpi_gather routine is still usable in the above test program even though it’s not explicitly imported (since an explicit interface doesn’t exist for it anyways, see the Intel community discussion at the beginning of my post for details). Using the more modern mpi_f08 module (your program must be compiled with mpiifx if you want to do this) has the same behavior, that is routines like mpi_send, mpi_gather, etc are all usable in the final binary despite never having been explicitly included via only: ....
Why and/or how is it that such routines are usable even though they are not explicitly included in the only list? It seems like this violates expected behavior since if one sees a module file containing
use mpi, only: mpi_gather, mpi_init, mpi_finalize
then naturally I would expect only those functions to be used in the file, however, this contract is not enforced.
A full example of this behavior (routines not explicitly included are usable) can be shown in the below program:
! @file mpi_send_example.f90
!
! @usage
! mpif90 mpi_send_example.f90
! mpirun -n 2 ./a.out
program mpi_send_example
use mpi, only: MPI_INTEGER, MPI_COMM_WORLD, MPI_STATUS_IGNORE
implicit none
integer :: ierr, rank, size
integer :: tag, source, dest
integer :: message
! Initialize MPI
call MPI_Init(ierr)
call MPI_Comm_rank(MPI_COMM_WORLD, rank, ierr)
call MPI_Comm_size(MPI_COMM_WORLD, size, ierr)
tag = 0
source = 0
dest = 1
if (size < 2) then
if (rank == 0) print *, "This program needs at least 2 MPI processes."
call MPI_Finalize(ierr)
stop
end if
if (rank == source) then
message = 42
print *, "Rank", rank, "sending message:", message, "to rank", dest
call MPI_Send(message, 1, MPI_INTEGER, dest, tag, MPI_COMM_WORLD, ierr)
else if (rank == dest) then
call MPI_Recv(message, 1, MPI_INTEGER, source, tag, MPI_COMM_WORLD, MPI_STATUS_IGNORE, ierr)
print *, "Rank", rank, "received message:", message, "from rank", source
end if
call MPI_Finalize(ierr)
end program mpi_send_example