Help with CMake, Intel MPI, and GNU Fortran

All,

I’m hoping to get some help using Intel MPI with CMake, but with GNU Fortran as the compiler, not Intel Fortran (which works fine). For example, I have a code called mpiversion.F90 that isn’t very special:

program main
   use mpi
   implicit none

   integer :: ierror, n 
   character(MPI_MAX_LIBRARY_VERSION_STRING) :: version_string

   call MPI_Get_library_version(version_string, n, ierror)

   write(*,*) trim(version_string)
end program main

And I have loaded GCC 8.3.0 and Intel MPI 2019 Update 5:

(1039) $ gfortran --version
GNU Fortran (GCC) 8.3.0
Copyright (C) 2018 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.

(1040) $ mpirun --version
Intel(R) MPI Library for Linux* OS, Version 2019 Update 5 Build 20190806 (id: 7e5a4f84c)
Copyright 2003-2019, Intel Corporation.

And I can build and run the program just fine by hand using the mpifc wrapper:

(1043) $ mpifc -o mpiversion.exe mpiversion.F90
(1044) $ ./mpiversion.exe 
 Intel(R) MPI Library 2019 Update 5 for Linux* OS

Now I try to make a simple CMakeLists.txt file:

cmake_minimum_required(VERSION 3.15.5)
project(mpiversion VERSION 1.0.0 LANGUAGES Fortran)
find_package(MPI REQUIRED)
message(STATUS "MPI_Fortran_COMPILER: ${MPI_Fortran_COMPILER}")
add_executable(mpiversion.exe mpiversion.F90)
target_link_libraries(mpiversion.exe PRIVATE MPI::MPI_Fortran)

This CMake file works just happily with Intel Fortran and Intel MPI. But when I try with gfortran and Intel MPI:

