1.3 Automating the Process with GNU Make

If you're accustomed to programming for the Windows operating system, you're probably accustomed to working with an Integrated Development Environment (IDE). You add sources files to your project, and then the IDE builds your project automatically. Although IDEs are available for Linux, this book doesn't discuss them. Instead, this book shows you how to use GNU Make to automatically recompile your code, which is what most Linux programmers actually do.

The basic idea behind make is simple. You tell make what targets you want to build and then give rules explaining how to build them. You also specify dependencies that indicate when a particular target should be rebuilt.

In our sample reciprocal project, there are three obvious targets: reciprocal.o, main.o, and the reciprocal itself. You already have rules in mind for building these targets in the form of the command lines given previously. The dependencies require a little bit of thought. Clearly, reciprocal depends on reciprocal.o and main.o because you can't link the complete program until you have built each of the object files. The object files should be rebuilt whenever the corresponding source files change. There's one more twist in that a change to reciprocal.hpp also should cause both of the object files to be rebuilt because both source files include that header file.

In addition to the obvious targets, there should always be a clean target. This target removes all the generated object files and programs so that you can start fresh. The rule for this target uses the rm command to remove the files.

You can convey all that information to make by putting the information in a file named Makefile. Here's what Makefile contains:

reciprocal: main.o reciprocal.o 
        g++ $(CFLAGS) -o reciprocal main.o reciprocal.o 
main.o: main.c reciprocal.hpp 
        gcc $(CFLAGS) -c main.c 
reciprocal.o: reciprocal.cpp reciprocal.hpp 
        g++ $(CFLAGS) -c reciprocal.cpp 
        rm -f *.o reciprocal 

You can see that targets are listed on the left, followed by a colon and then any dependencies. The rule to build that target is on the next line. (Ignore the $(CFLAGS) bit for the moment.) The line with the rule on it must start with a Tab character, or make will get confused. If you edit your Makefile in Emacs, Emacs will help you with the formatting.

If you remove the object files that you've already built, and just type

% make 

on the command-line, you'll see the following:

% make 
gcc -c main.c 
g++ -c reciprocal.cpp 
g++ -o reciprocal main.o reciprocal.o 

You can see that make has automatically built the object files and then linked them. If you now change main.c in some trivial way and type make again, you'll see the following:

% make 
gcc -c main.c 
g++ -o reciprocal main.o reciprocal.o 

You can see that make knew to rebuild main.o and to re-link the program, but it didn't bother to recompile reciprocal.cpp because none of the dependencies for reciprocal.o had changed.

The $(CFLAGS) is a make variable. You can define this variable either in the Makefile itself or on the command line. GNU make will substitute the value of the variable when it executes the rule. So, for example, to recompile with optimization enabled, you would do this:

% make clean 
rm -f *.o reciprocal 
% make CFLAGS=-O2 
gcc -O2 -c main.c 
g++ -O2 -c reciprocal.cpp 
g++ -O2 -o reciprocal main.o reciprocal.o 

Note that the -O2 flag was inserted in place of $(CFLAGS) in the rules.

In this section, you've seen only the most basic capabilities of make. You can find out more by typing this:

% info make 

In that manual, you'll find information about how to make maintaining a Makefile easier, how to reduce the number of rules that you need to write, and how to automatically compute dependencies. You can also find more information in GNU, Autoconf, Automake, and Libtool by Gary V.Vaughan, Ben Elliston, Tom Tromey, and Ian Lance Taylor (New Riders Publishing, 2000).