How to write loop in a Makefile?

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 following will do it if, as I assume by your use of ./a.out, you're on a UNIX-type platform.

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

Test as follows:

target:
    for number in 1 2 3 4 ; do \
        echo $$number ; \
    done

produces:

1
2
3
4

For bigger ranges, use:

target:
    number=1 ; while [[ $$number -le 10 ]] ; do \
        echo $$number ; \
        ((number = number + 1)) ; \
    done

This outputs 1 through 10 inclusive, just change the while terminating condition from 10 to 1000 for a much larger range as indicated in your comment.

Nested loops can be done thus:

target:
    num1=1 ; while [[ $$num1 -le 4 ]] ; do \
        num2=1 ; while [[ $$num2 -le 3 ]] ; do \
            echo $$num1 $$num2 ; \
            ((num2 = num2 + 1)) ; \
        done ; \
        ((num1 = num1 + 1)) ; \
    done

producing:

1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3
4 1
4 2
4 3

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;

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 "$@ success"
${JOBS}: job%: ; ./a.out $*

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