Pattern Rules

Having one rule for each compilation command is fine when there are only a few files, but what if your program consists of dozens of source files? Most of them have to be compiled with very similar commands. It is tedious to type in a separate rule for each source file, and then if you decide to change the rules, you have to change the makefile in a dozen places. A better solution to this problem is to use a pattern rule.

A pattern rule is a concise way of specifying a rule for many files at once. The rule will depend on the file names, but usually it depends on them in a simple way. You specify a pattern by using the % wildcard. When present in the dependency list, % matches any string of any length; when present in the list of targets, % stands for the string that % in the dependency list matched.

The following pattern rule will take any .c file and compile it into a .o file:

%.o: %.c
	$(CC) $(CFLAGS) $(INCLUDES) -c $(input) -o $(output)

(This assumes that you have the variables CC, CFLAGS, and INCLUDES defined to be something suitable. Makepp will guess a value for CC and CFLAGS.)

The first line of the rule says that it applies to every possible input file that matches the pattern %.c. These .c files can be transformed into the corresponding .o file using the specified actions.

The action of rule is quite similar to the other actions we've seen previously, except that it uses automatic variables. An automatic variable is a variable whose value is automatically set by makepp depending on the rule that it appears in. Some useful automatic variables are:

$(input)
The name of the first input file. In this rule, this would be the file that matches the %.c pattern. $(dependency) is a synonymn for $(input). In older makefiles, you will also see the cryptic symbol $< used as well.
$(output)
The name of the first output file. In this rule, this would be the file that matches the %.o pattern. $(target) and $@ are synonymns.
$(inputs)
The name of all explicitly listed input files. In this case, since there is only one, $(inputs) is equivalent to $(input). $(dependencies) and $^ are synonymns.
$(outputs)
The name of all explicitly listed targets. In this case, since there is only one, $(outputs) is equivalent to $(output). $(targets) is a synonymn for $(outputs).

Note that these variables are lower case.

You can use these automatic variables even for non-pattern rules. This avoids repeating target filenames.

You can actually do considerably more complicated things with pattern rules. For example,

# Put the object files into a separate directory:
objects/%.o: %.cpp
	$(CXX) $(CXXFLAGS) -c $(input) -o $(output)

# Run a preprocessor to make source files:
moc_%.cxx: %.h
	$(MOC) $(input) -o $(output)

Using pattern rules and automatic variables, we'd probably rewrite our makefile for our simple program like this:

CXX	:= c++
CXXFLAGS := -g
INCLUDES := -I.			# This would contain any -I options to the
				# compiler, if there are any.
LIBS	:= -L/usr/X11R6/lib -lX11 # Contains libraries we need to link in.
OBJECTS	:= processing.o gui.o

my_program: $(OBJECTS)
	$(CXX) $(inputs) -o $(output) $(LIBS)

%.o: %.cxx
	$(CXX) $(INCLUDES) $(CXXFLAGS) -c $(input) -o $(output)

Now we don't have to have an explicit rule for each object file we need to produce. If we want to add another module to our program, we only have to change the one line that defines the OBJECTS variable. Note that this makefile is now much more concise than our original makefile. Each piece of information occurs only once so there is no possibility of making a mistake by changing information in one place and forgetting to change it in others.


When you use pattern rules, it's not uncommon for there to be two different rules that can produce the same file. If both rules are pattern rules, then the one that occurs later in the makefile is actually used. If one rule is a pattern rule, and the other is an explicit rule (one that actually names the target file explicitly), then the explicit rule is used. This is often helpful if you want to compile most modules with the same command, but there is one module that needs slightly different compilation options, as shown in this makefile fragment:

CXXFLAGS := -g -O2
FAST_CXXFLAGS := -DNO_DEBUG -O6 -malign-double -funroll-all-loops

%.o: %.cpp
	$(CXX) $(CXXFLAGS) -c $(input) -o $(output)

time_critical_subs.o: time_critical_subs.cpp
	$(CXX) $(FAST_CXXFLAGS) -c $(input) -o $(output)

If you find yourself wanting to do something with patterns that isn't expressed easily using the % wildcard, makepp has another syntax which is somewhat harder to read, but considerably more powerful. See the :foreach clause for more details.


Makepp actually has builtin rules for compiling C or C++ or Fortran code, which are available if you don't override them with your own rules. The builtin rules are almost identical to the examples above. Most makefiles contain pattern rules for compilation, but you can depend on the builtin rules if you want.


Tutorial index | Next (phony targets) | Previous (using variables)
Last modified: Tue Dec 26 19:34:43 PST 2000