Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

make wildcard subdirectory targets

Tags:

I have a "lib" directory in my applications main directory, which contains an arbitrary number of subdirectories, each having its own Makefile.

I would like to have a single Makefile in the main directory, that calls each subdirectory's Makefile. I know this is possible if I manually list the subdirs, but I would like to have it done automatically.

I was thinking of something like the following, but it obviously does not work. Note that I also have clean, test, etc. targets, so % is probably not a good idea at all.

LIBS=lib/*  all: $(LIBS)  %:   (cd $@; $(MAKE)) 

Any help is appreciated!

like image 300
Zed Avatar asked Dec 19 '09 13:12

Zed


2 Answers

The following will work with GNU make:

LIBS=$(wildcard lib/*) all: $(LIBS) .PHONY: force $(LIBS): force   cd $@ && pwd 

If there might be something other than directories in lib, you could alternatively use:

LIBS=$(shell find lib -type d) 

To address the multiple targets issue, you can build special targets for each directory, then strip off the prefix for the sub-build:

LIBS=$(wildcard lib/*) clean_LIBS=$(addprefix clean_,$(LIBS)) all: $(LIBS) clean: $(clean_LIBS) .PHONY: force $(LIBS): force   echo make -C $@ $(clean_LIBS): force   echo make -C $(patsubst clean_%,%,$@) clean 
like image 102
mrkj Avatar answered Sep 19 '22 17:09

mrkj


There is also a way of listing sub-directories with gmake commands only, without using any shell commands:

test:   @echo $(filter %/, $(wildcard lib/*/)) 

This will list all sub-directories with trailing '/'. To remove it you can use the substitute pattern:

subdirs = $(filter %/, $(wildcard lib/*/)) test:   @echo $(subdirs:%/=%) 

Then to actually create rules executing makefiles in each sub-directory you can use a small trick - a phony target in a non-existent directory. I think in this case an example will tell more than any explanation:

FULL_DIRS =$(filter %/, $(wildcard lib/*/)) LIB_DIRS  =$(FULL_DIRS:%/=%) DIRS_CMD  =$(foreach subdir, $(LIB_DIRS), make-rule/$(subdir))  make-rule/%:   cd $* && $(MAKE)  all: DIRS_CMD 

Basically, target 'all' lists all sub-directories as prerequisites. For example, if LIB_DIRS contained lib/folder1 lib/folder2 then the expansion would look like this:

all: make-rule/lib/folder1 make-rule/lib/folder2 

Then 'make', in order to execute rule 'all', tries to match each prerequisite with an existing target. In this case the target is 'make-rule/%:', which uses '$*' to extract the string after 'make-rule/' and uses it as argument in the recipe. For example, the first prerequisite would be matched and expanded like this:

make-rule/lib/folder1:   cd lib/folder1 && $(MAKE) 
like image 45
Greg Avatar answered Sep 19 '22 17:09

Greg