Make Wildcard Patterns AKA build all the files you find
Published: Monday, 27 July 2020 by Michael Twomey
You want Make to automatically build all sources in a given folder without having to specify them each time in the Makefile.
You can combine a wildcard to match all the sources, then use a patsubst to name the targets from these, and finally use a static pattern rule to generate the commands to build these.
Note that you could also use a for loop in a shell script inside the Makefile, but you might as well not use Make at that point :)
Example: Generating Graphs with Graphviz
In this example you want to generate PNG images from all the Graphviz dot files in your current directory. These can take a while so you want to use Make to only rebuild the images you’ve modified.
General wildcard patterns
Build all the dot files in the current directory to PNG files.
SOURCES=$(wildcard *.dot) TARGETS=$(patsubst %.dot,%.png,$(SOURCES)) all: $(TARGETS) %.png: %.dot dot -Tpng -o $@ $<
$ make dot -Tpng -o my-graph.png my-graph.dot dot -Tpng -o my-other-graph.png my-other-graph.dot $ touch my-graph.dot $ make dot -Tpng -o my-graph.png my-graph.dot
Wildcards with subdirectories
This is a little more sophisticated, you want a directory with sources to go into a build directory. I include this mostly because I can’t remember the right amount of times to include the
build/ bit in the static patern and the
See also: order only pre-requisites.
BUILDDIR=build SOURCES=$(wildcard src/*.dot) TARGETS=$(patsubst src/%.dot,$(BUILDDIR)/%.png,$(SOURCES)) all: $(TARGETS) $(TARGETS): | $(BUILDDIR) # build the build directory first $(BUILDDIR): mkdir $(BUILDDIR) $(BUILDDIR)/%.png: src/%.dot dot -Tpng -o $@ $<
Note: I originally had
$(TARGETS): $(SOURCES) | $(BUILDDIR) but this caused all the targets to be rebuilt when one source changed. Defeating one of the goals of this approach.
$ make mkdir build dot -Tpng -o build/my-graph.png src/my-graph.dot dot -Tpng -o build/my-other-graph.png src/my-other-graph.dot $ touch src/my-graph.dot $ make dot -Tpng -o build/my-graph.png src/my-graph.dot
You can further refine this by merging a few of the lines together (the GNU Make Manual shows this in their examples):
BUILDDIR=build SOURCES=$(wildcard src/*.dot) TARGETS=$(patsubst src/%.dot,$(BUILDDIR)/%.png,$(SOURCES)) all: $(TARGETS) $(BUILDDIR): mkdir $(BUILDDIR) $(TARGETS): $(BUILDDIR)/%.png: src/%.dot | $(BUILDDIR) dot -Tpng -o $@ $<
Apart from being a little neater this has worked better for me in some situations with more complex patterns.
You can also take the simple case and slightly modify it:
SOURCES=$(wildcard *.dot) TARGETS=$(patsubst %.dot,%.png,$(SOURCES)) all: $(TARGETS) $(TARGETS): %.png: %.dot dot -Tpng -o $@ $<
Improved Wildcards example.