make and Makefiles

Luis Fernandes
Department of Electrical and Computer Engineering
Ryerson Polytechnic University

``Make it so.''
--Jean-Luc Picard,
Captain, U.S.S. Enterpise


make is a program utility that automatically determines which parts of a large program need to be recompiled, and issues commands to recompile them. It reads instructions from a Makefile.

The examples in this tutorial show how C programs are compiled using make, since they are most common, but you can use make with any programming language. Indeed, make is not limited to programs. You can use it to describe any task where one or more files are generated automatically from other files whenever the others change1.

A simple Makefile

A Makefile contains instructions for make to do something, typically compile a program. The following is the simplest Makefile possible that compiles the Towers of Hanoi program in Lab 1:

# A Simple Makefile to compile Lab 1: Towers of Hanoi 

all: towers

towers: towers.o
	gcc -o towers towers.o

towers.o: towers.c
	gcc -c towers.c

Figure 1, annotates the various sections of the Makefile



Figure 1.Annotated Makefile
Comments begin with a #.
Targets indicate what the Makefile is capable of.
Dependancies indicate what each target depends on.
Commands indicate how the targets are to be built.

make Targets

A Makefile target has 3 parts:

  1. The target name;
  2. A colon;
  3. One or more dependencies.
  4. One or more lines indented by a TAB with commands to build the target.

Each dependency, in turn, requires a target to tell make how to build the dependency.

The all Target

The line following the comment, all: towers, is called the ``default target''. Targets are what make looks for when it runs; every Makefile requires the all target. Typing make is a synonym for typing make all.

How does make know what to compile?

make has a few built-in rules that explain the dependancies between .c, .o and the executable files.

It knows that a .c file is compiled into a .o file and one or more .o files are linked to produce an executable binary.

All files have time-stamps that indicated when they were last modified. So, an executable has to be re-compiled if a .c file has a later time-stamp than the corresponding .o file.

make knows that the target is up-to-date when the time-stamp of the dependancy is later than the target. This means that if you modify towers.c and save it, the time of this file will be later than towers.o and make knows that it has to re-compile the towers.c file to get a new towers.o and finally generate a new towers binary.

So you can see how make could be convenient in keeping track of files that need to be recompiled when working on a project with 1000 files.

The towers Target

In this example, the all target depends on the program towers. This means that for the all target to be up-to-date, the towers target has to be up-to-date.

That's what the next line: towers: towers.o, specifies. It tells make that the target towers is dependent on the object file towers.o.

The line just below that, indented with a TAB, tells make how to build the target from the dependancy. To generate the program towers (dependent on towers.o), make has to execute: gcc -o towers towers.o.

The towers.o Target

Finally, the towers.o: towers.c line tells make that the object file towers.o is dependent on the C file towers.c.

The line just below that, indented with a TAB, tells make how to build the target from the dependancy. To generate the object file towers.o (dependent on towers.c), make has to execute: gcc -c towers.c.

The Lab 1 Makefile

The Makefile you were give for Lab 1 has a few more items in it than the simple Makefile.

# Given Makefile for ELE428 Lab 1 
LAB=lab1
COURSE=ele428
ARCHIVE=*.c *.h Makefile README *.sh
ARCHFILE=${LAB}.archive
CC = gcc
SRCS=towers.c
CFLAGS = -g -Wall

all: towers

towers: towers.o
	$(CC) $(CFLAGS) -o towers towers.o

towers.o: towers.c
	$(CC) $(CFLAGS) -c towers.c

Myst: Myst.c
	$(CC) $(CFLAGS) -o Myst Myst.c

include /home/courses/ele428/bin/Makefile.sub

clean:
	rm -f *~ core a.out *.o towers Myst lab1.archive
Figure 2, annotates the various sections of the Lab 1 Makefile



Figure 2. Annotated Lab 1 Makefile

The most obvious difference is the variable definitions at the start of the Makefile.

These variables are used for convenience when creating a Makefile. For example, every occurence of $(CC) is replaced by gcc because the seventh line specifies CC = gcc.

Note that there is also a target for compiling Myst and one for ``cleaning'' the directory.

Note also the line ARCHIVE=*.c *.h Makefile README *.sh. This line specifies the files that will be submitted when you type make submit.

The Lab 1 Makefile Walkthrough

Figure 3, walks through the Lab 1 Makefile.



Figure 3. Lab 1 Makefile Walk-through: checking dependancies

Figure 4, continues the walk through the Lab 1 Makefile



Figure 4. Lab 1 Makefile Walk-through (Continued): updating targets

The Lab 2 Makefile

The major difference between the Lab 1 Makefile and the Lab 2 Makefile is that the Lab 2 Makefile has an all target with two dependancies; i.e. it builds two programs and each program is dependant on more than one file.

# Given Makefile for ELE428 Lab 2 (a multi-file project)
LAB=lab2
COURSE=ele428
ARCHIVE=*.c *.h Makefile README *.sh
ARCHFILE=${LAB}.archive
CFLAGS = -Wall -g
CC = gcc

all: insertionSort mergeSort

insertionSort: sortDriver.o metrics.o insertionSort.o
	$(CC) -o insertionSort sortDriver.o metrics.o insertionSort.o

mergeSort: sortDriver.o metrics.o mergeSort.o
	$(CC) -o mergeSort sortDriver.o metrics.o mergeSort.o

testMetrics: metrics.c
	$(CC) -o testMetrics -Wall -D TEST_METRICS metrics.c
	@-./testMetrics
	@-rm metrics.o core testMetrics 2> /dev/null

include /home/courses/ele428/bin/Makefile.sub

clean:
	-@rm -f *~ *.o a.out core ${LAB}.archive insertionSort mergeSort


1 Adapted from the GNU make manual.

If you are wondering where the submit target is, the line include /home/courses/ele428/bin/Makefile.sub ``includes'' the submit target into this file.


Luis Fernandes
Last Modified: Sun Feb 03 11:19:26 2002