Proper usage of multiple rules for the same targets

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

Proper usage of multiple rules for the same targets

Tiphaine Turpin
Hello,


I have discovered an issue while using an additional rule with just prerequisites, as suggested in section "Multiple Rules for One Target" of the documentation, when the "main" rule is a pattern rule. The problem it that this changes the behavior in case of missing source files in a non intuitive way.


Here is a minimal example Makefile:


%.t: %.x
        echo using implicit rule

foo.t : additional_prerequisite


If I run 'make foo.t', then

- if foo.x and additional_prerequisite both exist, then the pattern rule is executed as expected, and outputs 'using implicit rule'

- if foo.x is missing then the build succeeds with "Nothing to be done for 'foo.t'."


However, what I would actually want is to get an error, as the one I get if I remove the additional prerequisite rule: "No rule to make target 'foo.t'."


I found the explanation to this in the documentation: if foo.x is missing then the pattern rule is not "enabled" because a pattern rule only matches when "all prerequisites in that rule either exist or can be built" as mentioned in sections "How Patterns Match" and "Using Implicit Rules". The latter additionally says:

'A file “can be made” if it is mentioned explicitly in the makefile as a target or a prerequisite, or if an implicit rule can be recursively found for how to make it.'

In my case, foo.x clearly can't be made, so the pattern rule just does not apply and the additional rule is interpreted as "making" foo.t by doing nothing.


So, a simple solution is to make sure that foo.x exists or can be made, for example with another pattern rule:

%.x:
        $(error no $@)

Could anyone suggest another approach ? Is it better to avoid additional rules for this purpose, adding prerequisites to the pattern rule instead ? Is there a way to define a rule as "dependency-only", so that it can't be used to actually make its target using the implicit "no-op" reciepe ?


Thanks,

Tiphaine Turpin
_______________________________________________
Help-make mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/help-make
Reply | Threaded
Open this post in threaded view
|

Re: Proper usage of multiple rules for the same targets

Sébastien Hinderer
Dear Tiphaine,

At the moment I can't come up with another way to solve the problem you
describe, sorry. However, would you be able to describe in more details
the context and what you are trying to achieve? Perhaps if we understand
what exactly you are trying to do we can come up with another solution?

Best wishes,

Sébastien.

_______________________________________________
Help-make mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/help-make
Reply | Threaded
Open this post in threaded view
|

Re: Proper usage of multiple rules for the same targets

Tiphaine Turpin
In reply to this post by Tiphaine Turpin
Hi,


The reason for the added dependency was that I am using a compiler which can itself be changed (not in the same Makefile, though), and I wanted to make sure that the source files are recompiled when this tool changes. So a more concrete example is:


%.t : %.x
        x2t $<

%.t : x2t

Of course, in this very simple case, the dependency can be added to the first pattern rule, which solves the issue. But in fact there are other dependencies that should trigger the rebuild
when they change (libraries built by some other Makefile) and there are also other occurrences of using the same compiler and associated libraries in the Makefile, in specialized rules, so I
found it more readable to use a separate rule to add the same dependencies to all the relevant targets. Adding the dependency to each rule also requires to slightly adapt some rules, for
example if they were using $^ in their recipe.


So, there is no absolute need to use an additional rule, but I thought it was the most natural way to proceed when I wrote it.


Best Regards,

Tiphaine


________________________________
From:   Sébastien Hinderer
Subject:        Re: Proper usage of multiple rules for the same targets
Date:   Tue, 4 Sep 2018 15:18:37 +0200
________________________________

Dear Tiphaine,

At the moment I can't come up with another way to solve the problem you
describe, sorry. However, would you be able to describe in more details
the context and what you are trying to achieve? Perhaps if we understand
what exactly you are trying to do we can come up with another solution?

Best wishes,

Sébastien.




_______________________________________________
Help-make mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/help-make
Reply | Threaded
Open this post in threaded view
|

Re: Proper usage of multiple rules for the same targets

Sébastien Hinderer
Dear Tiphaine,

Sure, I understand your use case a bit better.

Yesterday I tried to hack something which failed but let me share it
anyway, just in case it inspires you or somebody else.

Imagine for each target that uses additional dependencies you could
write them in a variable like

foo_prereqs = additiional prerequisites specific to foo

and then you would be able to add a pattern-specific variable to your
rule, like

%.t: %.x $(%_prereqs)

It didn't work, unfortunately. I also tried with the eval function and
as far as I could try that was not more successful but perhaps from here
you or somebody else can see how to proceed.

Best wishes,

Sébastien.

_______________________________________________
Help-make mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/help-make
Reply | Threaded
Open this post in threaded view
|

Re: Proper usage of multiple rules for the same targets

Max Gautier
Hi.

To force the behavior you want, I think you could use a static pattern rule :

The syntax being as follow :

<list_of_target>:<pattern_target>:<prerequisite_pattern>

In your case, that would give :

foo.t: %.t: %.x
    touch $@

foo.t: another_file

That achieves what you want, if I'm testing correctly.
(You'll need to have a way to have all of your concerned target in a variable
for readabilite, of course, something like

$(TARGETS): %.t: %.x

)

