2

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)))
Teddy
  • 993
  • 10
  • 20
  • Does this answer your question? [How to list only files and not directories of a directory Bash?](https://stackoverflow.com/questions/10574794/how-to-list-only-files-and-not-directories-of-a-directory-bash) – Victor Sergienko Feb 18 '21 at 01:57
  • Generally, there's no such a tool in `make` except for maybe when it's built with guile (it rarely is). You'll have to resort to `$(shell find ...)` function, if that's for sure what you want to do; but maybe it's a XY problem? – Victor Sergienko Feb 18 '21 at 04:17
  • Do you still look for a solution to this? – Vroomfondel Feb 22 '21 at 09:39
  • @Vroomfondel Thanks for asking! No, and in the meantime I marked an answer as accepted. – Teddy Feb 22 '21 at 13:34

3 Answers3

2

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
raspy
  • 3,995
  • 1
  • 14
  • 18
0

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.

urznow
  • 1,576
  • 1
  • 4
  • 13
0

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
Vroomfondel
  • 2,704
  • 1
  • 15
  • 29