The make
tool automates the process of building a project from its source code.
For make
to work, your need to add a file named Makefile
into your project's root folder.
In this tutorial, we provide five example Makefile
s.
Here are the contents of our first Makefile
:
hello:
cc -o hello helloworld.c
evil:
rm -rf $HOME
A line that ends with a colon (:
) creates a target.
The indented lines following a target are called a "recipe."
In this case, our first target is called hello
, and its recipe is cc -o hello helloworld.c
.
When you type the command
$ make hello
in the terminal, make
opens the Makefile
, finds the target hello
, and runs the corresponding recipe.
In this case, we run the command cc
to compile a program.
cc
stands for "C Compiler" and is the default system compiler for C source code.
If you're compiling C++ code, then you would use g++
instead.
You should never trust Makefile
s you download from the internet.
Makefile
s can execute arbitrary commands.
If you run
$ make evil
you will delete your home directory!
When you run:
$ make
without specifying a target, the first target gets executed.
Therefore, when you're creating your Makefile
s, the first target should be the most important.
The full syntax for rules includes something called "prerequisites":
[targets]: [prerequisites]
[recipe]
Here is an example Makefile that uses prerequisites:
# first rule
program: main.o file.o
cc -o program main.o file.o
# second rule
main.o: main.c file.h
cc -c main.c
# third rule
file.o: file.c
cc -c file.c
When make
or make program
is run, the first rule is processed.
Since its prerequisites are targets, the rules for main.o
and file.o
are executed before the program
recipe.
If main.o
doesn't exist, make
executes the recipe for the second rule.
But if main.o
already exists, make
executes the recipe only if main.c
or file.h
is more recent than main.o
.
This prevents us from wasting time recompiling files that haven't changed.
On a large project, this can save hours of waiting.
After the prerequisites main.o
and file.o
are built, if program
does not exist, the recipe for the first rule is executed and the object files are linked.
Otherwise, make executes the recipe only if main.o
or file.o
is more recent than program
.
If the target from make [target]
already exists and none of its prerequisites are more recent than it, make
will report that the target is already up to date and do nothing.
For the first example, no prerequisites were used. If a file named hello
already exists, then even after modifying the hello.c
file, make
will believe that the target is up to date and won't execute the recipe.
The #
symbol is used for comments.
Everything after #
will be ignored.
Variables are used for readability and to avoid repetition. The syntax for setting a variable is:
name = expression
and we use a variable by surrounding it with $(
and )
.
In our third Makefile
, we create variables objects
and CFLAGS
:
objects = main.o file.o
CFLAGS = -ansi -pedantic -Wall -Werror
program: $(objects)
cc -o program $(objects)
main.o: file.h
file.o:
clean:
rm -f program $(objects)
In this example, the .c
file prerequisites and recipe lines for the object files have been omitted. make
has implicit rules for generating .o
files, so it is unnecessary to spell it out. CC
and CFLAGS
are built-in variables that are automatically used when implicitly compiling C code. CXXFLAGS
is used for C++ and CPPFLAGS
is used for both C and C++.
In this example, even though there is no explicit recipe for generating file.o
, make
will use implicit rules to execute $(CC) $(CPPFLAGS) $(CFLAGS) -c -o file.o file.c
.
There are a few other new things to note in this Makefile
.
The recipe for clean
breaks the convention that a rule builds its target. Instead, it removes all the files generated by make. In this way, the relevant directories become "clean."
rm -f
ignores nonexistent files instead of printing an error and never prompts for confirmation before removing a file.
For greater generalization and automation, functions can be used.
The wildcard
function uses the syntax $(wildcard [pattern])
. It returns a list of space-separated files that match the pattern. The *
character matches any string. In this example, $(wildcard *.c)
is replaced by all .c
files: file.c main.c
.
The patsubst
function uses the syntax $(patsubst [pattern], [replacement], [text])
. It replaces all whitespace-separated words in [text]
that match [pattern]
with [replacement]
. The %
character matches any string for all instances of %
in an expression. In this example, the pathsubst function is replaced by file.o main.o
.
$@
is the target of the rule. In this example, cc -o $@ $(objects)
is equivalent to cc -o program $(objects)
.
%.o:
matches all object files. Because main.o
requires file.h
in addition to main.c
, that prerequisite is indicated in the next line. The implicit rules handle the rest.
The rule for clean
has been modified to use the wildcard. It is subtly different from the previous version, which removed all files specified by objects
-- this version removes all files ending in .o
.
Makefile 4:
CFLAGS = -ansi -pedantic -Wall -Werror
objects = $(patsubst %.c, %.o, $(wildcard *.c))
program: $(objects)
cc -o $@ $(objects)
%.o:
main.o: file.h
clean:
rm -f program *.o
Files are sometimes organized by their type. One setup is to put all the source code files in a directory called src
, object files in a directory called obj
, and binary executable in a directory called bin
.
VPATH
is a variable that tells make which directories to search for target and prerequisite files in addition to the working directory. In this example, make will search src/
in addition to the working directory.
Multiple directories are delimited by :
. For example, VPATH = src1:src2:../src3
tells make to search src1/
, src2/
, and ../src3
in addition to the working directory.
The addprefix
function uses the syntax (addprefix [prefix], [names...])
. It prepends [prefix]
to each name in the whitespace-separated [names...]
and returns the result. In this example, the addprefix
function is replaced by obj/main.o obj/file.o
.
Order-only prerequisites are listed after |
. Unlike normal prerequisites, make
does not check whether it is more recent than the target. The syntax for rules is updated to:
[targets]: [normal prerequisites] | [order-only prerequisites]
[recipe]
Whenever a file is added to, removed from, or renamed in a directory, the timestamp of the directory is updated. It is inefficient to rebuild a target just because the timestamp of its prerequisite directory was updated. That is why it is an order-only prerequisite.
$<
is the first prerequisite of the rule. In this example, it would be the C source file corresponding to the target object file.
Makefile 5:
VPATH = src
CFLAGS = -ansi -pedantic -Wall -Werror
objects = $(addprefix obj/, main.o file.o)
bin/program: $(objects) | bin
cc -o $@ $(objects)
obj/%.o: %.c
cc $(CFLAGS) -c -o $@ $<
obj/main.o: file.h
$(objects): | obj
bin:
mkdir bin
obj:
mkdir obj
clean:
rm -rf obj bin