Previous: Phony Targets Prerequisites, Up: Phony Targets


4.6.1 Phony Targets in Recursive Invocations

Another example of the usefulness of phony targets is in conjunction with recursive invocations of make (for more information, see Recursive Use of make). In this case the makefile will often contain a variable which lists a number of subdirectories to be built. One way to handle this is with one rule whose command is a shell loop over the subdirectories, like this:

     SUBDIRS = foo bar baz
     
     subdirs:
             for dir in $(SUBDIRS); do \
               $(MAKE) -C $$dir; \
             done

There are a few problems with this method, however. First, any error detected in a submake is not noted by this rule, so it will continue to build the rest of the directories even when one fails. This can be overcome by adding shell commands to note the error and exit, but then it will do so even if make is invoked with the -k option, which is unfortunate. Second, and perhaps more importantly, you cannot take advantage of make's ability to build targets in parallel (see Parallel Execution), since there is only one rule.

By declaring the subdirectories as phony targets (you must do this as the subdirectory obviously always exists; otherwise it won't be built) you can remove these problems:

     SUBDIRS = foo bar baz
     
     .PHONY: subdirs $(SUBDIRS)
     
     subdirs: $(SUBDIRS)
     
     $(SUBDIRS):
             $(MAKE) -C $@
     
     foo: baz

Here we've also declared that the foo subdirectory cannot be built until after the baz subdirectory is complete; this kind of relationship declaration is particularly important when attempting parallel builds.

Phony targets can have prerequisites. When one directory contains multiple programs, it is most convenient to describe all of the programs in one makefile ./Makefile. Since the target remade by default will be the first one in the makefile, it is common to make this a phony target named `all' and give it, as prerequisites, all the individual programs. For example:

     all : prog1 prog2 prog3
     .PHONY : all
     
     prog1 : prog1.o utils.o
             cc -o prog1 prog1.o utils.o
     
     prog2 : prog2.o
             cc -o prog2 prog2.o
     
     prog3 : prog3.o sort.o utils.o
             cc -o prog3 prog3.o sort.o utils.o

Now you can say just `make' to remake all three programs, or specify as arguments the ones to remake (as in `make prog1 prog3'). Phoniness is not inherited: the prerequisites of a phony target are not themselves phony, unless explicitly declared to be so.

When one phony target is a prerequisite of another, it serves as a subroutine of the other. For example, here `make cleanall' will delete the object files, the difference files, and the file program:

     .PHONY: cleanall cleanobj cleandiff
     
     cleanall : cleanobj cleandiff
             rm program
     
     cleanobj :
             rm *.o
     
     cleandiff :
             rm *.diff