Variably determined prerequisites

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Variably determined prerequisites

NightStrike
Hi list!

I am trying to use a pattern rule to pick which variable gets added to
a target's prereq list.  It's not working, so I'm curious if this is
even possible.  Ultimately, what I'd like to do is:

xx%: xx%.o $(extra%)
    echo $@ $^

extra1 += ex1

# The below output is fake, it doesn't actually work
$ make xx1
echo xx1 xx1.o ex1
xx1 xx1.o ex1


But instead, make looks for a variable with a literal percent sign in
it, $(extra%):

extra% = zzz

xx%: xx%.o $(extra%)
        echo $@ $^

$ make xx1
make: *** No rule to make target `xx1'.  Stop.


Ok, that's a confusing error message... there's no rule to make zzz,
not xx1, maybe a bug in make?  Fine... adding ".PHONY: zzz":

$ make xx1
echo xx1 xx1.o zzz
xx1 xx1.o zzz


Ok, so % signs don't work the way I want in a pattern rule.  Let's be
more explicit:

extra1 = ex1
extra2 =

xx1: $(extra1)
xx2: $(extra2)

xx%: xx%.o
    echo $@ $^

extra2 += ex2

$ make xx1
make: *** No rule to make target `ex1', needed by `xx1'.  Stop.
$ make xx2
echo xx2 xx2.o
xx2 xx2.o

So now xx1 is doing the right thing!  Great!  But only if extra1 is
defined prior to writing the rule, despite them being = instead of :=.
With extra2, the way I want it to be such that other files included
later can add on to it, the rule has already been scanned by make and
so the later appending to it doesn't help.

What am I missing?

Oh, I guess I should also say:
$ make --version
GNU Make 3.81

Although, a quick test with 4.0 shows the same thing not working.


So...  is there a way to do this?

Reply | Threaded
Open this post in threaded view
|

Re: Variably determined prerequisites

Paul Smith-20
On Wed, 2020-04-01 at 16:03 -0400, NightStrike wrote:
> I am trying to use a pattern rule to pick which variable gets added
> to a target's prereq list.

All of the confusion here is due to not quite grasping make's rules for
expanding variables.

Make operates in two stages: in the first stage all makefiles are
parsed and an internal graph of dependency relationships are created.
This stage is described here:
https://www.gnu.org/software/make/manual/html_node/Parsing-Makefiles.html

In the second stage, make walks that internal graph and actually runs
recipes to try to bring targets up to date.

All variables that are needed to create the graph are expanded during
the first stage, when make is parsing makefiles.  This expansion
happens immediately, as the line is read in from the file.

This means all variables that appear in either target or prerequisite
ists are expanded immediately in the first stage.

Variables that are not needed until the second stage are not expanded
until make tries to actually run a recipe.

This is discussed in the manual, here:
https://www.gnu.org/software/make/manual/html_node/Reading-Makefiles.html

This explains your behavior.  When your variables appear in a target or
recipe they are expanded right then, as the line is parsed.  It doesn't
matter whether they are defined with "=" or ":=".  For pattern rules,
since we're not actually trying to build any targets (that happens in
the second phase), there is no way to expand the pattern value so it
just expands the literal string "extra%" as a variable.


You should be able to use secondary expansion (see the manual) to do
what you want:

  .SECONDEXPANSION:
  xx%: xx%.o $$(extra$$*)
          echo $@ $^

I didn't test this.


Reply | Threaded
Open this post in threaded view
|

Re: Variably determined prerequisites

NightStrike
On Wed, Apr 1, 2020 at 4:23 PM Paul Smith <[hidden email]> wrote:

>
> On Wed, 2020-04-01 at 16:03 -0400, NightStrike wrote:
> > I am trying to use a pattern rule to pick which variable gets added
> > to a target's prereq list.
>
> All of the confusion here is due to not quite grasping make's rules for
> expanding variables.
>
> Make operates in two stages: in the first stage all makefiles are
> parsed and an internal graph of dependency relationships are created.
> This stage is described here:
> https://www.gnu.org/software/make/manual/html_node/Parsing-Makefiles.html
>
> In the second stage, make walks that internal graph and actually runs
> recipes to try to bring targets up to date.
>
> All variables that are needed to create the graph are expanded during
> the first stage, when make is parsing makefiles.  This expansion
> happens immediately, as the line is read in from the file.
>
> This means all variables that appear in either target or prerequisite
> ists are expanded immediately in the first stage.
>
> Variables that are not needed until the second stage are not expanded
> until make tries to actually run a recipe.
>
> This is discussed in the manual, here:
> https://www.gnu.org/software/make/manual/html_node/Reading-Makefiles.html
>
> This explains your behavior.  When your variables appear in a target or
> recipe they are expanded right then, as the line is parsed.  It doesn't
> matter whether they are defined with "=" or ":=".  For pattern rules,
> since we're not actually trying to build any targets (that happens in
> the second phase), there is no way to expand the pattern value so it
> just expands the literal string "extra%" as a variable.
>
>
> You should be able to use secondary expansion (see the manual) to do
> what you want:
>
>   .SECONDEXPANSION:
>   xx%: xx%.o $$(extra$$*)
>           echo $@ $^
>
> I didn't test this.

Thank you for such a swift, detailed, and correct response!  Certainly
this is what I want, it works perfectly, and the example in the manual
is even exactly what I want to do:
https://www.gnu.org/software/make/manual/make.html#Secondary-Expansion

Thank you for helping to explain this without making me feel stupid :)