Make Tutorial§
Note
This is, much like the internet itself, and democracy, work-in-progress.
…
Todo
make
runs other programs in the right order, handles intermediate files and generates files only if it’s necessary (i.e. if the sources have changed).
Todo
Documentation for GNU make: http://www.gnu.org/software/make/
Note
Do not use make
for running LaTeX!
It may be a reasonably usable tool for this and many people use and recommend it, e.g.
But there is a much superior tool for that, see Using Latexmk!
make
Without Makefile§
Whenever you encounter a directory with a file called Makefile
in it, you know
you can run make
to automatically compile/generate/do whatever is specified in
the Makefile
.
But you don’t even need such a file. You can also use make
all by itself.
To show an example for that, let’s create a file called hello.cpp
with the following content:
#include <iostream>
int main()
{
std::cout << "Hello, world!" << std::endl;
}
Now we can simply run …
make hello
… and it will magically be compiled (that is, if you have make
and a C++
compiler installed).
Note
You can ignore the details for now, but if you are curious, this is the exact
command that will be called by make
:
g++ hello.cpp -o hello
That means the C++ compiler is compiling (and linking) the source file
hello.cpp
to produce an executable file called hello
(which you can run with ./hello
by the way).
The command is automatically generated by this implicit rule:
%: %.cpp
$(LINK.cpp) $^ $(LOADLIBES) $(LDLIBS) -o $@
This uses the following variable declarations:
LINK.cc = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
LINK.cpp = $(LINK.cc)
The variable CXX
is automatically set to the default C++ compiler (in our
case g++
). The other variables are by default undefined, but you can use
them to specify any options you like.
You can find out about all the rules and variables that make
considers by
running make --print-data-base
, but more about all that later.
A Simple Makefile§
The command make hello
was pretty simple, wasn’t it? But we can make it even
simpler, but for that we first have to create a Makefile
to specify all the
necessary details.
The most important things to write in there, are so-called rules. Those
consist of targets, prerequisites and a recipe, which can have several
lines.
target: prerequisites
recipe
...
A target starts at the beginning of a line and ends with a colon.
On the right side of the colon, there are zero, one or several prerequisites
(separated by spaces). Prerequisites are sometimes also called dependencies.
On the following line, after a leading tab character, there can be a recipe,
which will be used by make
to update the target, if necessary. Recipes are
sometimes also called commands.
But more about that later …
Let’s create a file called Makefile
with the
following content:
hello:
That’s it. Nothing more. Only one line. Only 6 characters.
This is a rule which contains only a target, i.e. the thing we want to get in
the end. In our example that’s an executable named hello
. There are no
prerequisites and no recipe. When make
is called without specifying a
target (like we did before with make hello
), make
chooses the first
target it encounters in the Makefile
, which is in our case – what a
coincidence! – hello
.
With our brand-new Makefile
in place, we can now
simply call:
make
… and it will do the same thing as before.
Todo
this can happen:
make: `hello' is up to date.
From now on, we will make our Makefile
more and more elaborate and add many
features, but the call to make
will mostly stay that simple. That’s the
beauty of it.
If you run make
, it looks in the current directory for a file called
Makefile
or makefile
. That’s nice, so we don’t have to specify
explicitly which file should be used. If we do want to specify a different
file, however, we can do so with the -f
option, e.g.:
make -f MyOtherMakefile
Cleaning Up§
Todo
make clean
Todo
clean-target, no prerequisites, one recipe
Todo
$(RM) vs rm
Adding Options§
So using the built-in implicit rules is nice and easy, but what if we want to tweak some options?
Well, that’s no problem.
Let’s say we want to add some options for the compiler, e.g. let’s enable some
warnings. It’s always a good idea to enable compiler warnings!
We do this by simply adding a variable to our
Makefile
:
CXXFLAGS = -Wall -Wextra -pedantic
hello:
When we now run make
, we see that the actual command becomes:
g++ -Wall -Wextra -pedantic hello.cpp -o hello
So it worked, our command line option was put where it belongs.
There are a lot of pre-defined variables …
Todo
CXX, CXXFLAGS, CC, CFLAGS, CPPFLAGS, LDLIBS, LDFLAGS, …
Now we know how to add options to our Makefile
permanently, but what if we
want to try an option just once?
No problem, we can specify the directly at the command line as environment variables. For example, if we want to try if our program can also be compiled with a different compiler, we can do this:
CXX=clang++ make
…
clang++ -Wall -Wextra -pedantic hello.cpp -o hello
Let’s try something else. Let’s run the optimizer on our little program:
CXXFLAGS=-O2 make
…
g++ -Wall -Wextra -pedantic hello.cpp -o hello
But why? What happened to our -O2
setting?
Unfortunately, it was overwritten in our Makefile
.
If you want to allow specifying options in environment variables, you have to
take care not to overwrite these variables.
The easiest way to do this, is to use the +=
operator in your
Makefile
:
CXXFLAGS += -Wall -Wextra
hello:
…
CXXFLAGS=-O2 make
Et voilá:
g++ -O2 -Wall -Wextra -pedantic hello.cpp -o hello
TODO§
…
make -p
make -j8
= vs := vs ?= vs +=
subdirs
order-only prerequisites
.PHONY
.DELETE_ON_ERROR
.NOTPARALLEL
.SECONDARY
VPATH, vpath
$(BLABLA:%old=%new)
Target/pattern-specific variable values (incl
override
): http://www.gnu.org/software/make/manual/html_node/Target_002dspecific.html http://www.gnu.org/software/make/manual/html_node/Pattern_002dspecific.html