Lazer
Lazer

Reputation: 94840

How to generate targets in a Makefile by iterating over a list?

CODE:

LIST=0 1 2 3 4 5
PREFIX=rambo

# some looping logic to interate over LIST

EXPECTED RESULT:

rambo0:
    sh rambo_script0.sh

rambo1:
    sh rambo_script1.sh

Since my LIST has 6 elements, 6 targets should be generated. In future, if I want to add more targets, I want to be able to just modify my LIST and not touch any other part of the code.

How should the looping logic be written?

Upvotes: 21

Views: 24698

Answers (3)

Mizux
Mizux

Reputation: 9291

Just my 2 cents to @Idelic answer, if you need to use some Make $cmd you must escape them using $$ e.g.

LIST = 0 1 2 3 4 5
define make-rambo-target
$(info create target: $(addprefix rambo_script, $(addsuffix .sh, $1)).)
rambo$1: $$(addprefix rambo_script, $$(addsuffix .sh, $1))
    sh $$<
endef

all: $(addprefix rambo, $(LIST))

$(foreach element, $(LIST), $(eval $(call make-rambo-target,$(element))))

output:

$ make
create target: rambo_script0.sh.
create target: rambo_script1.sh.
create target: rambo_script2.sh.
create target: rambo_script3.sh.
create target: rambo_script4.sh.
create target: rambo_script5.sh.
sh rambo_script0.sh
sh rambo_script1.sh
sh rambo_script2.sh
sh rambo_script3.sh
sh rambo_script4.sh
sh rambo_script5.sh

note: here rules "are seen" by Make as

rambo0: $(addprefix rambo_script, $(addsuffix .sh, 0))
    sh $<

But here we could have written without escaping i.e.

rambo$1: $(addprefix rambo_script, $(addsuffix .sh, $1))
    sh $$<

So rule "are seen" as:

rambo0 : rambo_script0.sh
    sh $<

when Make parse it.

Upvotes: 1

Idelic
Idelic

Reputation: 15582

If you're using GNU make, you can generate arbitrary targets at run-time:

LIST = 0 1 2 3 4 5
define make-rambo-target
  rambo$1:
         sh rambo_script$1.sh
  all:: rambo$1
endef

$(foreach element,$(LIST),$(eval $(call make-rambo-target,$(element))))

Upvotes: 33

Michael J. Barber
Michael J. Barber

Reputation: 25042

Use text-transforming functions. With patsubst you can make quite general transformations. For constructing filenames, addsuffix and addprefix are both convenient.

For the rules, use pattern rules.

The overall result might look something like this:

LIST = 0 1 3 4 5
targets = $(addprefix rambo, $(LIST))

all: $(targets)

$(targets): rambo%: rambo%.sh
    sh $<

Upvotes: 24

Related Questions