Paul Draper
Paul Draper

Reputation: 83383

Target-specific variables in a makefile & prerequisites

I'm seeing unexpected results for target-specfic variables in GNU make.

What I want is to set a target-specific variable that affects dependencies. I can use .SECONDEXPANSION to achieve that.

some-target: DEP := debug-dep

debug: some-target

.SECONDEXPANSION:
some-target: $$(DEP)
    @echo $^

debug-dep:

make debug prints debug-dep.


Now I read that make defines target-specific variables for descendant rules:

When you define a target-specific variable that variable value is also in effect for all prerequisites of this target, and all their prerequisites, etc.

But when I change my makefile to have the variable set on "parent" target:

debug: DEP := debug-dep

debug: some-target

.SECONDEXPANSION:
some-target: $$(DEP)
    @echo $^

debug-dep:

and do make debug I get a blank line.

This seems to contradict the documented behavior of target-specific variables. Is there something that I am missing?


This is sort of similar to make: Using target specific variables in prerequisites, but what I am doing isn't working.

Upvotes: 10

Views: 5024

Answers (2)

Bruce
Bruce

Reputation: 607

All variables are set in the first read-in phase. It is true no matter it is a global variable, or a target-specific variable (or a pattern-specific variable).

There is no such thing that is like the other answer says

target-specific variables are not set until the targets are being run

See the example Makefile below,

GA = ga
GB = $(GA)
GC := $(GA)

a: aTA = $(GA)
a: aTB := $(GA)
a: aTC = $(aTA)
a: b;
GA = ga2

b: bTA = $(aTA)
b: bTB := $(aTA)
b: bTC := $(bTA)
b:;

After the first read-in phase, all variables are set (therefore, aTB is ga, not ga2). They are as follows respectively,

  • GA is literal ga2
  • GB is literal $(GA)
  • GC is literal ga
  • aTA is literal $(GA)
  • aTB is literal ga
  • aTC is literal $(aTA)
  • bTA is literal $(aTA)
  • bTB is literal (empty)
  • bTC is literal (empty)

Although they are all set, they are not visible everywhere, they have scope. E.g.,

  • Global variables' scope is everywhere
  • Target-specific variables' scope is
    • the target's other target-specific variables

    • the recipe of the target

    • the recipes of the target's prerequisites

      This is the only reason that we could see bTA is eventually expanded to ga2 if we use bTA in the target b's recipe.

    • the prerequisite-literal appearing in the target's rule when using .SECONDEXPANSION

      This is why the 1st case in OP's question works.

The following is NOT the scope of a target-specific variable,

  • everywhere in the parent target

  • the target-specific variables of the target's prerequisites

    This is why bTB and bTC are both empty.

  • the (sub) prerequisite-literal appearing in the rule of the target's prerequisites (whether using .SECONDEXPANSION or not)

    This is why the 2nd case in OP's question doesn't work.

Upvotes: 0

Etan Reisner
Etan Reisner

Reputation: 81032

I believe the issue here is that target-specific variables are not set until the targets are being run (if you add @echo '$(DEP)' to your some-target body in that second case you will see that it is set) but that second expansion happens immediately after the initial read-in phase.

I was going to say that I'm actually surprised that this works in the first case at all (and speculate as to why) but then I pulled up the manual for a minute and while reading about .SECONDEXPANSION I found the following:

[T]he true power of this feature only becomes apparent when you discover that secondary expansions always take place within the scope of the automatic variables for that target. This means that you can use variables such as $@, $*, etc. during the second expansion and they will have their expected values, just as in the recipe. All you have to do is defer the expansion by escaping the $. Also, secondary expansion occurs for both explicit and implicit (pattern) rules.

Which explains your behaviour exactly. The expansion only sees variables set in the scope of the target and the prerequisite inheriting only happens at target evaluation time (since it depends on target prerequisites).

Upvotes: 7

Related Questions