Building a program from source code typically involves a few common steps:
– Writing the source code
– Process the code to expand all *#include* files, macros, etc.
– Compiling the expanded source code to machine assembly language
– Compiling assembly language to machine binary code
– Linking binary code in multiple files or libraries into
an executable binary program
Executing these steps on a small set of source code may be manageable, but
as the source code gets larger, the process becomes more complex.
* The Make System
The *make* command looks for a file called *Makefile* which
defines targets and their prerequisites, and the rules, or
recipes, used to create them.
gcc myprog.o -o myprog
gcc -c myprog.c
rm -f *.o myprog core
To build *myprog* with this *Makefile*:
We could shorten it to just this:
** Rules, Targets, Dependencies
A /rule/ consists of a /target/, the files it depends on and the
actions required to build it.
A rule defines:
– name of the target(s)
– how to decide if the target is out of date and needs to be built
– how to create or update the target
*Make* uses the modification times of the
dependencies to determine when the actions should be invoked.
The commands to build a target are executed if:
– the target file does not exist
– the modification time of the prerequisite(s) are newer than
the existing target file
What happens if the target file exists but the prerequisites do not?
Execution lines must begin with a *<TAB>* character; spaces are not permitted.
Command lines can be continued with a backslash as the last character.
Each line is executed as a separate shell command and processed
by the command interpreter defined in the “SHELL” variable which
defaults to “/bin/sh”.
The exit status of each shell is examined by *make*. If the shell
completed successfully (exit 0), then *make* continues its execution
with the next line. Otherwise, it exits.
The exit value of a line can be ignored by prefacing it with a *-*.
-rm -f *.o a.out core
** Common Targets
Some common targets are *all* and *clean*. The target *all* typically
builds all of the program targets of the *Makefile*. The *clean*
target typically cleans up after the compiler to leave the build directory
in its pre-build state. These are not required nor predefined, you must
define them, if desired.
@rm -f *.o mywc a.out core
Normally, *make* will echo each line before executing it. This can be
turned off with an /’@’/ at the beginning of the line.
** Multiple Targets in a Rule
If multiple targets are defined in a rule, *make* treats each as if it
is a separate target with identical prerequisites and commands.
This is useful to add a prerequisite or when similar recipes are used
for all targets.
king.o queen.o knight.o rook.o: moves.h
** Variables and Macros
*Make* uses variables extensively. Some variables are predefined by *make*.
Environment variables are inherited from the calling
program, and there can be user-defined variables.
Macros are used similarly to variables.
CC = gcc
OBJECTS = myprog.o
CFLAGS = -g -v
myprog = “myprog”
$(CC) $(CFLAGS) $(OBJECTS) -o $@
Environment variables are inherited from the calling environment.
Every environment variable that *make* sees is turned into a *make*
variable with the same name and value.
An explicit variable assignment in a *Makefile* will override the
In order to prefer the inherited values, use the command-line
Environment variables are passed to rule command lines and
recursive *make* commands.
Variables can be added to the environment to make it available
to shell commands, or prevented from being exported:
export MYVAR1 MYVAR2
unexport GCC CFLAGS
The value of a variable can be appended after it is set:
SOURCEFILES = main.c printf.c
SOURCEFILES += add.c
Some variables are defined automatically.
Automatic variables are evaluated fresh for each rule that is
executed, instead of having a fixed value. Some examples:
– $@ Name of the target
– $< Name of the first prerequisite
– $^ Names of all the prerequisites
– $? Names of all prerequisites which are newer than the target
A link to a table of automatic variables is included in the References.
** Suffix & Pattern Rules
By itself, *make* knows how to create a /.o/ file from
its corresponding /.c/ file. It has the following
rule based on filename suffixes predefined:
$(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $<
The rule may also be written as a /Pattern/ rule:
$(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $<
The /%/ represents the basename of the target file. Note the use of
/variables/ to generalize the rule. The /$@/ is the current target and
the /$</ is the current dependency.
Similar to the implicit rule for /.o/ files, *make* has
a predefined implicit rule for making an executable
file from a /.c/ file.
$(LINK.c) -o $@ $< $(LDLIBS)
The rule uses a macro that is defined as:
LINK.c=$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS)
Because of predefined macros and implicit rules, our previous example can
be shortened to this:
rm -f *.o myprog core
Implicit rules make used of many variables, such as:
– AR Program to make archive libraries; default *ar*
– CC Program for compiling C programs; default *cc*
– CFLAGS Extra flags for the C compiler
– LDFLAGS Extra flags for the linker
A link to a table of some common variables used by implicit rules
as part of the References.
Several /directives/ are available to modify the behavior of *make*:
*** Conditonal Directives
/Conditional/ directive causes parts of the *Makefile* to be used or ignored
based on the value of variables:
– ifeq /( arg1 , arg2 )/
– ifneq /( arg1 , arg2 )/
– ifdef /condition/
– ifndef /condition/
*** Other Directives
The *include* directive causes *make* to read the specified file(s)
before continuing. The *override* directive changes the value of a
variable which was set on the *make* command line:
– include /file1/ /file2/ /…/
– override /var = value/
** Recursive *make*
The *make* command can be used in a *Makefile* just as any other
command. This is useful when there are multiple susbsystems which
comprise one larger system:
subdir = /some/other/dirname
$(MAKE) -C $(subdir)
Environment variables are passed to each command line and recursive *make*.
By default, only environment variables that came from the environment or the
*make* command line will be passed. The /export/ directive can pass other
What happens in the following example?
FOO = foo
** Command Line Arguments
*Make* has many command line arguments which can alter its behavior.
Variables can be set on the command line.
Some common arguments:
– make -i /# Ignore the exit value of shell commands/
– make -d /# Print debugging information/
– make -n /# Dry-run; only print what would be done/
– make -t /# Touch files instead of running rules/
– make -e /# Environment variables override *Makefile* assignments/
– make -r /# Disable the built-in implicit rules/
– make -j /N/ /# Run N jobs at once/
– make VAR=value /# Set the value of variable VAR/
** Further Exploration
Most GNU source code (and many others) use
*autoconf* and *automake* to create templates for *make*
which make it more portable and can better account for the
build machine environment. These are commands that make
* Make Tutorials Available on the Web
** A Simple Makefile Tutorial:
** Tutorial by Example:
** A tutorial and reference *PDF*:
* Make References
** The GNU *make* reference manual:
** Catalogue of Built-In Rules
** Default Suffix Rules and Predefined Macros
** List of Automatic Variables
** Variables Used by Implicit Rules
** A Short Guide to Makefiles:
** A GNU *make* cheat sheet on /GitHub/
Includes a *Makefile* for building a PDF version from LaTex source files: