Reputation: 95
here is part of my makefile:
PATH := $(shell pwd)
EDIR := impl
EFFECTS := $(filter-out $(EDIR), $(shell find $(EDIR) -maxdepth 1 -type d))
ALLMAKES := $(patsubst %, $(PATH)/%, $(EFFECTS))
all:
$(foreach c,$(ALLMAKES),$(MAKE) -C $(c))
So essentially, I want to call make for all directories in the "impl" directory without "impl" itself. I understand that make will remember the last directory it was at when last called with the -C argument which is why I give the absolute path everytime. What make echos seems to be what I want:
make -C <projectdir>/impl/thing1 make -C <projectdir>/impl/thing2 make -C <projectdir>/impl/thing3
The issue is that make doesn't accomplish the command and simply prints:
make: make: Command not found.
I can call "make -C <path>" for each of the directories individually outside of the makefile but it doesn't work in the foreach call. I have tried this instead but it doesn't work either:
$(foreach c,$(ALLMAKES),$(shell make -C $(c)))
Any ideas?
Upvotes: 2
Views: 11954
Reputation: 100816
That's because you are calling a single make
, with lots of arguments including the subsequent make
commands. You need to add a shell command separator between the invocations of make. Something like this will work:
all:
$(foreach c,$(ALLMAKES),$(MAKE) -C $(c) && ) true
On second look, there are other issues with your makefile. You should not set a make variable named PATH
, because that will override the subshell's $PATH
variable. You can just use the make built-in variable $(CURDIR)
rather than running $(shell pwd)
. You don't actually need to prefix your directories with the path at all, because running $(MAKE) -C ...
does not change the shell's working directory, just make's, and when make exits it will be set back, so you can just use a relative path.
Also invoking sub-makes in a loop has some issues. First, you reduce the amount of parallelization you can get. Second, the -k
option can't be properly supported (without a lot of unpleasant effort). A better way to handle this issue is to take advantage of the fact that make already knows how to build lots of targets:
all: $(EFFECTS)
$(EFFECTS):
$(MAKE) -C $@
.PHONY: all $(EFFECTS)
If you have specific ordering issues between the different subdirectories, you can define them as well:
impl/thing2: impl/thing1
etc. This ensures maximum parallelization opportunities, while still preserving important ordering.
To add alternative rules, say for clean
, you can do something like this:
CLEAN_EFFECTS := $(addsuffix .clean,$(EFFECTS))
clean: $(CLEAN_EFFECTS)
$(CLEAN_EFFECTS):
$(MAKE) -C $(basename $@) clean
.PHONY: clean $(CLEAN_EFFECTS)
This is nice because you can also build a single subdirectory (and all its prerequisites) by running make impl/thing1
for example. Or clean them by running make impl/thing1.clean
If you have more of these you can also get fancy with pattern rules, etc. to avoid repeating this for every type of target. It gets more cumbersome.
Upvotes: 10