Reputation: 1013
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
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
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
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