Recursive wildcards in GNU make?

I would try something along these lines

FLAC_FILES = $(shell find flac/ -type f -name '*.flac')
MP3_FILES = $(patsubst flac/%.flac, mp3/%.mp3, $(FLAC_FILES))

.PHONY: all
all: $(MP3_FILES)

mp3/%.mp3: flac/%.flac
    @mkdir -p "$(@D)"
    @echo convert "$<" to "$@"

A couple of quick notes for make beginners:

  • The @ in front of the commands prevents make from printing the command before actually running it.
  • $(@D) is the directory part of the target file name ($@)
  • Make sure that the lines with shell commands in them start with a tab, not with spaces.

Even if this should handle all UTF-8 characters and stuff, it will fail at spaces in file or directory names, as make uses spaces to separate stuff in the makefiles and I am not aware of a way to work around that. So that leaves you with just a shell script, I am afraid :-/


You can define your own recursive wildcard function like this:

rwildcard=$(foreach d,$(wildcard $(1:=/*)),$(call rwildcard,$d,$2) $(filter $(subst *,%,$2),$d))

The first parameter ($1) is a list of directories, and the second ($2) is a list of patterns you want to match.

Examples:

To find all the C files in the current directory:

$(call rwildcard,.,*.c)

To find all the .c and .h files in src:

$(call rwildcard,src,*.c *.h)

This function is based on the implementation from this article, with a few improvements.