This page last changed on Jan 11, 2009 by straha1.

Turning source code (ie.: .c, .f, .f90 files) into executables is a multi-step process. Depending on how you compile, some or all of the steps are hidden from you. If you are compiling only a single source file into an executable, you can ignore all of the steps and have the compiler directly convert your source code to an executable. We did that in the Compiling C Programs on HPC page and its Fortran 77, Fortran 90 and C++ equivalents. However, if you are creating a single executable from multiple source files then you must use a two step process. The rest of this page describes that process. If you never use more than one source file to create an executable, then you can ignore this page.

The two steps in this process are:

  1. Compile your code: convert each of your your source files (.c, .f, .f90, etc.) into object files (.o files). An object file is a binary version of your human-readable source file, in a format that the computer's CPU can understand.
  2. Link your object files and create an executable. While the computer's CPU can understand the contents of an object file, the operating system needs more information in order to know how to send the binary code to the CPU. Linking combines the .o files into a single file (your executable) that has that additional information.

Each language needs a different set of libraries in order to link. A library is a file that contains multiple archived object files (.o files). Those archived object files contain implementations of functions external to your program such as C's printf, Fortran's write statement and MPI's MPI_Bcast. Each language has libraries to which you must link your object files when compiling a program. For example, C programs are linked to the libc.so library. In order to use MPI, you must link with the libraries that implement the MPI that you chose to use. Generally, MPI implementations have a separate library for each language: one for C, one for Fortran and one for C++.

The rest of this page assumes you are compiling MPI code (parallel jobs). However, all of this material works for serial code as well. If you wish to compile serial code, you will need to replace the mpicc, mpif90, mpif77 and mpicxx commands throughout this page with other commands:

mpiXXX Command Equivalent GCC Command Equivalent PGI Command
mpicc gcc pgcc
mpicxx g++ pgcpp
mpif90 gfortran -ffree-form pgf90
mpif77 gfortran -ffixed-form pgf77

When you use mpicc, mpif90, mpif77 or mpicxx (which I will refer to collectively as mpiXXX), your program is linked with the libraries appropriate for that language. If you are using only one language, linking is simple: use the mpiXXX for that language. When you use more than one language in your source files, you must use an mpiXXX that links your code with libraries for all of the languages involved.

In the next two sections, we cover the mechanics of each of the two steps in this process: compiling and linking.

Step 1: Compiling Source Files to Object Files

To compile your source code to an object file, use the appropriate command for the language of the source file:

Fortran 77 Code mpif77 my_f77_file.f -c -o my_f77_file.o compilation-options
Fortran 90 Code mpif90 my_f90_file.f90 -c -o my_f90_file.o compilation-options
C Code mpicc my_c_code.c -o my_c_code.o compilation-options
C++ Code mpicxx my_c++_code.cc -o my_c++_code.o compilation-options

Each of those commands creates an object file (the .o file) that contains a binary version of the corresponding source file (.f, .f90, .c or .cc). You must run that command once for each source file that you have.

The compilation-options in the above commands should be replaced by any compiler flags that you need for your program to compile. See below for more information on that. The -c tells the mpiXXX program that you are not linking; you are creating an object file instead of an executable.

Step 2: Linking Object Files to Create an Executable

The command to link object files depends on the particular combination of languages. In general, the command has this syntax:

mpiXXX object_file_1.o object_file_2.o object_file_3.o ... -o my_executable linker-options

The my_executable should be replaced with the name of the executable you want to create. The linker-options should be replaced with any compiler flags you need for your program to link. See below for more information. The "object_file_1.o object_file_2.o object_file_3.o ..." should be replaced with a complete list of all object files that you created for this program. In general, this includes your main program (the file with your PROGRAM block in Fortran or your main(int,char**) for C and C++) plus all object files needed to implement the functions and procedures that your main program calls.

