tags:

views:

117

answers:

4

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?

+5  A: 

Common practice is to put a Makefile in each subdir with sources, then

all: recursive
    $(MAKE) -C componentX
    # stuff for current dir

or

all: recursive
    cd componentX && $(MAKE)
    # stuff for current dir

recursive: true

It may be wise to put settings for each Makefile in a Makefile.inc in the root source directory. The recursive target forces make to go into the subdirectories. Make sure that it doesn't recompile anything in a target requiring recursive.

If you have many subdirectories, use a loop:

SUBDIRS = componentX componentY

all: recursive
    for i in $(SUBDIRS); do \
        cd "$$i" && $(MAKE) $@; \
    done

(Same for install and other major targets.)

larsmans
Sure, but I'd still have to write "componentX" by hand, which I'm trying to avoid.
ggambett
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.
larsmans
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 http://miller.emu.id.au/pmiller/books/rmch/
Jack Kelly
+3  A: 

This is a side note and do not answer to your question but there is a paper "Recursive Make Considered Harmful". It's worth reading.

Here is the link. http://aegis.sourceforge.net/auug97.pdf

Ilho
+1. I despise recursive make and don't think that anybody should advertise it anymore. Giving the subdirs make.includes isn't any harder than giving them their own makefiles. In fact, it's a little bit easier because they don't need to include a "god" file with all of the project's definitions. And hey, you don't get a bunch of crappy, incomplete dependency graphs! That paper gives some other good advice, too.
Steve M
+1  A: 

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
Christoph
+1  A: 

This should do it:

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

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.)

Beta
To search at any depth, I think `$(wildcard **/*.cpp)` would work.
Jack Kelly
@Jack Kelly: I just tried that and it didn't work (GNU Make 3.81). Does it work with your version?
Beta
@Beta: Yes. I'm also on GNU Make 3.81, so perhaps it's due to something else (glob?) behaving differently on our platforms? I'm on Ubuntu 10.10 amd64.
Jack Kelly