Reputation: 21
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))
Upvotes: 1
Views: 3044
Reputation: 100916
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
)
Upvotes: 0
Reputation: 80969
You don't want $(eval)
there. It is wrong. The contents being passed to it are not makefile contents they are shell contents.
You want:
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.
Upvotes: 1