Edmondo
Edmondo

Reputation: 20080

Invoking a Make target in a loop with an argument

I am designing a simple makefile that defines one target which takes an argument, and I would like to define a second target that invokes the first target in a loop, once per every variable defined in an array variable at the top of the Makefile.

my_loop_var = var1 var2

my_thing:
    echo $MY_VAR
all:
   invoke my_thing once for each value of my_loop_var

What is the right way to solve this?

Upvotes: 1

Views: 812

Answers (1)

Renaud Pacalet
Renaud Pacalet

Reputation: 28965

Note: $MY_VAR will probably expand as Y_VAR because make will try to expand variable M, which is probably undefined, and concatenate Y_VAR to the result. Use $(VARNAME) to expand make variable VARNAME. It is only with single-character variable names that you can expand with $X.

There is not really a "right way". There are many ways. The most straightforward from your specifications (but the less natural) would be something like:

my_loop_var := var1 var2

my_thing:
    echo "$(MY_VAR)"

.PHONY: all my_thing

all:
    for v in $(my_loop_var); do $(MAKE) my_thing MY_VAR="$$v"; done

The recipe of all is a shell loop that re-invokes make with the my_thing goal and with each value in my_loop_var passed as the value of make variable MY_VAR.

Note the $$v to escape the first expansion that make always performs before passing the recipe to the shell. With just $v make would expand the recipe as ... MY_VAR="" ... and the result would not be what you expect.

Note also the use of the MAKE make variable instead of directly calling make (have a look at the documentation if you want to understand why it is better like this).

all and my_thing are declared as phony because they are not real file names that their recipes create, and make needs to know this kind of things.

But a much more make-ish way would be something like:

my_loop_var      := var1 var2
my_thing_targets := $(addprefix my_thing_,$(my_loop_var))

.PHONY: all $(my_thing_targets)

all: $(my_thing_targets)

$(my_thing_targets): my_thing_%:
    echo "$*"

Here we define as many my_thing_something targets as there are something values in my_loop_var. And explain make how to build such targets with a static pattern rule. In the recipe of a pattern rule the $* automatic variable expands as the part that matched the % pattern. So, this static pattern rule says that if we need to build my_thing_something, the recipe is echo "something".

We declare all these my_thing_something targets as prerequisites of all such that if you type make or make all, make will build all the my_thing_something targets.

This second solution is better for at least two reasons. First, make is invoked only once, which is better, at least for performance. Second, make can parallelize the build of the my_thing_something if you use the -j N option (to allow make to run up to N jobs in parallel). This also is better for performance.

But it is also a matter of style. Very frequently if you use shell loops in your recipes, especially to invoke make again, it is the sign that you did not really understand what make is intended for and how it works. The make language is not a scripting language (even if the recipes are written in shell language, which is a scripting language); make is designed to "loop" over all targets to build, without the need for explicit loops.

Upvotes: 2

Related Questions