You want to use GNU make to build a simple “Hello, World” program, such as that in Example 1-4.
Before you write your first makefile, you’ll need to know a little terminology. A makefile consists of a collection of rules of the form
prerequisites are space-separated strings, and
consists of zero or more lines of text, each of which begins with a Tab character. Targets
and prerequisites are usually files names, but sometimes they are simply formal names for
actions for make to perform. The command script
consists of a sequence of commands to be passed to a shell. Roughly speaking, a rule tells
make to generate the collection of targets from the
collection of prerequisites by executing the command script.
Whitespace in makefiles is significant. Lines containing command scripts must begin with a Tab rather than a Space — this is a source of some of the most common beginner errors. In the following examples, lines which begin with a Tab are indicated by an indentation of four characters.
Now you’re ready to begin. Create a text file named makefile in the directory containing your source file. In this file, declare
four targets. Call the first target
all, and specify
the name of the executable you wish to build as its sole prerequisite. It should have no
command script. Give the second target the same name as your executable. Specify your
application’s source file as its prerequisite, and specify the command line needed to
build the executable from the source file as your target’s command script. The third
target should be called
install. It should have no
prerequisites, and should have a command script to copy the executable from the directory
containing the makefile to the directory where you want it installed. The last target
should be called
clean. Like install, it should have no
prerequisites. Its command script should remove the executable and the intermediate object
file from the current directory. The
install targets should both be labeled as
phonytargets, using the
Example 1-14. Makefile to build the executable hello with GCC
# This is the default target, which will be built when # you invoke make .PHONY: all all: hello # This rule tells make how to build hello from hello.cpp hello: hello.cpp g++ -o hello hello.cpp # This rule tells make to copy hello to the binaries subdirectory, # creating it if necessary .PHONY: install install: mkdir -p binaries cp -p hello binaries # This rule tells make to delete hello and hello.o .PHONY: clean clean: rm -f hello
Example 1-15. Makefile to build the executable hello.exe with Visual C++
Commands and lists of targets or prerequisites can span more than one line of text in a makefile by using the continuation character \, just as in C++ source files.
To build your executable, set any environment variables required by your command-line
tools, change to the directory containing makefile
make. To copy your executable to the
binaries subdirectory, enter
install. To delete the executable and the
intermediate object file from the makefile directory, enter
You can also execute this makefile from the Cygwin shell, as follows. From cmd.exe, run vcvars32.bat to set Visual C++’s environment variables. Next, run
cygwin.bat to start the Cygwin shell. If you
place the Cygwin installation directory in your
you can start the Cygwin shell from cmd.exe simply
cygwin. Finally, change to the
directory containing the makefile and enter
Similarly, you can execute the makefile from the MSYS shell: run vcvars32.bat from cmd.exe, then run msys.bat to start the MSYS shell.
If your toolset provides a script to set environment variables, running a makefile from Cygwin or MSYS is slightly more involved than running it from cmd.exe. It’s necessary for some makefiles, however, since they simply won’t work from cmd.exe.
In the next few recipes, you’ll see that GNU make is a powerful tool for building complex projects. But what does it actually do? Here’s how it works. When make is invoked with no arguments, it looks in the current directory for a file named GNUmakefile, makefile or Makefile, and attempts to build the first target it contains, called the default target. If the default target is up to date — meaning that it exists, that all its prerequisites are up to date, and that none of its prerequisites has been modified more recently than it has — make’s job is done. Otherwise, it attempts to generate the default target from its prerequisites by executing its command script. Like the definition of up to date, this process is recursive: for each prerequisite which is not up to date, make searches for a rule having that prerequisite as a target, and starts the whole process again. This continues until the default target is up to date or until an error occurs.
It follows from the above description that a target having no prerequisites is up to date if and only if it corresponds to a file on the filesystem. Therefore, a target corresponding to a non-existent file is never up to date, and can be used to force a command script to be executed unconditionally. Such targets are called phony targets.
Conversely, a prerequisite corresponding to an existing file is always up to date, provided it doesn’t appear as the target of a rule.
Now let’s look at what happens when we execute the makefile in Example 1-14. The phony target
all is always out of date: its only purpose is to tell make to
build hello.exe. In such a simple makefile, there’s
no need for an
all target; in more complex examples,
all target may have several prerequisites. The rule
hello tells make to build hello, if necessary, by
invoking g++. Assuming that the current directory is
empty except for makefile and hello.cpp, the target
hello is not up to date. The prerequisite is up to date,
however, because the file hello.cpp exists, and
hello.cpp does not appear as the target of any
rule. Consequently, make invokes g++ to compile and link hello.cpp, producing the file hello.
The prerequisite to the
all target is now up to date,
so make builds the
all target — by executing an empty command script — and exits.
When you invoke make with a command-line argument corresponding to a target, make
attempts to build that target. Therefore executing
install causes the following commands to be
mkdir -p binaries cp -p hello binaries
The first command creates the directory binaries,
if it doesn’t already exist; the second command copies hello
to that directory. Similarly,
clean invokes the command
rm -f hello
which deletes the hello.
If you’re using Windows, the
rm commands used
clean targets refer to the GNU tools distributed with Cygwin or
Once you understand how make analyzes dependencies, Example 1-14 may seem pretty simple. In fact, however, it’s considerably more complicated than it needs to be; looking at the various ways it can be simplified is a good way to learn some of the rudiments of makefiles.
GNU make supports variables whose values are strings. The most common use of variables in makefiles is as symbolic constants; instead of hard-coding the name of a file or a shell command in several locations within a makefile, you can assign the file or command name to a variable and use the variable instead. This leads to simpler and easier to maintain makefiles. For example, you can rewrite the makefile from Example 1-14 using make variables, as shown in Example 1-16.
Example 1-16. Makefile to build the executable hello with GCC, modified to use make variables
# Specify the target file and the install directory OUTPUTFILE=hello INSTALLDIR=binaries # Default target .PHONY: all all: $(OUTPUTFILE) # Build hello from hello.cpp $(OUTPUTFILE): hello.cpp g++ -o hello hello.cpp # Copy hello to the binaries subdirectory .PHONY: install install: mkdir -p $(INSTALLDIR) cp -p $(OUTPUTFILE) $(INSTALLDIR) # Delete hello .PHONY: clean clean: rm -f $(OUTPUTFILE)
Here I’ve introduced two make variables,
INSTALLDIR. As you can
see, make variables can be assigned values using the assignment operator
=, and they can be evaluated by enclosing them in
parentheses and prefixing a dollar sign.
You can also set the value of a make variable on the command line, using the syntax
Y. In addition, when make
starts up, each environment variable is used to initialize a make variable with the same name and value. Values specified on the
command line take precedence over values inherited from the environment; values
specified in the makefile itself take precedence over values specified on the command
GNU make also supports
automatic variables that take special values when
evaluated in a command script. Most importantly, the variable
$@ represents the filename of the target, the variable
$< represents the filename of the first prerequisite, and
$^ represents the sequence of
prerequisites, separated by spaces. Using these variables, we can further simplify the
makefile from Example 1-16, as shown in
Example 1-17. Makefile to build the executable hello with GCC, modified to use automatic variables
# Specify the target file and the install directory OUTPUTFILE=hello INSTALLDIR=binaries # Default target .PHONY: all all: $(OUTPUTFILE) # Build hello from hello.cpp $(OUTPUTFILE): hello.cpp g++ -o $@ $< # Install and clean targets as in Example 1-16
Within the command script
$<, the variable
$@ expands to hello and the variable
$< expands to
the makefile in Example 1-17 is
equivalent to that in Example 1-16, but
involves less code duplication.
The makefile in Example 1-17 can
still be radically simplified. In fact, the command script associated with
hello is superfluous, as you can
demonstrate by executing the makefile in Example 1-18.
Example 1-18. Makefile to build the executable hello with GCC, modified to use implicit rules
# Specify the target file and the install directory OUTPUTFILE=hello INSTALLDIR=binaries # Default target .PHONY: all all: $(OUTPUTFILE) # Tell make to rebuild hello whenever hello.cpp is modified $(OUTPUTFILE): hello.cpp # Install and clean targets as in Example 1-16
How does make know how to build the executable hello from the source file hello.cpp, without being told? The answer is that make maintains an internal database of implicit rules representing operations commonly performed when building C and C++ applications. For example, the implicit rule to generate an executable file from a .cpp file looks like Example 1-19.
Example 1-19. A pattern rule from make’s internal database
%: %.cpp # commands to execute (built-in): $(LINK.cpp) $^ $(LOADLIBES) $(LDLIBS) -o $@
Rules with first lines of the form
yyy are known as
pattern rules; the
character act as a
wildcard. When no ordinary rule matches an out-of-date
prerequisite, make searches the available pattern
rules. For each pattern rule, make tries to find a string which when substituted for the
wildcard character in the target portion of the pattern rule yields the out-of-date
prerequisite. If make finds such a string,
make substitutes it for the wildcard character in
both the target and prerequisite portions of the pattern rule to produce a new rule.
make then attempts to build the out-of-date
prerequisite using the new rule.
For example, when the makefile in Example
1-18 is first executed, the prerequisite
hello of the default target
all is out
of date. Although
hello does appear as a target in
hello.cpp, this rule has no command script, and so is useless for building
the file hello.make therefore searches its internal database, and finds the rule shown in
Example 1-19. By substituting the
hello for the wildcard character in the rule
in Example 1-19, make generates the following rule, with
hello as its target:
hello: hello.cpp $(LINK.cpp) $^ $(LOADLIBES) $(LDLIBS) -o $@
So far, so good — but clearly there’s more to the story. Looking once again through
make’s internal database reveals that the
LINK.cpp expands, by default, to
turn, expands by default to
$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
Finally, the variable
CXX expands by default to
g++, and the other four variables—
$(TARGET_ARCH)—expand to empty strings. When all these substitutions are
carried out, we’re left with the following rule, which by now may look familiar.
hello: hello.cpp g++ $^ -o $@
Now that you see how the pattern rule in Example 1-19 causes make to build the executable hello from the source file hello.cpp, you might well wonder why it was necessary to go through so many intermediate steps. Why not simply add the rule
%: %.cpp g++ $^ -o $@
to make’s internal database, instead of the
complex rule in Example 1-19? The
answer is that the intermediate variables such as
$(LDFLAGS), serve as user customization points. For example, you can specify
additional flags to be passed to the linker by specifying a value for
LDFLAGS on the command line, in a makefile, or by setting an
environment variable. The variables
CXXFLAGSplay a similar role for C++ preprocessor
and compiler options, respectively. You can even specify a compiler other than GCC by
setting the variable
CXX. For example, to build
hello with Intel for Linux using the makefile in
Example 1-18, you can enter
CXX=icpc from the command line—assuming you’ve
set the environment variables required by the Intel compiler.
In Example 1-18, make is able to apply the correct pattern rule because the
.cpp file resides in the directory where the
output file is to created. If your source files are in a different directory, you can
variable to tell make where to search for targets or
You can also use a
vpath directive to tell
make to look in a certain location for particular
types of files:
# look for .exp files in ../lib vpath %. exp../lib