Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I have a C++ library built using a Makefile. Until recently, all the sources were in a single directory, and the Makefile did something like this

SOURCES = $(wildcard *.cpp)

which worked fine.

Now I've added some sources that are in a subdirectory, say subdir . I know I can do this

SOURCES = $(wildcard *.cpp) $(wildcard subdir/*.cpp)

but I'm looking for a way to avoid specifying subdir manually, that is, make wildcard look into subdirectories, or generating a list of subdirectories somehow and expanding it with several wildcard functions. At this point, having a non-recursive solution (that is, expanding only the first level) would be fine.

I haven't found anything - my best guess is using find -type d to list the subdirectories, but it feels like a hack. Is there any built-in way to do this?

@Jeroen should be the other way around as this question has a superior answer (using ** ). user1804599 Mar 13, 2016 at 10:28

If you change you mind and want a recursive solution (i.e. to any depth), it can be done but it involves some of the more powerful Make functions. You know, the ones that allow you to do things you really shouldn't.

EDIT:
Jack Kelly points out that $(wildcard **/*.cpp) works to any depth, at least on some platforms, using GNUMake 3.81. (How he figured that out, I have no idea.)

@Jack Kelly: I just tried that and it didn't work (GNU Make 3.81). Does it work with your version? Beta Oct 28, 2010 at 1:40 **/* isn't working for me. OS X 10.8.2, GNU Make 3.81. It's behaving sort of weird actually... RyanM Nov 16, 2012 at 23:47 **/*.cpp does work for me, but it does not include anything in the current directory (i.e. to get behavior similar to *.cpp */*.cpp */*/*.cpp ... , you have to do *.cpp **/*.cpp ), which is rather unfortunate IMO. Ponkadoodle Nov 5, 2015 at 23:59

Recursive wildcards can be done purely in Make, without calling the shell or the find command. Doing the search using only Make means that this solution works on Windows as well, not just *nix.

# Make does not offer a recursive wildcard function, so here's one:
rwildcard=$(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2))
# How to recursively find all files with the same name in a given folder
ALL_INDEX_HTMLS := $(call rwildcard,foo/,index.html)
# How to recursively find all files that match a pattern
ALL_HTMLS := $(call rwildcard,foo/,*.html)

The trailing slash in the folder name is required. This rwildcard function does not support multiple wildcards the way that Make's built-in wildcard function does, but adding that support would be straightforward with a couple more uses of foreach.

This doesn't work for me. It returns all subdirectories and files regardless of the provided pattern. – Antimony May 5, 2014 at 22:25 @Antimony: (In case you did...) Do not add extra spaces within the recursive $(call ...) around commas separating arguments. Adding such spaces alters the result. – Petr Vepřek Dec 16, 2017 at 9:31

If you don't want to use recursive makefiles, this might give you some ideas:

subdirs := $(wildcard */)
sources := $(wildcard $(addsuffix *.cpp,$(subdirs)))
objects := $(patsubst %.cpp,%.o,$(sources))
$(objects) : %.o : %.cpp
SOURCES := $(wildcard *.cpp */*.cpp */*/*.cpp */*/*/*.cpp)

Unfortunately, and unlike what we sometimes read, glob (**) is not supported by makefile and will be interpreted as normal wildcard (*).

For example **/*.cpp match dir/file.cpp but neither file.cpp nor dir/sub/file.cpp.

If you need infinite depth use shell and find:

SOURCES := $(shell find . -name "*.cpp")
                Please do it this way. Simply compiling and linking every source/object file in every subdir is going to break once you want to build a library, build one file with special compiler settings, write test programs, etc. I always list every single object file in my Makefiles and sometimes every single source file. Listing a few directories to loop over isn't much of a pain.
– Fred Foo
                Oct 27, 2010 at 18:25
                Don't call make -C directly. You need to call $(MAKE) -C instead. The version of make being run could be different from the system make. In addition, aren't you going to set off an infinite loop by running $(MAKE) $@? Lastly, recursive make is considered harmful by some. See miller.emu.id.au/pmiller/books/rmch
– Jack Kelly
                Oct 27, 2010 at 23:22
                Note: with recursive makefile approach, it's hard to get your dependencies right. Good read: Resurvie Make Considered Harmfull
– harmv
                Feb 26, 2014 at 12:36

If you can use find shell command, you may define a function to use it.

recurfind = $(shell find $(1) -name '$(2)')
SRCS := $(call recurfind,subdir1,*.c) $(call recurfind,subdir2,*.cc) $(call recurfind,subdir2,*.cu) \
        

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.