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!
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
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With