Merging rules

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

Merging rules

Sébastien Hinderer
Dear all,

Assume the following fragment of a Makefile

%.$(O): %.c
        $(CC) ...

%.pic.$(O): %.c
        $(CC) ...

%.p.$(O): %.c
        $(CC) ...

%.i.$(O): %.c
        $(CC) ...

%.d.$(O): %.c
        $(CC) ...

That is, these rules build different types of object files from C
sources.

Until recently the commands in these rules were different but now,
thanks to target-specific variables, I managed to make all the commands
in these rule look exactly the same.

I am now wondering: is there a way to "merge" all these rules in just
one generic rule?

I assume if I write something like

%.$(O) %.pic.$(O) %.p.$(O) %.i.$(O) %.d.$(O): %.c
        $(CC) ...

Then make will think that with only one invocation all the different
types of files will be produced, which is of course wrong.

Is there another way to achieve this?

Many thanks in advance!

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: Merging rules

Basin Ilya
Hi Sébastien.


> Then make will think that with only one invocation all the different
> types of files will be produced, which is of course wrong.

I think you've got a wrong impression. Make will run the rule as many times as needed to make all the targets.


13.06.2018 20:38, Sébastien Hinderer пишет:

> Dear all,
>
> Assume the following fragment of a Makefile
>
> %.$(O): %.c
>         $(CC) ...
>
> %.pic.$(O): %.c
>         $(CC) ...
>
> %.p.$(O): %.c
>         $(CC) ...
>
> %.i.$(O): %.c
>         $(CC) ...
>
> %.d.$(O): %.c
>         $(CC) ...
>
> That is, these rules build different types of object files from C
> sources.
>
> Until recently the commands in these rules were different but now,
> thanks to target-specific variables, I managed to make all the commands
> in these rule look exactly the same.
>
> I am now wondering: is there a way to "merge" all these rules in just
> one generic rule?
>
> I assume if I write something like
>
> %.$(O) %.pic.$(O) %.p.$(O) %.i.$(O) %.d.$(O): %.c
>         $(CC) ...
>
> Then make will think that with only one invocation all the different
> types of files will be produced, which is of course wrong.
>
> Is there another way to achieve this?
>
> Many thanks in advance!
>
> Sébastien.
>
>
> _______________________________________________
> 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: Merging rules

Sébastien Hinderer
Hi, Basin!

Basin Ilya (2018/06/13 21:15 +0300):
> Hi Sébastien.
>
>
> > Then make will think that with only one invocation all the different
> > types of files will be produced, which is of course wrong.
>
> I think you've got a wrong impression. Make will run the rule as many
> times as needed to make all the targets.

Strange: I have a Makefile with a rule to generate a parser from a
grammar and that parser consists in two files, and I do believe the
command is run only once, which is fine because it produces both files
at the same time.

Or perhaps is that the difference between pattern rules and static
pattern rules?

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: Merging rules

Basin Ilya
> I do believe the
> command is run only once, which is fine because it produces both files

I think that `make all` depends on just one output of that rule. If you really want to such command only once, then don't mention additional outputs in the makefile or choose a primary output and make the others depend on it (but you'll have to ensure that the additional outputs are newer then the primary output, using `touch`)


On 13.06.2018 21:32, Sébastien Hinderer wrote:

> Hi, Basin!
>
> Basin Ilya (2018/06/13 21:15 +0300):
>> Hi Sébastien.
>>
>>
>>> Then make will think that with only one invocation all the different
>>> types of files will be produced, which is of course wrong.
>>
>> I think you've got a wrong impression. Make will run the rule as many
>> times as needed to make all the targets.
>
> Strange: I have a Makefile with a rule to generate a parser from a
> grammar and that parser consists in two files, and I do believe the
> command is run only once, which is fine because it produces both files
> at the same time.
>
> Or perhaps is that the difference between pattern rules and static
> pattern rules?
>
> Sébastien.
>
> _______________________________________________
> 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: Merging rules

Sébastien Hinderer
OK here is my real example, I think it's just simpler to show the
fragments as they are -- sorry I dind't do it earlier.

After a bunch of refactorings, I reached a point where the frament in
question looks like this:

%.$(O): %.c
        $(CC) -c $(OC_CFLAGS) $(OC_CPPFLAGS) $(OUTPUTOBJ)$@ $<

%.$(DBGO): OC_CPPFLAGS += $(OC_DEBUG_CPPFLAGS)
%.d.$(O): %.c
        $(CC) -c $(OC_CFLAGS) $(OC_CPPFLAGS) $(OUTPUTOBJ)$@ $<

%.i.$(O): OC_CPPFLAGS += $(OC_INSTR_CPPFLAGS)
%.i.$(O): %.c
        $(CC) -c $(OC_CFLAGS) $(OC_CPPFLAGS) $(OUTPUTOBJ)$@ $<