The reason for that is that static pattern rules are not really pattern rules,
which act as default when no other rules can be found.
The static pattern rule is in fact more a template, which is applied to
all of the targets listed in the <list_of_target>.
Thus, a static pattern rule is equivalent to write the same rule
for all of your listed targets, and each behave as a normal rule. (aka
: will always apply to that target)

(This is explained more clearly in the Static Pattern section in the
Gnu Make manual).


I'm not sure that this solution will not conflict with your other
requirements, though.
Specifically, you mentions using $^ in recipes : I think the
'another_file' dependency would
end up in it ; although I dont think there is any way to avoid it.
Let me know if you managed to work around it.

Regards,

Max

_______________________________________________
Help-make mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/help-make
Reply | Threaded
Open this post in threaded view
|

Re: Proper usage of multiple rules for the same targets

Tiphaine Turpin
Hi,

The static pattern solution looks very nice, thanks. It seems to work fine in the real Makefile. And there is no visible performance impact, as far as I can tell (I'm not sure about how efficiently static pattern rules are implemented). So I think I'll go for this one.

I also tried idea suggested by Sébastien to add prerequisites using a target-specific variable. It can be made to work using secondary expansion:

foo_prereqs = additional prerequisites specific to foo

.SECONDEXPANSION:

%.t: %.x $$($$*_prereqs)
    ...

But I find this more complex.
Thanks for your help !

Tiphaine


________________________________
From: Help-make <help-make-bounces+tiphaine.turpin=[hidden email]> on behalf of Max Gautier <[hidden email]>
Sent: Wednesday, September 5, 2018 11:03 AM
To: [hidden email]
Subject: Re: Proper usage of multiple rules for the same targets

Hi.

To force the behavior you want, I think you could use a static pattern rule :

The syntax being as follow :

<list_of_target>:<pattern_target>:<prerequisite_pattern>

In your case, that would give :

foo.t: %.t: %.x
    touch $@

foo.t: another_file

That achieves what you want, if I'm testing correctly.
(You'll need to have a way to have all of your concerned target in a variable
for readabilite, of course, something like

$(TARGETS): %.t: %.x

)

The reason for that is that static pattern rules are not really pattern rules,
which act as default when no other rules can be found.
The static pattern rule is in fact more a template, which is applied to
all of the targets listed in the <list_of_target>.
Thus, a static pattern rule is equivalent to write the same rule
for all of your listed targets, and each behave as a normal rule. (aka
: will always apply to that target)

(This is explained more clearly in the Static Pattern section in the
Gnu Make manual).


I'm not sure that this solution will not conflict with your other
requirements, though.
Specifically, you mentions using $^ in recipes : I think the
'another_file' dependency would
end up in it ; although I dont think there is any way to avoid it.
Let me know if you managed to work around it.

Regards,

Max

_______________________________________________
Help-make mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/help-make

_______________________________________________
Help-make mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/help-make
Reply | Threaded
Open this post in threaded view
|

Re: Proper usage of multiple rules for the same targets

Sébastien Hinderer
Thanks a lot for your feedback Tiphaine! Thanks for having explored what
I suggested, and great you could find a solution to your problem!

Best wishes,

Sébastien.

_______________________________________________
Help-make mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/help-make
Reply | Threaded
Open this post in threaded view
|

Re: Proper usage of multiple rules for the same targets

Paul Smith-20
In reply to this post by Tiphaine Turpin
On Thu, 2018-09-06 at 08:05 +0000, Tiphaine Turpin wrote:
> The static pattern solution looks very nice, thanks. It seems to work
> fine in the real Makefile. And there is no visible performance
> impact, as far as I can tell (I'm not sure about how efficiently
> static pattern rules are implemented).

Static pattern rules are just another way of writing explicit rules.
As such, they're more efficient than pattern rules (since they are
applied directly when the target is needed, and no pattern matching or
searching is necessary).

_______________________________________________
Help-make mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/help-make
Reply | Threaded
Open this post in threaded view
|

Re: Proper usage of multiple rules for the same targets

Thomas Martitz-2
Am 06.09.18 um 14:56 schrieb Paul Smith:
> On Thu, 2018-09-06 at 08:05 +0000, Tiphaine Turpin wrote:
>> The static pattern solution looks very nice, thanks. It seems to work
>> fine in the real Makefile. And there is no visible performance
>> impact, as far as I can tell (I'm not sure about how efficiently
>> static pattern rules are implemented).
> Static pattern rules are just another way of writing explicit rules.
> As such, they're more efficient than pattern rules (since they are
> applied directly when the target is needed, and no pattern matching or
> searching is necessary).


I found the thread interesting to read, I recently came across static
pattern rules as well and like them. Since you mention efficiency, I
wonder if there's a threshold when pattern rules become more efficient
than tons of explicit rules (imagine explicit rules for every .o in huge
projects). Is there a number of objects when pattern rules are
recommended over explicit rules or are explicit rules better regardless
of the number of them? I would imagine that pattern rules require less
memory and that the lookup for 10000s of explicit rules becomes a
performance issue, too.

This is a theoretical question, I haven't had performance problems with
any type (classic, static pattern or implicit pattern rules).

Best regards.


_______________________________________________
Help-make mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/help-make