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))

Answers


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.


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)


Need Your Help

Not able to get id in controller

php codeigniter

I am sending ID through anchor tag in codeigniter

JSON Dictionary Duplicate Automatically Eliminated

python json dictionary wikipedia dump

The problem is that there are multiple revision IDs and it only takes one revision ID no matter how many ever revisions are present. Using Dictionary along with JSON.