Programming Utilities Guide

Using Implicit Rules to Simplify a Makefile: Suffix Rules

Since the command lines for compiling main.o and data.o from their .c files are now functionally equivalent to the .c.o suffix rule, their target entries are redundant; make performs the same compilation whether they appear in the makefile or not. This next version of the makefile eliminates them, relying on the .c.o rule to compile the individual object files.

Table 4-6 Makefile for Compiling C Sources Using Suffix Rules
# Makefile for a program from two C sources 
# using suffix rules.  
CFLAGS= -O 

.KEEP_STATE:

functions: main.o data.o 
         $(LINK.c) -o functions main.o data.o 
clean: 
         rm functions main.o data.o


Note -

A complete list of suffix rules appears in Table 4-8.


As make processes the dependencies main.o and data.o, it finds no target entries for them. It checks for an appropriate implicit rule to apply. In this case, make selects the .c.o rule for building a .o file from a dependency file that has the same base name and a .c suffix.


Note -

make uses the order of appearance in the suffixes list to determine which dependency file and suffix rule to use. For instance, if there are both main.c and main.s files in the directory, make uses the .c.o rule, since .c is ahead of .s in the list.


First, make scans its suffixes list to see if the suffix for the target file appears. In the case of main.o, .o appears in the list. Next, make checks for a suffix rule to build it with, and a dependency file to build it from. The dependency file has the same base name as the target, but a different suffix. In this case, while checking the .c.o rule, make finds a dependency file named main.c, so it uses that rule.

The suffixes list is a special-function target named .SUFFIXES. The various suffixes are included in the definition for the SUFFIXES macro; the dependency list for .SUFFIXES is given as a reference to this macro:

Table 4-7 The Standard Suffixes List
SUFFIXES= .o .c .c~ .cc .cc~ .C .C~ .y .y~ .l .l~ .s .s~ .sh .sh~ .S .S~ .ln \ .h .h~ .f .f~ .F .F~ .mod .mod~ .sym .def .def~ .p .p~ .r .r~ \ .cps .cps~ .Y .Y~ .L .L~ .SUFFIXES: $(SUFFIXES)

The following example shows a makefile for compiling a whole set of executable programs, each having just one source file. Each executable is to be built from a source file that has the same basename, and the .c suffix appended. For instance demo_1 is built from demo_1.c.


Note -

Like clean, all is a target name used by convention. It builds "all" the targets in its dependency list. Normally, make and make all are usually equivalent.


# Makefile for a set of C programs, one source 
# per program.  The source file names have ".c" 
# appended.  
CFLAGS= -O 
.KEEP_STATE:

all: demo_1 demo_2 demo_3 demo_4 demo_5

In this case, make does not find a suffix match for any of the targets (through demo_5). So, it treats each as if it had a null suffix. It then searches for a suffix rule and dependency file with a valid suffix. In the case of demo_2, it would find a file named demo_2.c. Since there is a target entry for a .c rule, along with a corresponding .c file, make uses that rule to build demo_2 from demo_2.c.

To prevent ambiguity when a target with a null suffix has an explicit dependency, make does not build it using a suffix rule. This makefile

program: zap 
zap:

produces no output:

$ make program 
$