One of the simplest tasks to automate in Gnu Make is directory recursion.
In this example, Make needs to recurse into five directories. In a traditional Makefile, this results in a lot of repetition, as follows:
default: $(MAKE) -C database $(MAKE) -C network $(MAKE) -C client $(MAKE) -C server $(MAKE) -C gui test: $(MAKE) -C database test $(MAKE) -C network test $(MAKE) -C client test $(MAKE) -C server test $(MAKE) -C gui test clean: $(MAKE) -C database clean $(MAKE) -C network clean $(MAKE) -C client clean $(MAKE) -C server clean $(MAKE) -C gui clean all: default test
We’ll optimize this Makefile by first combining the “default”, “clean”, and “test” targets into a single line, and using ”$@” to get the target name instead of hard coding it.
Next, we’ll replace all the separate calls to $(MAKE) with a shell look that reads the SUBDIRS variable.
Finally, targets will be followed by the double colon (::) instead of the single colon. This is required by Make to allow multiple instances of the same target (i.e., there are two instances of “default”, and there could be more instances of “clean” and “test” in a real Makefile).
SUBDIRS=database network client server gui default:: all:: default test default clean test:: for subdir in $(SUBDIRS); do $(MAKE) -C $$subdir $@ || exit 1 ; done
Breaking it out
Now that we know how to simplify the Makefile, it’s time to move the reusable code into its own file.
While we’re at it, we’ll add a switch that let’s us turn off recursion.
ifndef NORECURSE default clean test:: for subdir in $(SUBDIRS); do $(MAKE) -C $$subdir $@ || exit 1 ; done endif
To use “subdirs.mk”, your Makefile might look like:
SUBDIRS=database network client server gui include subdirs.mk