Makefile with foreach loop - *** missing separator
I am new to makefiles.
I have a large number of fairly similar directories each of which contains a makefile and some source, all of which I want to address from the directory above with an overarching makefile. The makefiles in the directories work. The number of subdirectories will grow in the future, so whatever I design should be able to grow indefinitely.
If I call the subdirectory makefiles directly I have no problem,
mytarget: cd a && $(MAKE) mytarget cd b && $(MAKE) mytarget cd c && $(MAKE) mytarget
but I do get a **** missing separator error when I try the below attached. I have used tabs, no spaces, so I do not understand my error.
LIST = a b c d e mytarget: $(foreach var,$(LIST),$(eval cd $(var) && $(MAKE) mytarget))
You don't want $(eval) there. It is wrong. The contents being passed to it are not makefile contents they are shell contents.
LIST = a b c d e mytarget: $(foreach var,$(LIST),cd $(var) && $(MAKE) mytarget; cd ..;)
Because you want the result of the $(foreach) call to be the recipe body.
Another option that might be more understandable (or might not...) is to use a shell loop, not a makefile loop. Also this results in a shorter script which could be important if you get enough subdirectories and you want to work on systems with more limited command line length restrictions:
LIST = a b c d e mytarget: for var in $(LIST); do $(MAKE) -C $$var $@; done
Or if you would prefer to use cd instead of the GNU make -C option, something like this:
LIST = a b c d e mytarget: for var in $(LIST); do (cd $$var && $(MAKE) $@); done
Note we use parentheses here to start the make in a subshell, so we don't have to use something like cd .. (which will not work if some element in LIST is a path rather than a simple directory, e.g. f/g/h or similar).
The big problem with these solutions is the error handling is all broken. What if the sub-make for the a target fails? These makefiles will not notice that. Also, parallelism is not ideal: in all cases here only a single sub-make will be invoked at a time.
The best way to write loops in makefiles is using multiple prerequisites, not a loop inside a recipe. Something like this:
LIST = a b c d e mytarget: $(addprefix mytarget-,$(LIST)) mytarget-%: $(MAKE) -C $* mytarget
(or, cd $* && $(MAKE) mytarget)