User Tools

Site Tools


wiki:make:compile

Compiling Code

To compile code we use a compiler. Popular choices for Fortran and C are either gcc or intel compilers. In this example we will look at compiling Fortran with gfortran. gfortran is an open source GNU compiler. It is actually more than just a compiler. When we call gfortran we are calling a compiler driver which decides what tasks to send to a fortran compiler, assembler and linker. Often we have a source code that consists of many different files. Subroutines in each file are called by code in the other files. These files need to be linked together.

There are two steps in building programs:

  1. Compiling the individual source files into object files
  2. Linking the files with each other and numerical libraries

In the first step, compiling, gfortran goes through the source code files and converts them to assembler, which are instructions to run on a CPU. This step usually produces object files ending in .o and files with the extension .mod. .mod files are used when compiling other source files that depend on the first.

To compile a source file we use the following command:

  $ gfortran -c file1.f90

The second step, linking, gfortran links together the compiled object files and, optionally, external numerical libraries into an executable file. Blas and Lapack are popular numerical libraries. They contain many fast subroutines for manipulating matrices.

To link files together we can use the following command:

  $ gfortran -o file1.o file2.o file3.o -L/usr/lib/ -llpack -lblas

Here the option -L/usr/lib indicates the directory where the libraries can be found and -l is used to link each of the libraries.

But we have to compile the files in right order, as they depend on each other. This is where make can help us.

I made an example code for you called inverse. It inverts a simple 3×3 matrix using lapack. It is a simple code and it is not really important that we understand it. It is more important to note that I divided the code up into four different .f90 files. inverse.f90 is the main file which calls subroutines from input.f90 and invert.f90. invert.f90 calls a subroutine from lu_decompose.f90.

I also created a simple makefile to build the program let's take a look and see if we can understand it.

  #This is a makefile for inverse.
  
  F90 = gfortran
  
  LIBDIR = -L/usr/lib
  
  LIBS = \
          $(LIBDIR) \
          -llapack \
          -lblas
  
  OBJS = \   
          lu_decompose.o \
          invert.o \
          input.o \
          inverse.o \
  
  
  %.o:%.f90
          $(F90) -c $*.f90
          
  inverse: $(OBJS)
          $(F90) -o inverse $(OBJS) $(LIBS)
  
  #dependencies
  
  invert.o: invert.f90 lu_decompose
  inverse.o: inverse.f90 input.o invert.o
  input.o: input.f90
  lu_decompose.o: lu_decompose.f90
  
  clean:
           rm -f *.o *.mod

Let's unpack this makefile. First we define some macros. The compiler as $F90, our library path as $LIBDIR, our external libraries as $LIBS and the object file names as $OBJS.

Then we use a pattern rule to compile all .f90 files in object files. The executable inverse depends on all objects and links the object files with each other and the external libraries.

Next we define all the dependencies. Notice that we can define them here and make will automatically figure out in which order to run the pattern rule %.o:%.f90. That's quite convenient.

Finally we define a clean target. It is not an actual file. Sometimes we call these targets phoney targets. It has a command to delete all the .o and .mod files created in the compile process. It won't normally run since make only runs the first command in a makefile and any rules which create dependencies for the first target. But, we can force it to run by typing:

  $ make clean

in the shell.

Suffix rules & Implicit rules

You will likely encounter one more type of rule, suffix rules.

These rules consist of file suffixes listed together. e.g. .f.o It is confusing that in suffix rules the prerequisite is listed first and then the target. These rules also only work with built-in suffixes. You can add to the make built-in suffixes with the line:

  .SUFFIXES: .f90

Suffix rules are obsolete and pattern rules should be used instead. But for compatibility with a old make files they are kept. I much prefer to use pattern rules since they are more general and clearer.

Another thing you should be aware of is that make includes several built-in rules also called implicit rules. We can see all of the variables and rules of make if we type make -p into the shell. Make will search through these implicit rules if you list a target with no rule or a dependency that has no rule.

wiki/make/compile.txt · Last modified: 2022/07/21 06:59 by 127.0.0.1