Make Wildcard Patterns AKA build all the files you find

Published: Monday, 7 July 2020 by Michael Twomey

The Problem

You want Make to automatically build all sources in a given folder without having to specify them each time in the Makefile.

The Solution

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)

all: $(TARGETS)

	dot -Tpng -o $@ $<
❯ make
dot -Tpng -o my-graph.png
dot -Tpng -o my-other-graph.png

❯ touch

❯ make
dot -Tpng -o my-graph.png

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 patsubst.

See also: order only pre-requisites.

SOURCES=$(wildcard src/*.dot)
TARGETS=$(patsubst src/,$(BUILDDIR)/%.png,$(SOURCES))

all: $(TARGETS)

$(TARGETS): | $(BUILDDIR)  # build the build directory first

	mkdir $(BUILDDIR)

$(BUILDDIR)/%.png: src/
	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/
dot -Tpng -o build/my-other-graph.png src/

❯ touch src/

❯ make
dot -Tpng -o build/my-graph.png src/