%.pic.$(O): OC_CFLAGS += $(SHAREDLIB_CFLAGS)
%.pic.$(O): %.c
        $(CC) -c $(OC_CFLAGS) $(OC_CPPFLAGS) $(OUTPUTOBJ)$@ $<

As you can see, the recipe is the same for all these rules.

Now I am wondering whether there would be a way to rewrite this fragment
without having to repeat the command.

I tried:

%.$(O) %.d.$(O) %.i.$(O) %.pic.$(O): %.c
        $(CC) -c $(OC_CFLAGS) $(OC_CPPFLAGS) $(OUTPUTOBJ)$@ $<

%.d.$(O): OC_CPPFLAGS += $(OC_DEBUG_CPPFLAGS)

%.i.$(O): OC_CPPFLAGS += $(OC_INSTR_CPPFLAGS)

%.pic.$(O): OC_CFLAGS += $(SHAREDLIB_CFLAGS)

But that does not work: when make tries to build the target that
requires the .d.o files, it fails to do so because the expected files
have not been built.

My interpretation of why this happens is that the rule has been invoked
once, to build the regular .o files, and then make believes that this
single invocation has built all the targets, which is actually not the
case.

Any help warmly appreciated, sorry if the question is naïve!

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: Merging rules

Paul Smith-20
On Thu, 2018-06-14 at 13:51 +0200, Sébastien Hinderer wrote:
> Now I am wondering whether there would be a way to rewrite this
> fragment without having to repeat the command.

No, there is no way to do that.

Well, you could define a variable containing the rule and use an
eval/call pair inside a foreach loop but I'm not convinced that would
be more understandable or readable than what you have.

> My interpretation of why this happens is that the rule has been
> invoked once, to build the regular .o files, and then make believes
> that this single invocation has built all the targets, which is
> actually not the case.

Your interpretation is correct.  Using multiple pattern targets tells
make that one invocation of the recipe will build _all_ the targets.
Once make believes it's run a recipe to build a target, it will never
try again even if the resulting target wasn't actually built, or wasn't
updated.

This is important behavior and is used in all sorts of makefiles, to
avoid rebuilding things that are actually up to date.

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

Re: Merging rules

Sébastien Hinderer
Dear Paul,

Many thanks for your clear, prompt and helpful response!

Paul Smith (2018/06/14 08:19 -0400):
> On Thu, 2018-06-14 at 13:51 +0200, Sébastien Hinderer wrote:
> > Now I am wondering whether there would be a way to rewrite this
> > fragment without having to repeat the command.
>
> No, there is no way to do that.
>
> Well, you could define a variable containing the rule and use an
> eval/call pair inside a foreach loop but I'm not convinced that would
> be more understandable or readable than what you have.

Ah, it's too bad. Because, what I forgot to mention is that the intent
behind all this is to make the recipe(s) a bit more complex by adding
other variables, namely CFLAGS and CPPFLAGS, to let the user (the
person who compiles the package) use them when desired.

I that light, and to guarantee that all the rules are consistent, do you
think it would become worth defining a marco that takes as only argument
the pattern of the target?

> > My interpretation of why this happens is that the rule has been
> > invoked once, to build the regular .o files, and then make believes
> > that this single invocation has built all the targets, which is
> > actually not the case.
>
> Your interpretation is correct.  Using multiple pattern targets tells
> make that one invocation of the recipe will build _all_ the targets.
> Once make believes it's run a recipe to build a target, it will never
> try again even if the resulting target wasn't actually built, or wasn't
> updated.

OK great, so at least I kind of start to understand a bit of soemthing.
Thanks a lot for having confirmed.

Just to make sure: do you confirm that it wouldn't be possible to
achieve the desired result through suffix rules?

> This is important behavior and is used in all sorts of makefiles, to
> avoid rebuilding things that are actually up to date.

Sure, got it. I think I am even taking advantage of this in other
places.

Thanks again, Paul!

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: Merging rules

Sébastien Hinderer
Sébastien Hinderer (2018/06/14 14:27 +0200):
> Ah, it's too bad. Because, what I forgot to mention is that the intent
> behind all this is to make the recipe(s) a bit more complex by adding
> other variables, namely CFLAGS and CPPFLAGS, to let the user (the
> person who compiles the package) use them when desired.
>
> I that light, and to guarantee that all the rules are consistent, do you
> think it would become worth defining a marco that takes as only argument
> the pattern of the target?

I meant "In that lignt".

Or perhaps, rather than putting the whole rule in a macro, I could
define as a macro just the recipe? Would that be better style?

Thanks again,

Sébastien.

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