variable - while loop in makefile




How to write loop in a Makefile? (6)

I want to execute the following commands:

./a.out 1
./a.out 2
./a.out 3
./a.out 4
.
.
. and so on

How to write this thing as a loop in a Makefile?


THE major reason to use make IMHO is the -j flag. make -j5 will run 5 shell commands at once. This is good if you have 4 CPUs say, and a good test of any makefile.

Basically, you want make to see something like:

.PHONY: all
all: job1 job2 job3

.PHONY: job1
job1: ; ./a.out 1

.PHONY: job2
job2: ; ./a.out 2

.PHONY: job3
job3: ; ./a.out 3

This is -j friendly (a good sign). Can you spot the boiler-plate? We could write:

.PHONY: all job1 job2 job3
all: job1 job2 job3
job1 job2 job3: job%:
    ./a.out $*

for the same effect (yes, this is the same as the previous formulation as far as make is concerned, just a bit more compact).

A further bit of parameterisation so that you can specify a limit on the command-line (tedious as make does not have any good arithmetic macros, so I'll cheat here and use $(shell ...))

LAST := 1000
NUMBERS := $(shell seq 1 ${LAST})
JOBS := $(addprefix job,${NUMBERS})
.PHONY: all ${JOBS}
all: ${JOBS} ; echo "[email protected] success"
${JOBS}: job%: ; ./a.out $*

You run this with make -j5 LAST=550, with LAST defaulting to 1000.


For cross-platform support, make the command separator (for executing multiple commands on the same line) configurable.

If you're using MinGW on a Windows platform for example, the command separator is &:

NUMBERS = 1 2 3 4
CMDSEP = &
doit:
    $(foreach number,$(NUMBERS),./a.out $(number) $(CMDSEP))

This executes the concatenated commands in one line:

./a.out 1 & ./a.out 2 & ./a.out 3 & ./a.out 4 &

As mentioned elsewhere, on a *nix platform use CMDSEP = ;.


If you're using GNU make, you could try

NUMBERS = 1 2 3 4
doit:
        $(foreach var,$(NUMBERS),./a.out $(var);)

which will generate and execute

./a.out 1; ./a.out 2; ./a.out 3; ./a.out 4;

Maybe you can use:

xxx:
    for i in `seq 1 4`; do ./a.out $$i; done;

This is not really a pure answer to the question, but an intelligent way to work around such problems:

instead of writing a complex file, simply delegate control to for instance a bash script like: makefile

foo : bar.cpp baz.h
    bash script.sh

and script.sh looks like:

for number in 1 2 3 4
do
    ./a.out $number
done

You can use set -e as a prefix for the for-loop. Example:

all:
    set -e; for a in 1 2 3; do /bin/false; echo $$a; done

make will exit immediately with an exit code <> 0.





loops