Makefile Example

Suppose we are writing a program to play Tic-Tac-Toe in 3 dimensions. The program is called T3D, and we are putting the code for it in several files:

T3D.cc calls functions in Board.cc and Move.cc, so Board.h and Move.h will be included in T3D.cc:

         #include "T3D.h"
         #include "Board.h"
         #include "Move.h"

Likewise, there are other include statements in the other files.


Example: The make file for this might look like the following.

         # This is an example of a makefile.
         # Notice these lines start with # and are comments.
         # Put your name at the top of a makefile in a comment line.

         # The first target, T3D, is the one that does the linking 
         # and makes the executable file, which is named T3D.

         T3D : T3D.o  Board.o  Move.o
                      g++ -Wall -o T3D T3D.o Board.o Move.o

         # The next three targets do the compiling to create the
         # three object files.

         T3D.o : T3D.cc  Board.h  Move.h  T3D.h
                      g++ -Wall -c T3D.cc      

         Board.o : Board.cc  Board.h  T3D.h
                      g++ -Wall -c Board.cc

         Move.o : Move.cc  Move.h  T3D.h
                      g++ -Wall -c Move.cc

         # Clean is an example of a pseudo-target.
         # We use it to clean up the working directory.

         Clean :
                      - rm *.o
                      - rm T3D

In the example, each label at the left side is a target. Most targets are the names of files we want to produce by compiling or linking. Each target is followed by commands. We can also have targets such as "Clean" above, which are still followed by a list of commands.

The name of the make file is normally makefile or Makefile. It is possible to invent our own name for it, but we don't have to do so. (If we wanted to do so, we would say "make -f filename".)

To use it, we say "make target", where "target" is one of the labels listed in the file. If we omit the target, it uses the first such label.

Each command line begins with a TAB character.

The make utility will do the minimum amount of work needed to create the target file. This may include recompiling some of the files if they have changed recently. (It determines this by comparing the file modification dates, which are stored in the directory.)

One way to force a complete rebuild--recompiling everything--is to use the UNIX touch command to change the time-and-date stamp on the files involved. We do this with "touch filename".

In the example, the commands listed after "Clean" start with a hyphen (-). The hyphen tells the make utility to continue even if one of these commands causes an error--for instance, if we are trying to delete a file that does not exist.


We can use variables in a make file. Two standard variables are CC and CCFLAGS. We define these at the top and use them as $(CC) and $(CCFLAGS). Each is replaced by its value. Technically these are called "macros".

Here is the same example using CC and CCFLAGS:

         CC = g++
         CCFLAGS = -Wall

         T3D : T3D.o  Board.o  Move.o
                      $(CC) $(CCFLAGS) -o T3D

         T3D.o : T3D.cc  Board.h  Move.h  T3D.h
                      $(CC) $(CCFLAGS) -c T3D.cc      

         Board.o : Board.cc  Board.h  T3D.h
                      $(CC) $(CCFLAGS) -c Board.cc

         Move.o : Move.cc  Move.h  T3D.h
                      $(CC) $(CCFLAGS) -c Move.cc

         Clean :
                      - rm *.o
                      - rm T3D