Dummy00001
Dummy00001

Reputation: 17420

GNU make's prerequisite expansion is not lazy

In the GNU make, apparently the prerequisites for the rules are expanded immediately. Consider:

AAA = task1
all: ${AAA} ; @echo finalizing
task1: ; @echo task1
task2: ; @echo task2
AAA += task2

This would print only task1, but not task2, since at the moment of parsing the all rule, the variable ${AAA} held only the task1.

Is there any workaround for that? Or some way to make the make expand the variables lazily, like it does inside the commands?

P.S. In my case the ${AAA} variables is set/changed inside included files. Most are included at the top. Few are included at the bottom - and they are affected. I can't simply move all the include files to the top, since that messes up the default rule. And I can't easily add the extra prereqs to the rules, since there are multiple rules which rely on multiple variables (would lead to lots of copy-paste). The only ideas I have come up with so far were (A) to extract the final value of the variable and call make recursively with its full value (based on the suggestion here) or (B) move the variabe from prerequisites to the command and loop over it calling make recursively for every prerequisite. I'd love to have a more elegant alternative.

Upvotes: 0

Views: 642

Answers (1)

MadScientist
MadScientist

Reputation: 100956

Yes, this is clearly spelled out in the GNU make manual, here for example.

An alternative you can consider is secondary expansion which will let you defer the expansion of the variable until run-time.

However you don't need to do that. You are forgetting that you can add more prerequisites to a rule whenever you want. All you have to do is write your makefiles like this:

AAA = task1
all: ; @echo finalizing
task1: ; @echo task1
task2: ; @echo task2
AAA += task2

all: ${AAA}

As long as you can arrange for a final section to always be placed at the end you can add the prerequisites there and be sure that the variable assignments have all completed. This is also a lot more portable, if you care about that.

Also, you can force the default target to be whatever you want just by mentioning it first, you don't need to give it a recipe. So you could also write this if you wanted:

all:
AAA = task1
task1: ; @echo task1
task2: ; @echo task2
AAA += task2

all: ${AAA} ; @echo finalizing

Upvotes: 2

Related Questions