Teddy
Teddy

Reputation: 1013

Find files in makefile

I'm creating a makefile for GNU make. I want to find all files within a directory structure. For this I tried:

find_files_recursive = $(wildcard $(1)/*)$(foreach dir,$(wildcard $(1)/*),$(call find_files_recursive,$(dir)))

$(info $(call find_files_recursive,.))

The problem is that this prints also the directories, not only files. Any ideas how to eliminate directories?

Edit: I have to create an OS independent solution. So the Unix-way find -type f is no alternative. But it is exactly what I have to solve.

Used solution: Based on the accepted answer I developed a shorter version:

find_files_recursive = $(foreach item,$(wildcard $(1)/*),$(if $(wildcard $(item)/.),$(call find_files_recursive,$(item),$(2)),$(item)))

Upvotes: 2

Views: 2050

Answers (3)

Vroomfondel
Vroomfondel

Reputation: 2898

As the request for such a functionality keeps popping up regularly there now exists an extension to the built-in function wildcard in the GNUmake table toolkit. It distinguishes between files and directories via a obvious feature: if the given glob ends in / then you want directories, if the / is absent you want files.

include gmtt.mk

$(info $(call wildcard-rec,**.c)) # all C source files in the tree

$(info $(call wildcard-rec,**.c **.h)) # a C source and header files

$(info $(call wildcard-rec,drivers/**.c)) # only sources for the `drivers` tree

$(info $(call wildcard-rec,drivers/**/test/)) # all test subdirectories in the `drivers` tree

$(info $(call wildcard-rec,drivers/**/test/*.cfg)) # config files in all test subdirectories in the `drivers` tree

Upvotes: 0

raspy
raspy

Reputation: 4261

You can make use of $(wildcard) to check if a name is actually a directory by trying to append /. to its name. This would try to reach directory from the directory itself and it would not work for files. For example:

$ cat Makefile
filter_files = $(foreach item,$(1),$(if $(wildcard $(item)/.),,$(item)))
find_files_recursive = $(call filter_files,$(wildcard $(1)/*)) $(foreach dir,$(wildcard $(1)/*/.),$(call find_files_recursive,$(dir:/.=)))

$(info $(call find_files_recursive,.))

Output:

$ ls -R
.:
Makefile  foo

./foo:
bar  fooA  fooB

./foo/bar:
barA  baz

./foo/bar/baz:
bazA

$ make
 ./Makefile ./foo/fooB  ./foo/fooA ./foo/bar/barA  ./foo/bar/baz/bazA

Upvotes: 2

urznow
urznow

Reputation: 1801

For GNU Make 4.2.1:

ffrec = $(foreach E,$(wildcard $(1)/*),\
        $(if $(realpath $(E)/.),$(call ffrec,$(E)),$(E)))
files  := $(call ffrec,.)

Combine with $(sort …) if appropriate.

Upvotes: 0

Related Questions