When software is distributed in the form of source code, the package often
includes a file, conventionally named
instructions for building and installing the software automatically.
Makefiles are essentially scripts written in a declarative language and
executed by an interpreter named
As in other declarative languages, control flow is not determined by
explicit constructions of the text of the the
make script, but is
rather inferred by the interpreter from the dependency relationships that the
programmer specifies. Makefiles are composed primarily of constructions
called rules. A rule consists of one or more targets, zero or more prerequisites, and zero more more
actions, arranged in the following format:
If there are two or more targets, they are separated by spaces. If there are two or more prerequisites, they too are separated by spaces. If there are two or more actions, they may be separated by semicolons (in which case they will be executed in sequence in a shell that is launched solely to perform those actions), or they may be placed on separate lines (in which case they will still be executed in sequence, but a different shell is launched for each one).Each action line must begin with a tab character -- not a sequence of eight spaces, but the actual horizontal tab character with ASCII code 0x09. Edit carefully.
A typical target is the name of a file that should be rebuilt automatically each time some other file is revised. The prerequisite is then the name of the other file, the one from which the target file should be constructed. The action is the command line that one would use to construct it.
For example, a makefile for a Java project might include the rule
make to build the target file HelloWorld.class (in the current working directory) from the prerequisite
file HelloWorld.java, by invoking the
provided that HelloWorld.java has been revised since HelloWorld.class was last constructed. The
make utility determines
whether this condition is met by comparing the timestamps on the files. It
will also perform the action, of course, if HelloWorld.class
does not exist and HelloWorld.java does.
Exercise: Write a rule that directs
make to run the
compiler to obtain the object file queue.o from the source-code
file queue.c, provided that queue.o either does not
exist or is older than one or both of its prerequisite files queue.c and queue.h.
make, first create the Makefile in the directory
containing the source files. Use
cd to make it the current working
directory, if you haven't already done so. Then, at the prompt in the
terminal window, type
make and the target or targets that you want
the builder to construct. For instance, you would give the command
make's attention to the rule for building HelloWorld.class.
You'll get a fairly clear error report from
make if you specify a
target that doesn't exist:
If you don't specify any target at all,
make assumes that you want
to build the target of the first rule in the Makefile.
If you neglect to create the Makefile,
make will look at
the suffixes of the targets and try to guess what action you had in mind.
Although it recognizes a few simple cases (it knows enough to run the C
compiler in order to build a target file with a name ending in .o), for the most part it simply reports that it has no rule to apply.
Exercise: Create a folder make-lab for this lab and copy
queue.c, queue.h, and test-queues.c
from /home/stone/courses/software-design/code/ into that
folder. Create a Makefile in the same folder, containing the
rule you wrote in section 0 above. Don't forget to write comments into the
Makefile. (Any line beginning with a mesh character,
is a comment, and
make will ignore it.) Run
make to build
the queue.o file.
A file that is a target in one rule may be a prerequisite within some other
rule. For instance, documentation that is prepared with the TEX
typesetter and released in Portable Document Format might be processed by
three different utility programs along the way. The .pdf file
might be derived from a PostScript (.ps) version by means of
ps2pdf converter, as directed by the following
The PostScript file in turn comes from a "device-independent"
page-description file, depending on some program like
perform the conversion:
And TEX is used to construct the .dvi file from the .tex input file or files:
If all three of these rules are placed in the Makefile, in any order, the command
tells make to consider frogs.pdf and its direct and
indirect prerequisites as targets, any or all of which might require its
intervention. If it finds that frogs.dvi is older than
frogs.tex, then it infers that it is necessary to run TEX in
order to get a newer version of frogs.dvi. The timestamp on
the new frogs.dvi then shows it to be more recent than
a2ps in order to get a
revised frogs.ps file. This file is now more recent than
ps2pdf to build the
revised frogs.pdf file.
Exercise: Add to the Makefile that you created in section 1
above a second rule, directing
make to recompile and re-link
the executable test-queues if it does not exist, or if any of
three files on which it depends -- test-queues.c,
queue.h, or queue.o -- has changed since
test-queues was constructed. Run
make to build this
executable. Then delete queue.o and run
make rebuilds queue.o before recompiling
Makefiles in which all of the rules are written out in full, like those
shown above, are tedious to write and difficult to maintain. The
make utility allows you to create and initialize string variables and to
use the values of those variables in subsequent rules.
To create and initialize a variable, put the variable at the beginning of a line, followed by an equals sign. The string comprising the characters to the right of the equals sign becomes the value of the variable (except that whitespace characters adjacent to the equals sign, on either side, are ignored).
For example, one might write
to create the variable
JAVA_FLAGS and give it the string value
Note that quotation marks are not needed as delimiters for the string value.
To use the value of a variable in a rule, write the variable with a dollar sign and left brace in front of it and a right brace after it:
make utility replaces the variable reference with its value
before executing the action. For historical reasons,
accepts parentheses rather than braces around the variable name, so that,
$(JAVAFLAGS) is the same as
A few variables are maintained internally by
make and have values
that are relative to the current rule. For instance, the variable
< refers to the first prerequisite of the current rule, so that one
could also write the rule shown just above as
(Actually, one could even abbreviate the second variable reference to
$<. The braces are optional for variables with one-character names.)
Similarly, in the action part of a rule, the variable
@ refers to
the target. Thus the rule for
frogs.pdf in section 2 above could be
Exercise: Add a
CFLAGS variable at the beginning of your Makefile and use it in your rules to make sure that invocations of the C
compiler always turn on the
make utility also recognizes several other ways of associating
values with variables. It predefines thirty or so of them, such as
FC for the FORTRAN compiler; if a rule contains the reference
make replaces it with the default value
f77 even if
no explicit assignment appears in the
make utility also asks the shell that invokes it to pass along
the values of any shell variables that have been set, such as
for the list of directories that the shell uses to search for executables
PWD for the current working directory. These, too, are
available for use in rules.
Finally, the command line that you use to invoke
make can include
assignments to variables, such as
PREP=/usr/bin/m4. In this case,
you can't have whitespace on either side of the equals sign, and you'll
need delimiters that the shell can recognize on the right-hand side if it
contains spaces (as in
A2PSFLAGS="-1 --landscape --no-header".
A variable assignment on the command line takes precedence over an explicit
assignments within the
Makefile, which in turn takes precedence over
an assignment inherited from the corresponding shell variable, which in
turn takes precedence over an implicit predefinition supplied by
If you give
make the command-line option
-p, it will print
out (among other things) the values of all the variables it knows about,
whatever their source, before it proceeds to rebuild the target(s).
Exercise: In the rules in your
Makefile, replace the name of the GNU
C compiler with a reference to the implicitly defined variable
Delete the executable
test-queues and run
make to rebuild
it. What value does
make supply for the variable
this work? Why or why not?
test-queues and run
make again, this time
specifying on the command line that the variable
CC should have the
test-queues again, edit the
Makefile to place the same assignment to
CC at the top, and then
make again to rebuild the executable.
After listing all of the variables and their values,
make -p also
prints out a number of suffix rules, supplying default actions
for frequently encountered targets. For instance, one of these is the rule
which says that, if the target is any file that ends in .dvi, its prerequisite is the corresponding file ending in .tex, and you can build it by running the executable whose name is the
value of the variable
TEX on that prerequisite .tex
make preloads this suffix rule, we don't actually need
the explicit rule shown above for the target
make does the same thing by default (if
TEX has the value
/usr/bin/tex, at least).
Exercise: There is a similar rule for targets ending with .o and prerequisites ending in .c:
Looking back through the output from
make -p, we can see how the
OUTPUT_OPTION were initialized. Note
how they refer to still other variables.
References to uninitialized variables, such as
CPPFLAGS in this
example, are replaced with null strings when
make processes the
rules containing them.
Does the presence of this suffix rule make any of the commands in the
Makefile that you've been constructing superfluous? If so, rewrite the
Makefile, removing the superfluous commands. Then delete queue.o and test-queues and run
make to rebuild them.
It is possible to use identifiers that are not file names as targets,
simply as triggers for actions that should be performed when one of the
prerequisites changes or even (without prerequisites) simply when it is
convenient to have
make do them.
For instance, the Makefile in a software package that includes
source code often includes a target
install, with all of the
executables in that the package provides as prerequisites, that copies
those executables into some appropriate directory such as /usr/local/bin/ and makes sure that they have the correct permissions and
Exercise: Write a rule for a target called
clean that removes all of
the .o files and the executable test-queues.
(This, too, is a common usage in makefiles for software packages. The idea
is to force a completely new recompilation the next time
make is run
with any of the executables as targets.)
Full documentation for GNU make is available on line: