I'm studying parallel programming and I'm trying to understand the difference between compiling OpenMP and MPI programs. OpenMP uses special #pragma directives, yet programs can be compiled with ordinary compilers such as GCC or Clang. MPI appears to be a library of ordinary function calls, but people commonly use commands like mpicc instead. Why is the compilation process different, and what do these compiler commands actually do?
3 Answers
MPI doesn’t fundamentally require a special compiler. Commands such as mpicc are usually wrapper programs around GCC, Clang, or another normal compiler. They automatically add the MPI header locations, library paths, libraries, and other installation-specific options. You could invoke the underlying compiler directly if you supplied all of those flags yourself, then launch the finished program with the appropriate MPI runtime.
OpenMP directives are designed so a compiler can ignore pragmas it doesn’t understand. Without an OpenMP option, GCC or Clang can usually compile the program as ordinary C, though the parallel behavior won’t be generated. With a flag such as -fopenmp, the compiler recognizes the directives, emits the required threading code, and links the OpenMP runtime library.
The key difference is where the work happens. OpenMP is partly a compiler feature: pragmas tell the compiler how to transform ordinary code into multithreaded code, while the runtime supports things such as thread management. MPI calls are regular functions implemented by an external library, so the compiler only needs declarations for them; the linker must then find the correct MPI library. The wrapper compiler mainly makes that setup convenient, rather than being a fundamentally different kind of compiler.

One caveat is that ignoring a pragma is only safe when the program still has correct serial behavior. Some pragmas affect calling conventions or other details, so an unsupported directive can potentially lead to link errors or incorrect runtime behavior.