The program make
reads a Makefile
in the current directory and builds the
targets according to the instructions in the Makefile
.
Let's deconstruct a common makefile:
hello: hello.c
cc -Wall -ansi -o hello hello.c
The first line contains a target filename (hello
), followed by a list of
files on which the target depends (hello.c
). Whenever hello.c
is newer
than hello
, make will run the command given on the second line.
Remember that make is picky about the tab at the beginning of the second line. Spaces won't work, it has to be a tab.
That is all you need to know about makefiles for this class. But if you are curious, keep reading.
GNU Make has lots of advanced features which allow for more general-purpose makefiles. We'll discuss just a couple here.
You may wonder why we have to type hello
all over the place. This is a good
thing to wonder, because one of the cardinal rules of programming is to not
repeat yourself wherever possible. If you repeat yourself, and later you have
to change something, you might not remember to change it everywhere and that
would introduce bugs. Make has special substitutions that will keep us from
repeating ourselves:
hello: hello.c
cc -Wall -ansi -o $@ $<
$@
is replaced with the target name, which is hello
. $<
is replaced with
the first dependency name, which is hello.c
here. $*
is replaced with all
of the dependencies, which is also just hello.c
here since we only have one
dependency. Now if we want to change from hello
to goodbye
we only have to
change in two places, not four.
Make can use generic rules based on patterns:
%: %.c
cc -Wall -ansi -o $@ $<
In this example the %
is replaced by the name of the program you're trying
to compile. But you have to tell make what program to compile, so you type
make hello
, or make goodbye
. If you type only make
, make will complain
that you don't have a default rule, which is its way of telling you that you
didn't give it enough information.
In makefiles you can have more than one rule, and the first is the default rule. So, we can add a rule at the beginning that tells make which program we want to compile, like this:
default: hello
%: %.c
cc -Wall -ansi -o $@ $<
The first rule says default
is built by building hello
. Now the pattern
matches and the second rule is used to build hello
. Now we can just type
make
and it will build hello
, and if we want to change hello
to
goodbye
we only have to change it in one place.
We can do even better, though. GNU Make has implicit rules which will be
followed even if there is no matching rule in your makefile, and even when
there is no makefile at all. In fact, if you have hello.c
but no makefile,
and you type make hello
, make will run cc hello.c -o hello
for you.
But what if we want our options -Wall -ansi
in there too? The make implicit
rule is actually $(CC) $(CPPFLAGS) $(CFLAGS) $< -o $@
. The variable CC
has
the default value cc
, and the other variables are by default empty. So, if
we define CFLAGS
to be equal to -Wall -ansi
, then make will use those
flags when compiling our program. We can do this with a makefile that contains
the following:
CFLAGS=-Wall -ansi
default: hello
Now if we type make
, make will compile our program with the command cc
-Wall -ansi hello.c -o hello
which is just what we want.
The last thing I will discuss is the customary clean
target. People usually
provide a clean
target to get rid of the binary output files so that
everything is recompiled from scratch. In our case the clean target would
look like this:
clean:
rm hello
You would run this by typing make clean
. Makefiles can be used for many
tasks other than programming, as well. In fact I build these webpages using
make to run a script that converts
markdown into HTML.