``Make it so.''
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 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:
Figure 1, annotates the various sections of the Makefile
A Makefile target has 3 parts:
Each dependency, in turn, requires a target to tell make how to build the dependency.
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.
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.
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.
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 Makefile you were give for
Lab 1 has a few more items in it than the simple 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.
Figure 4, continues the walk through the Lab 1
Makefile
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.
make and Makefiles
Luis Fernandes
Department of Electrical and Computer Engineering
Ryerson Polytechnic University
--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.
A simple Makefile
# 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.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
The all Target
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. The towers Target
The towers.o Target
The Lab 1 Makefile
Figure 2, annotates the various sections of the Lab 1 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. Annotated Lab 1 Makefile
The Lab 1 Makefile Walkthrough
Figure 3, walks through the Lab 1
Makefile.

Figure 3. Lab 1 Makefile Walk-through: checking dependancies
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
Luis Fernandes
Last Modified: Sun Feb 03 11:19:26 2002