The correct way of building MPI program using Cmake

[Last update on August 24, 2021]

Many posts on this topic appear outdated. Modern cmake is centered around target-specific configurations. A correct way of building MPI program with cmake (version 3.10.2 for instance) would be:

find_package(MPI REQUIRED)
add_executable(my_mpi_bin src1.cpp src2.cpp)
target_include_directories(my_mpi_bin PRIVATE ${MPI_CXX_INCLUDE_PATH})
target_compile_options(my_mpi_bin PRIVATE ${MPI_CXX_COMPILE_FLAGS} my_extra_compile_flags)
target_link_libraries(my_mpi_bin ${MPI_CXX_LIBRARIES} ${MPI_CXX_LINK_FLAGS} my_extra_link_flags)

If the MPI implementation (MPICH-3.2 for instance) is installed at certain location that cmake is unable to find automatically, explicitly specify the path. For example:

cmake \
-DMPI_CXX_COMPILER=/usr/local/mpich-install/bin/mpicxx \
-DMPI_C_COMPILER=/usr/local/mpich-install/bin/mpicc \

MPI_CXX_COMPILER and MPI_C_COMPILER are merely MPI wrappers. They are not the actual compiler/linker. To specify a certain compiler/linker:

cmake \
-DCMAKE_CXX_COMPILER=/usr/local/bin/g++-6.4.0 \
-DCMAKE_C_COMPILER=/usr/local/bin/gcc-6.4.0 \
-DMPI_CXX_COMPILER=/usr/local/mpich-install/bin/mpicxx \
-DMPI_C_COMPILER=/usr/local/mpich-install/bin/mpicc \

*Never ever specify CMAKE_CXX_COMPILER and CMAKE_CXX_COMPILER by hardcoding them in the cmake script. This is such a common anti-pattern.

To create a test for the MPI program:

add_test(NAME my_mpi_test
         my_arg_1 my_arg_2 ...)

*Prior to cmake 3.10.2, use MPIEXEC instead of MPIEXEC_EXECUTABLE.

What phrase is considered toxic but may apply now? — GG EZ


6 thoughts on “The correct way of building MPI program using Cmake

  1. Adrien

    As of CMake 3.10 (well, 3.9 even, but FindMPI had tremendous improvements in 3.10), all you have to do is say that you depend on the imported target `MPI::CXX` (and/or `MPI::Fortran`, `MPI::C`), like so:

    `target_link_libraries(my_target PUBLIC MPI::CXX)`

    That’s it. No manual fiddling with `${MPI__}` variables that are only here for backward compatibility reasons. The required flags, definitions and include path will all be forwarded by the imported target. You can then control how and whether these are propagated by your own `my_target` with the `PUBLIC` vs `PRIVATE` vs `INTERFACE` keywords. This isn’t generally useful for an executable target, but very important to get right when your target is a library (or an interface target) so that other targets than inherits from it have all the flags and directories set properly.

    To manually set your compilers, you can even (as of 3.10) directly set the `CMAKE__COMPILER` variables to the corresponding MPI wrappers , FindMPI is smart enough to deal with that properly.

    (Also, adding the `srcX.h` file in your include _directories_ is a common mistake, it’s perfectly unnecessary).


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s