(1069) $ cmake ..
-- The Fortran compiler identification is GNU 8.3.0
-- Check for working Fortran compiler: /usr/local/other/gcc/8.3.0/bin/gfortran
-- Check for working Fortran compiler: /usr/local/other/gcc/8.3.0/bin/gfortran  -- works
-- Detecting Fortran compiler ABI info
-- Detecting Fortran compiler ABI info - done
-- Checking whether /usr/local/other/gcc/8.3.0/bin/gfortran supports Fortran 90
-- Checking whether /usr/local/other/gcc/8.3.0/bin/gfortran supports Fortran 90 -- yes
-- Found MPI_Fortran: /gpfsm/dulocal/sles12/intel/2019/compilers_and_libraries_2019.5.281/linux/mpi/intel64/lib/libmpifort.so (found version "3.1") 
-- Found MPI: TRUE (found version "3.1")  
-- MPI_Fortran_COMPILER: /usr/local/intel/2019/compilers_and_libraries_2019.5.281/linux/mpi/intel64/bin/mpif90
-- Configuring done
-- Generating done
-- Build files have been written to: /home/mathomp4/MPIVersionCMake/Fortran/build-GNUIMPI
(1070) $ make
Scanning dependencies of target mpiversion.exe
[ 50%] Building Fortran object CMakeFiles/mpiversion.exe.dir/mpiversion.F90.o
f951: Fatal Error: Reading module ‘mpi’ at line 1 column 2: Unexpected EOF
compilation terminated.
CMakeFiles/mpiversion.exe.dir/build.make:62: recipe for target 'CMakeFiles/mpiversion.exe.dir/mpiversion.F90.o' failed
make[2]: *** [CMakeFiles/mpiversion.exe.dir/mpiversion.F90.o] Error 1
CMakeFiles/Makefile2:75: recipe for target 'CMakeFiles/mpiversion.exe.dir/all' failed
make[1]: *** [CMakeFiles/mpiversion.exe.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2

So, first it picked the wrong MPI_Fortran_COMPILER wrapper, mpif90 instead of mpifc, but if I do a verbose make:

[ 50%] Building Fortran object CMakeFiles/mpiversion.exe.dir/mpiversion.F90.o
/usr/local/other/gcc/8.3.0/bin/gfortran  -I/gpfsm/dulocal/sles12/intel/2019/compilers_and_libraries_2019.5.281/linux/mpi/intel64/include -I/gpfsm/dulocal/sles12/intel/2019/compilers_and_libraries_2019.5.281/linux/mpi/intel64/include/gfortran/8.2.0   -c /home/mathomp4/MPIVersionCMake/Fortran/mpiversion.F90 -o CMakeFiles/mpiversion.exe.dir/mpiversion.F90.o
f951: Fatal Error: Reading module ‘mpi’ at line 1 column 2: Unexpected EOF
compilation terminated.
CMakeFiles/mpiversion.exe.dir/build.make:62: recipe for target 'CMakeFiles/mpiversion.exe.dir/mpiversion.F90.o' failed

and compare to from mpifc -show:

(1072) $ mpifc -show
gfortran -I/usr/local/intel/2019/compilers_and_libraries_2019.5.281/linux/mpi/intel64/include/gfortran/8.2.0 -I/usr/local/intel/2019/compilers_and_libraries_2019.5.281/linux/mpi/intel64/include -L/usr/local/intel/2019/compilers_and_libraries_2019.5.281/linux/mpi/intel64/lib/release -L/usr/local/intel/2019/compilers_and_libraries_2019.5.281/linux/mpi/intel64/lib -Xlinker --enable-new-dtags -Xlinker -rpath -Xlinker /usr/local/intel/2019/compilers_and_libraries_2019.5.281/linux/mpi/intel64/lib/release -Xlinker -rpath -Xlinker /usr/local/intel/2019/compilers_and_libraries_2019.5.281/linux/mpi/intel64/lib -lmpifort -lmpi -lrt -lpthread -Wl,-z,now -Wl,-z,relro -Wl,-z,noexecstack -Xlinker --enable-new-dtags -ldl

it does seem like Cmake knows gfortran-specific files can be found in the include/gfortran/8.2.0 directory…but it put it second so it’s actually picking up the Intel Fortran compiled modules.

I thought (reading the FindMPI help) that I could pass in the right wrapper with -DMPI_Fortran_COMPILER, but it doesn’t seem to change anything:

(1101) $ cmake .. -DMPI_Fortran_COMPILER=mpifc
-- The Fortran compiler identification is GNU 8.3.0
-- Check for working Fortran compiler: /usr/local/other/gcc/8.3.0/bin/gfortran
-- Check for working Fortran compiler: /usr/local/other/gcc/8.3.0/bin/gfortran  -- works
-- Detecting Fortran compiler ABI info
-- Detecting Fortran compiler ABI info - done
-- Checking whether /usr/local/other/gcc/8.3.0/bin/gfortran supports Fortran 90
-- Checking whether /usr/local/other/gcc/8.3.0/bin/gfortran supports Fortran 90 -- yes
-- Found MPI_Fortran: /gpfsm/dulocal/sles12/intel/2019/compilers_and_libraries_2019.5.281/linux/mpi/intel64/lib/libmpifort.so (found version "3.1") 
-- Found MPI: TRUE (found version "3.1")  
-- MPI_Fortran_COMPILER: /usr/local/intel/2019/compilers_and_libraries_2019.5.281/linux/mpi/intel64/bin/mpifc
-- Configuring done
-- Generating done
-- Build files have been written to: /home/mathomp4/MPIVersionCMake/Fortran/build-GNUIMPI
(1102) $ make
Scanning dependencies of target mpiversion.exe
[ 50%] Building Fortran object CMakeFiles/mpiversion.exe.dir/mpiversion.F90.o
f951: Fatal Error: Reading module ‘mpi’ at line 1 column 2: Unexpected EOF
compilation terminated.
CMakeFiles/mpiversion.exe.dir/build.make:62: recipe for target 'CMakeFiles/mpiversion.exe.dir/mpiversion.F90.o' failed
make[2]: *** [CMakeFiles/mpiversion.exe.dir/mpiversion.F90.o] Error 1
CMakeFiles/Makefile2:75: recipe for target 'CMakeFiles/mpiversion.exe.dir/all' failed
make[1]: *** [CMakeFiles/mpiversion.exe.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2
(1103) $ make VERBOSE=1
/gpfsm/dswdev/gmao_SIteam/other/SLES12.3/cmake/3.15.5/bin/cmake -S/home/mathomp4/MPIVersionCMake/Fortran -B/home/mathomp4/MPIVersionCMake/Fortran/build-GNUIMPI --check-build-system CMakeFiles/Makefile.cmake 0
/gpfsm/dswdev/gmao_SIteam/other/SLES12.3/cmake/3.15.5/bin/cmake -E cmake_progress_start /home/mathomp4/MPIVersionCMake/Fortran/build-GNUIMPI/CMakeFiles /home/mathomp4/MPIVersionCMake/Fortran/build-GNUIMPI/CMakeFiles/progress.marks
make -f CMakeFiles/Makefile2 all
make[1]: Entering directory '/gpfsm/dhome/mathomp4/MPIVersionCMake/Fortran/build-GNUIMPI'
make -f CMakeFiles/mpiversion.exe.dir/build.make CMakeFiles/mpiversion.exe.dir/depend
make[2]: Entering directory '/gpfsm/dhome/mathomp4/MPIVersionCMake/Fortran/build-GNUIMPI'
cd /home/mathomp4/MPIVersionCMake/Fortran/build-GNUIMPI && /gpfsm/dswdev/gmao_SIteam/other/SLES12.3/cmake/3.15.5/bin/cmake -E cmake_depends "Unix Makefiles" /home/mathomp4/MPIVersionCMake/Fortran /home/mathomp4/MPIVersionCMake/Fortran /home/mathomp4/MPIVersionCMake/Fortran/build-GNUIMPI /home/mathomp4/MPIVersionCMake/Fortran/build-GNUIMPI /home/mathomp4/MPIVersionCMake/Fortran/build-GNUIMPI/CMakeFiles/mpiversion.exe.dir/DependInfo.cmake --color=
make[2]: Leaving directory '/gpfsm/dhome/mathomp4/MPIVersionCMake/Fortran/build-GNUIMPI'
make -f CMakeFiles/mpiversion.exe.dir/build.make CMakeFiles/mpiversion.exe.dir/build
make[2]: Entering directory '/gpfsm/dhome/mathomp4/MPIVersionCMake/Fortran/build-GNUIMPI'
[ 50%] Building Fortran object CMakeFiles/mpiversion.exe.dir/mpiversion.F90.o
/usr/local/other/gcc/8.3.0/bin/gfortran  -I/gpfsm/dulocal/sles12/intel/2019/compilers_and_libraries_2019.5.281/linux/mpi/intel64/include -I/gpfsm/dulocal/sles12/intel/2019/compilers_and_libraries_2019.5.281/linux/mpi/intel64/include/gfortran/8.2.0   -c /home/mathomp4/MPIVersionCMake/Fortran/mpiversion.F90 -o CMakeFiles/mpiversion.exe.dir/mpiversion.F90.o
f951: Fatal Error: Reading module ‘mpi’ at line 1 column 2: Unexpected EOF
compilation terminated.
CMakeFiles/mpiversion.exe.dir/build.make:62: recipe for target 'CMakeFiles/mpiversion.exe.dir/mpiversion.F90.o' failed
make[2]: *** [CMakeFiles/mpiversion.exe.dir/mpiversion.F90.o] Error 1
make[2]: Leaving directory '/gpfsm/dhome/mathomp4/MPIVersionCMake/Fortran/build-GNUIMPI'
CMakeFiles/Makefile2:75: recipe for target 'CMakeFiles/mpiversion.exe.dir/all' failed
make[1]: *** [CMakeFiles/mpiversion.exe.dir/all] Error 2
make[1]: Leaving directory '/gpfsm/dhome/mathomp4/MPIVersionCMake/Fortran/build-GNUIMPI'
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2

The message() seems to say it’s going to use mpifc but it doesn’t seem to?

Now, I can sort of “force” a working compile by doing:

cmake .. -DMPI_Fortran_MODULE_DIR=/usr/local/intel/2019/compilers_and_libraries_2019.5.281/linux/mpi/intel64/include/gfortran/8.2.0
-- Configuring done
-- Generating done
-- Build files have been written to: /home/mathomp4/MPIVersionCMake/Fortran/build-GNUIMPI
(1074) $ make
Scanning dependencies of target mpiversion.exe
[ 50%] Building Fortran object CMakeFiles/mpiversion.exe.dir/mpiversion.F90.o
[100%] Linking Fortran executable mpiversion.exe
[100%] Built target mpiversion.exe
(1075) $ ./mpiversion.exe 
 Intel(R) MPI Library 2019 Update 5 for Linux* OS

but as I often compile code with various versions of GNU (on this cluster I have 6.5.0, 7.4.0, 8.3.0, and 9.2.0), I’d really like to have CMake actually do this automatically.

So, is there an easy way to use CMake with Intel MPI+gfortran? Does anyone have a recipe/macro/hint? I’m not the best at CMake, but I’m trying to figure out how to make CMake code that checks if mpifc is in MPI_Fortran_COMPILER and if so it runs execute_process() on mpifc and tries to extract the second (space-delimited) field, strips the -I and then tries to stuff that into MPI_Fortran_MODULE_DIR but I’m not having much luck yet. It’s a bit fragile as it assumes that the second field of mpifc will be the module include path, but I don’t see a good reason Intel would change that in the future as it works now. Of course, I’d really not like to even have to pass in MPI_Fortran_COMPILER but I guess that’s not too bad. It’s the passing in MPI_Fortran_MODULE_DIR that I’d like to avoid.

A couple of notes. First, I only have CMake 3.15.5 available on this cluster. I’ll try and ask the sysadmins to install 3.16.1 as maybe it’s fixed there, but the history on GitHub makes me think the only possible change will be an error message update (from Nov 20).

Second, CMake does seem to handle the Intel MPI + gcc case okay:

(1128) $ cat mpiversion.c 
# include <stdlib.h>
# include <stdio.h>
# include "mpi.h"

int main(int argc, char *argv[])
{
   char mpi_lib_ver[MPI_MAX_LIBRARY_VERSION_STRING];
   int len;
   MPI_Get_library_version(mpi_lib_ver, &len);
   printf("%s\n",mpi_lib_ver);
}
(1129) $ cat CMakeLists.txt 
cmake_minimum_required(VERSION 3.14)
project(mpiversion VERSION 1.0.0 LANGUAGES C)
find_package(MPI REQUIRED)
message(STATUS "MPI_C_COMPILER: ${MPI_C_COMPILER}")
add_executable(mpiversion.exe mpiversion.c)
target_link_libraries(mpiversion.exe PRIVATE MPI::MPI_C)
...
(1132) $ cmake ..
-- The C compiler identification is GNU 8.3.0
-- Check for working C compiler: /usr/local/other/gcc/8.3.0/bin/gcc
-- Check for working C compiler: /usr/local/other/gcc/8.3.0/bin/gcc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Found MPI_C: /gpfsm/dulocal/sles12/intel/2019/compilers_and_libraries_2019.5.281/linux/mpi/intel64/lib/release/libmpi.so (found version "3.1") 
-- Found MPI: TRUE (found version "3.1")  
-- MPI_C_COMPILER: /usr/local/intel/2019/compilers_and_libraries_2019.5.281/linux/mpi/intel64/bin/mpigcc
-- Configuring done
-- Generating done
-- Build files have been written to: /home/mathomp4/MPIVersionCMake/C/build
(1133) $ make
Scanning dependencies of target mpiversion.exe
[ 50%] Building C object CMakeFiles/mpiversion.exe.dir/mpiversion.c.o
[100%] Linking C executable mpiversion.exe
[100%] Built target mpiversion.exe
(1134) $ ./mpiversion.exe 
Intel(R) MPI Library 2019 Update 5 for Linux* OS

it even correctly used mpigcc. But as about 95% of my coding is in Fortran and using Fortran libraries, I’d like to get the gfortran working.

Thanks for the detailed report. I think your MPI_Fortran_COMPILER setting is being used but there should not be any difference between mpifc and mpif90 in this use case. The FindMPI module sets environment variables while using the MPI compiler -show option that configure the matching underlying Fortran compiler anyway. mpifc will just forward to mpif90.

FindMPI is flipping the include directory order from that reported by mpif90 -showme:compile. I tracked down the code doing that and opened CMake Issue 20098 for this bug. Please follow that issue for further updates.

Please try https://gitlab.kitware.com/cmake/cmake/merge_requests/4153 , I believe it should fix the issue.

@chuckatkins I copied your new FindMPI.cmake into a 3.16.2 download and built and all seems good! I can run my little tester with GCC 9.2 and Intel MPI and PGI 19.10 and Intel MPI and both seem happy. I even tried it with a more important code that doesn’t need -DMPI_Fortran_MODULE_DIR anymore to succeed.

Thank you, and I eagerly await CMake 3.17 (or 3.18 or whenever it gets in).

1 Like

Matt, I am seeing the same problem still, with cmake 3.22.1 but for Intel OneAPI MPI 2021.4.0 with GNU 10.1.0.

f951: Fatal Error: Reading module ‘/gpfsm/dulocal/sles12/intel/oneapi/2021/mpi/2021.4.0/include/mpi.mod’ at line 1 column 2: Unexpected EOF

It should be picking the gfortran module instead? Looks like it is getting the order wrong:

... -I/gpfsm/dulocal/sles12/intel/oneapi/2021/mpi/2021.4.0/include -I/gpfsm/dulocal/sles12/intel/oneapi/2021/mpi/2021.4.0/include/gfortran/10.2.0 -ffree-line-length-none ...

In CMakeCache.txt:

MPI_Fortran_COMPILER_INCLUDE_DIRS:STRING=/gpfsm/dulocal/sles12/intel/oneapi/2021/mpi/2021.4.0/include/gfortran/10.2.0;/gpfsm/dulocal/sles12/intel/oneapi/2021/mpi/2021.4.0/include