Programming Utilities Guide

Compiling Programs for Debugging and Profiling

Compiling programs for debugging or profiling introduces a new twist to the procedure and to the makefile. These variants are produced from the same source code, but are built with different options to the C compiler. Use the cc -g option to produce object code that is suitable for debugging. The cc options that produce code for profiling are -O and -pg.

Because the compilation procedure is the same otherwise, you could give make a definition for CFLAGS on the command line. Since this definition overrides the definition in the makefile, and .KEEP_STATE assures any command lines affected by the change are performed, the following make command produces the results as presented in this example:

$ make "CFLAGS= -O -pg" 
cc -O -pg -c main.c 
cc -O -pg -c data.c 
cc -O -pg -o functions main.o data.o -lcurses -ltermlib

Of course, you might not want to memorize these options or type a complicated command like this, especially when you can put this information in the makefile. What is needed is a way to tell make how to produce a debugging or profiling variant, and some instructions in the makefile that tell it how. One way to do this might be to add two new target entries, one named debug, and the other named profile, with the proper compiler options hard-coded into the command line.

A better way would be to add these targets, but rather than hard-coding their rules, include instructions to alter the definition of CFLAGS, depending upon which target it starts with. Then, by requiring each one to depend on the existing target for functions, make could use its rule, along with the specified options.

Instead of saying:

make "CFLAGS= -g"

to compile a variant for debugging, you could say:

make debug

The question is, how do you tell make that you want a macro defined one way for one target (and its dependencies), and another way for a different target?

Conditional Macro Definitions

A conditional macro definition is a line of the form:

target-list := macro = value

which assigns the given value to the indicated macro while make is processing the target named target-list and its dependencies.


Note -

Each word in target-list can contain one % pattern; make must know which targets the definition applies to, so you cannot use a conditional macro definition to alter a target name.


The following lines give CFLAGS an appropriate value for processing each program variant.

debug := CFLAGS= -g 
profile := CFLAGS= -pg -O

Notice that when you use a reference to a conditional macro in the dependency list, that reference must be delayed (by prepending a second $). Otherwise, make expands the reference before the correct value has been assigned. When it encounters a (possibly) incorrect reference of this sort, make issues a warning.