4

In bobbogo's answer to the Stack Overflow question How to write loop in makefile?, it is shown how to write the equivalent of the following pseudocode in a makefile:

For i in 1, ..., n:
  Add the following rule "job_$i: ; ./a.out $i > output_$i"

The great thing about bobbogo's solution, as noted in the answer itself, is that the jobs will be run in parallel if you specify "-j num_threads". Other obvious, and simpler solutions, do not have this property.

My question: How can I do the same thing, but for a nested loop, i.e.:

For i in 1, ..., n:
  For j in 1, ..., m:
    Add the following rule "job_$i_$j: ; ./a.out $i $j > output_$i_$j"

I only anticipate using GNU Make. Thanks in advance!

Community
  • 1
  • 1
N F
  • 213
  • 3
  • 6
  • I think you can do the same. @bobbogo's answer is an abuse of Make and its rule generation. The trick is how to generate all of the rules... – Michael Feb 27 '13 at 02:32

2 Answers2

9

@Michael has got it right. The only tricky bit is deriving $i and $j in the recipes for the jobs. In the original solution I used static pattern rules, where $* in the shell command expands to the string matched by % in the rule. Unfortunately, it's not quite so convenient when you want to match two fields from the target name. Macros help quite a bit. A sketch:

jobs := $(foreach i,1 2 3 4 5,$(foreach j,1 2 3,job-$i-$j))

.PHONY: all
all: ${jobs} ; echo $@ Success

i = $(firstword $(subst -, ,$*))
j = $(lastword $(subst -, ,$*))

.PHONY: ${jobs}
${jobs}: job-%:
    echo i is $i j is $j
bobbogo
  • 14,989
  • 3
  • 48
  • 57
3

After a bit of digging, I've found this:

NUM1 := $(shell seq 1 5)
NUM2 := $(shell seq 1 3)
A := $(addprefix job_,$(NUM1))
B := $(foreach a,$(A),$(addprefix $(a)_,$(NUM2)))

This forms the rules, then you'll just need to add your tasks. Something like this:

all: $(B)
$(B):
    @echo $@
Michael
  • 2,181
  • 14
  • 14