The mpiXXX should be replaced with one of mpif90, mpif77, mpicc or mpic++. You must use the mpiXXX that links your programs with the necessary libraries for all of the languages you are using. Some compilers generate extra files that the linker needs later (such as .mod module files for Fortran 90 modules). You must use an mpiXXX that knows how to use those files as well. For example, if you are compiling Fortran 90 and C code, you must use the mpif90 since it gives you all of the Fortran 90 and C libraries and knows about the Fortran 90 module files. For other combinations:

For This Combination of Languages Use This mpiXXX
Only Fortran 77 mpif77 or mpif90
Only Fortran 90 mpif90
Only C++ mpicxx
Only C mpif77, mpif90, mpicc, or mpicxx
Fortran 77 with Fortran 90 mpif90
C with Fortran 77 mpif77
C with Fortran 90 mpif90
C with Fortran 77 and Fortran 90 mpif90
C with C++ mpicxx
C++ with Fortran see below

Linking Programs that use Both C++ and Fortran.

Linking C++ code with Fortran code is a special case. None of the four mpiXXX programs will link your code with both the Fortran and C++ libraries. Also, when using Fortran 90, you need mpif90 so that the compiler will be able to use the Fortran module files. However, mpif90 does not include the C++ libraries when linking. You should be able to compile the two languages by sending the -l and -L and other flags required for C++ to the mpif90 command.

There are also issues with Fortran code calling C++ code. Fortran cannot catch C++ exceptions, and it cannot access class methods. There are other, more complex issues as well. For example, suppose you have a C++ function that calls a Fortran function which calls another C++ function. If the innermost C++ function throws an exception, the Fortran function may not properly pass that exception on to the outer C++ function. Whether it does or not depends on the compiler's C++ exception implementation. Also, the Fortran function may not deallocate any arrays that were in the heap instead of the stack. In general, you can simplify this situation by creating a C-like wrapper around your C++ code, and have Fortran call the wrapper functions.

If you need to use C++ with Fortran 77 or 90 and you do not know how to do it, email user support and ask for help. See Contact Information for the user support email address. Furthermore, if you got that combination of languages working on HPC, please tell us what you did and we will post it on this website.

Compiler and Linker Options

When you compile a program directly from source code to an executable, there are a number of options (also called switches or flags) you often use. For example, in C and C++ programs, you will often use -I /path/to/include/dir. With Fortran, you may use -module /path/to/module/dir or -M/path/to/module/dir. With both languages, you may use -L/path/to/lib/dir -llibrary-name to link with libraries (such as NetCDF, HDF or atlas). Some of these flags are used by the compilation phase (creating object files from source code) and some are used by the linking phase (creating an executable from object files). Usually, you can get away with sending all of the options to mpiXXX in both phases. Then mpiXXX will ignore the options that are inappropriate for the particular phase.

However, sometimes the compiler will get confused by the presence of options for the wrong phase. In particular, if you use multiple languages together, the mpiXXX command that you use to link will not understand the flags for other languages. For example, if you are using C and Fortran 90 code, you will compile your C code with mpicc and your Fortran code with mpif90. You will then link with mpif90. If you send C-specific compilation phase options to mpif90 when linking, mpif90 may not recognize those options. If it does not recognize them, it will give you an error.

If you run into such problems, you should try splitting your option list into two groups: one for the compilation phase and one for the linking phase. The man page for your compiler (pgf90, pgf77, pgcc, pgCC, gcc, g++ or gfortran) will tell you which option goes with which phase. The table below is a summary of which category of options goes with which phase:

Option Phase or Phases
-I, -D and other preprocessor flags compilation
PGI's -module or gfortran's -J or -M both
options relating to libraries (such as -l or -L) linking
interprocedural analysis (IPA) and profile-directed feedback – if you do not know what this is, you are probably not using it since it is disabled by default both
other optimizations compilation
code generation options (such as underscoring for fortran, or the sizes of various types) compilation
language options (such as choosing byteswap I/O versus non-byteswap I/O or C89 versus C99) compilation
Document generated by Confluence on Mar 31, 2011 15:37