views:

183

answers:

4

I have several hundred files in a non-flat directory structure. My Makefile lists each sourcefile, which, given the size of the project and the fact that there are multiple developers on the project, can create annoyances when we forget to put a new one in or take out the old ones. I'd like to generalize my Makefile so that make can simply build all .cpp and .h files without me having to specify all the filenames, given some generic rules for different types of files.

My question: given a large number of files in a directory with lots of subfolders, how do I tell make to build them all without having to specify each and every subfolder as part of the path? And how do I make it so that I can do this with only one Makefile in the root directory?

EDIT: this almost answers my question, but it requires that you specify all filenames :\

A: 

I would start by using a combination of the wildcard function: http://www.gnu.org/software/make/manual/make.html#Wildcard-Function

VPATH/vpath http://www.gnu.org/software/make/manual/make.html#Selective-Search

and the file functions http://www.gnu.org/software/make/manual/make.html#File-Name-Functions

For exclusion (ie: backups, as Jonathan Leffler mentioned), use a seperate folder not in the vpath for backups, and use good implicit rules.

You will still need to define which folders to do to, but not each file in them.

paquetp
A: 

I'm of two minds on this one. On one hand, if your Make system compiles and links everything it finds, you'll find out in a hurry if someone has left conflicting junk in the source directories. On the other hand, non-conflicting junk will proliferate and you'll have no easy way of distinguishing it from the live code...

I think it depends on a lot of things specific to your shop, such as source source control system and whether you plan to ever have another project with an overlapping code base. That said, if you really want to compile every source file below a given directory and then link them all, I'd suggest simple recursion: to make objects, compile all source files here, add the resultant objects (with full paths) to a list in the top source directory, recurse into all directories here. To link, use the list.

Beta
A: 

I'm sure a pure-gmake solution is possible, but using an external command to modify the makefile, or generate an external one (which you include in your makefile) is probably much simpler.

Something along the lines of:

all: myprog

find_sources:
    zsh -c 'for x in **/*.cpp; echo "myprog: ${x/.cpp/.o}" >> deps.mk'

include deps.mk

and run

make find_sources && make

note: the exact zsh line probably needs some escaping to work in a make file, e.g. $$ instead of $. It can also be replaced with bash + find.

orip
hm, so i'd just have to run a little shell script as one of my targets? i was thinking about doing that, but i was hoping there might have been something built into make that i was missing.
saramah
while not quite as clean as i might like, this seems to be the path of least resistance until i can find a build system that substantially tops make. thanks!
saramah
There is a more concise way to do this. Instead of "find_sources", use "deps.mk" as the target. Then you can just run "make".
Beta
P.S. credit for that technique belongs to Pavel Shved.
Beta
A: 

One way that would be platform independent (I mean independent from shell being in Windows or Linux) is this:

DIRS = relative/path1\
       relative/path2

dd = absolute/path/to/subdirectories
all:
@$(foreach dir, $(DIRS), $(MAKE) -C $(dd)$(dir) build -f ../../Makefile ;)
build:
     ... build here

note that spaces and also the semicolon are important here, also it is important to specify the absolute paths, and also specify the path to the appropriate Makefile at the end (in this case I am using only one Makefile on grandparent folder)

But there is a better approach too which involves PHONY targets, it better shows the progress and errors and stops the build if one folder has problem instead of proceeding to other targets:

.PHONY: subdirs $(DIRS)

subdirs: $(DIRS)

$(DIRS):
    $(MAKE) -C $@ build -f ../../Makefile
all : prepare subdirs
...
build :
... build here

Again I am using only one Makefile here that is supposed to be applicable to all sub-projects. For each sub-project in the grandchild folder the target "build" is created usinf one Makefile in the root.

dashesy