Command producing several targets at once

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

Command producing several targets at once

Sébastien Hinderer
Dear all,

OCaml's parser generator, ocamlyacc, produces two files simultaneously.
For example, the command

ocamlyacc parsermly

will produce both parser.ml (the code of the parser) and parser.mli (the
interface of the parsing module, descrbing which symbols it exports).

I am wondering what's the best way to let make know about this.

From what I understand, a rule like

parser.mli parser.ml: parser.mly
           ocaplyacc $<

does nos say exactly this but is rather an abbreviation for

parser.mli: parser.mly
            ocamlyacc $<

parser.ml: parser.mly
            ocamlyacc $<

which is not what I'd like to express

I have been told that one way to make things work could be the two
following rules:

parser.mli parser.ml: parser.mly
           ocamlyacc $<

parser.mli: parser.ml

Is this the commonly used way to achieve the expected result?

I find it a bit tricky because "parser.mli: parser.ml" looks like a hack
to me, there is no real dependency.

Even if that is what is commonly used, I am wondering how this would
generalize to a command that would produce n files where n>2.

Many thanks for any comment,

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: Command producing several targets at once

Paul Smith-20
On Wed, 2017-07-26 at 09:24 +0200, Sébastien Hinderer wrote:

> parser.mli parser.ml: parser.mly
>            ocaplyacc $<
>
> does nos say exactly this but is rather an abbreviation for
>
> parser.mli: parser.mly
>             ocamlyacc $<
>
> parser.ml: parser.mly
>             ocamlyacc $<

Correct.  However this:

  %.mli %.ml : %.mly
          ocamlyacc $<

will do just what you want.

Pattern rules with multiple targets tell make that a single invocation
of the recipe will build all the targets.

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

Re: Command producing several targets at once

Thomas Martitz-2
In reply to this post by Sébastien Hinderer
Am 26.07.2017 um 09:24 schrieb Sébastien Hinderer:

> Dear all,
>
> OCaml's parser generator, ocamlyacc, produces two files simultaneously.
> For example, the command
>
> ocamlyacc parsermly
>
> will produce both parser.ml (the code of the parser) and parser.mli (the
> interface of the parsing module, descrbing which symbols it exports).
>
> I am wondering what's the best way to let make know about this.
>
>  From what I understand, a rule like
>
> parser.mli parser.ml: parser.mly
>             ocaplyacc $<
>
> does nos say exactly this but is rather an abbreviation for
>
> parser.mli: parser.mly
>              ocamlyacc $<
>
> parser.ml: parser.mly
>              ocamlyacc $<
>
> which is not what I'd like to express
>
> I have been told that one way to make things work could be the two
> following rules:
>
> parser.mli parser.ml: parser.mly
>             ocamlyacc $<
>
> parser.mli: parser.ml
>
> Is this the commonly used way to achieve the expected result?
>
> I find it a bit tricky because "parser.mli: parser.ml" looks like a hack
> to me, there is no real dependency.
>
> Even if that is what is commonly used, I am wondering how this would
> generalize to a command that would produce n files where n>2.
>
> Many thanks for any comment,
>
> Sébastien.


Use pattern rules for this. As a special behavior they run the command
only once if multiple targets match the pattern:

%.mli %.ml: %.mly
            ocaplyacc $<


This behavior is different from normal, multi-target rules, and is
implement for this very case. See
https://www.gnu.org/software/make/manual/make.html#Pattern-Examples

Best gerads.


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

Re: Command producing several targets at once

Sébastien Hinderer
In reply to this post by Paul Smith-20
Dear Paul,

Many thanks for your prompt and helpful response!

Paul Smith (2017/07/26 08:57 -0400):

> On Wed, 2017-07-26 at 09:24 +0200, Sébastien Hinderer wrote:
> > parser.mli parser.ml: parser.mly
> >            ocaplyacc $<
> >
> > does nos say exactly this but is rather an abbreviation for
> >
> > parser.mli: parser.mly
> >             ocamlyacc $<
> >
> > parser.ml: parser.mly
> >             ocamlyacc $<
>
> Correct.  However this:
>
>   %.mli %.ml : %.mly
>           ocamlyacc $<
>
> will do just what you want.
>
> Pattern rules with multiple targets tell make that a single invocation
> of the recipe will build all the targets.

Oh great! I was not aware of this.

So am I correctin assuming that something like

parsers := foo.mly bar.mly baz.mly

$(parsers): %.ml %.mli
            ocamlyacc $<

would work the expected way?

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: Command producing several targets at once

Sébastien Hinderer
Sébastien Hinderer (2017/07/26 15:18 +0200):

> Oh great! I was not aware of this.
>
> So am I correctin assuming that something like
>
> parsers := foo.mly bar.mly baz.mly
>
> $(parsers): %.ml %.mli
>             ocamlyacc $<
>
> would work the expected way?

Sorry, I meant:

parsers := foo.mly bar.mly baz.mly
 
$(parsers): %.ml %.mli: %.mly
            ocamlyacc $<

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: Command producing several targets at once

Sébastien Hinderer
In reply to this post by Thomas Martitz-2
Thanks a lot to you too, Thomas!

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: Command producing several targets at once

Paul Smith-20
In reply to this post by Sébastien Hinderer
On Wed, 2017-07-26 at 15:21 +0200, Sébastien Hinderer wrote:
> Sorry, I meant:
>
> parsers := foo.mly bar.mly baz.mly
>  
> $(parsers): %.ml %.mli: %.mly%.ml %.mli: %.mly
>             ocamlyacc $<

No.  That's a static pattern rule.  You can't get this multiple targets
built with a single recipe feature with a static pattern rule, only with
normal pattern rules.

Just write it as I put in my email:

  %.ml %.mli: %.mly
          ocamlyacc $<

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

Re: Command producing several targets at once

Sébastien Hinderer
OK thanks a lot Paul. Things are much clearer now.
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: Command producing several targets at once

Britton Kerin
In reply to this post by Paul Smith-20
On Wed, Jul 26, 2017 at 5:31 AM, Paul Smith <[hidden email]> wrote:

> On Wed, 2017-07-26 at 15:21 +0200, Sébastien Hinderer wrote:
>> Sorry, I meant:
>>
>> parsers := foo.mly bar.mly baz.mly
>>
>> $(parsers): %.ml %.mli: %.mly%.ml %.mli: %.mly
>>             ocamlyacc $<
>
> No.  That's a static pattern rule.  You can't get this multiple targets
> built with a single recipe feature with a static pattern rule, only with
> normal pattern rules.
>
> Just write it as I put in my email:
>
>   %.ml %.mli: %.mly
>           ocamlyacc $<

Another option if you don't like non-static pattern rules or the
special-case stuff involved, is to use a stamp file:

yaccouts.stamp: parser.mly
        ocamlyacc $<

Since .ml and .mli files are always produced together by the same
program, they don't need individual nodes in your dependency graph so
you arrange yaccouts.stamp to represent them (and depend on the stamp
file in turn where needed).  This approach works with static pattern
rules and is useful in other situations as well, e.g. when you want to
represent completeness of a build in a subdir or other place, to
represent verification of expensive-to-verify build requirements, etc.

Britton

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

Re: Command producing several targets at once

Paul Smith-20
On Wed, 2017-07-26 at 09:17 -0800, Britton Kerin wrote:
> Another option if you don't like non-static pattern rules or the
> special-case stuff involved, is to use a stamp file:
>
> yaccouts.stamp: parser.mly
>         ocamlyacc $<

I expect you want to add a "touch $@" to this recipe.

And, this will only work if you have only on .mly file you need to
build; if you have more than one you'll need to ensure the stamp file
name is based on the .mly file name rather than "yaccouts.stamp".

> Since .ml and .mli files are always produced together by the
> sameprogram, they don't need individual nodes in your dependency
> graph so you arrange yaccouts.stamp to represent them (and depend on
> the stampfile in turn where needed).

This works if you can ensure that all other references to parser.ml and
parser.mli in the prerequisites lists in your makefile can be replaced
with a reference to the .stamp file.

But, it's not so simple if you have auto-generated prerequisites etc.
where it's harder to control this.

Also, this method doesn't take into account someone deleting either or
both of the .ml or .mli files by hand but not touching the .stamp file.

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

Re: Command producing several targets at once

Britton Kerin
On Wed, Jul 26, 2017 at 9:31 AM, Paul Smith <[hidden email]> wrote:
> On Wed, 2017-07-26 at 09:17 -0800, Britton Kerin wrote:
>> Another option if you don't like non-static pattern rules or the
>> special-case stuff involved, is to use a stamp file:
>>
>> yaccouts.stamp: parser.mly
>>         ocamlyacc $<
>
> I expect you want to add a "touch $@" to this recipe.

Yes, thx.  My bad should always test before post.

> And, this will only work if you have only on .mly file you need to
> build; if you have more than one you'll need to ensure the stamp file
> name is based on the .mly file name rather than "yaccouts.stamp".

Ok ok here's a more real-life version:

OCAMLYACC_STAMPS = $(patsubst %.mly,%.ocamlyacc.stamp,$(wildcard *.mly))

$(OCAMLYACC_STAMPS): %.ocamlyacc.stamp: %.mly
        ocamlyacc $<
        touch $@

>> Since .ml and .mli files are always produced together by the
>> sameprogram, they don't need individual nodes in your dependency
>> graph so you arrange yaccouts.stamp to represent them (and depend on
>> the stampfile in turn where needed).
>
> This works if you can ensure that all other references to parser.ml and
> parser.mli in the prerequisites lists in your makefile can be replaced
> with a reference to the .stamp file.
>
> But, it's not so simple if you have auto-generated prerequisites etc.
> where it's harder to control this.
>
> Also, this method doesn't take into account someone deleting either or
> both of the .ml or .mli files by hand but not touching the .stamp file.

True.  It's still worth it to avoid non-static pattern rules though IMO.

Britton

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

Re: Command producing several targets at once

Paul Smith-20
On Wed, 2017-07-26 at 12:31 -0800, Britton Kerin wrote:
> It's still worth it to avoid non-static pattern rules though IMO.

I use normal pattern rules all the time in all my makefiles.  Love 'em,
and I see no point in trying to avoid them.

YMMV of course, just providing a different viewpoint.

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

Re: Command producing several targets at once

Britton Kerin
On Wed, Jul 26, 2017 at 12:44 PM, Paul Smith <[hidden email]> wrote:
> On Wed, 2017-07-26 at 12:31 -0800, Britton Kerin wrote:
>> It's still worth it to avoid non-static pattern rules though IMO.
>
> I use normal pattern rules all the time in all my makefiles.  Love 'em,
> and I see no point in trying to avoid them.

The points in avoiding are: they don't have the same tendency to fire
in unintended circumstances (e.g. on generated code), and when they
do (because you compute the target set wrong), the error messages
are much less misleading.

> YMMV of course, just providing a different viewpoint.

But you're the god of make and not easily confused :)  Unfortunately I
don't have the examples on hand but after confusing myself badly
with misfiring implicit rules a couple of times I decided it was best to
just avoid them in favor of more exact static pattern rules.

Britton

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

Re: Command producing several targets at once

Sébastien Hinderer
Dear Paul and Britton,

I'd really like to thank both of you for your time and for sharing your
experience and expertise, I found it really interesting to follow your
exchange.

I'll probably follow Paul's advice because on the project I work on it
will probably work just fine. However, just for sake of completeness,
I'd like to mention that, in a project I was involved with in the past,
it happened that the project was using two parser generators, for
historical reasons (ocamlyacc and menhir). Both used .mly files as inut
and both produced both a .ml and a .mli file. In my understanding, this
is one example were Britton's approach would work better but please do
not hesitate to correct me if I am wrong.

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: Command producing several targets at once

Stefan Monnier
In reply to this post by Britton Kerin
> Another option if you don't like non-static pattern rules or the
> special-case stuff involved, is to use a stamp file:

> yaccouts.stamp: parser.mly
>         ocamlyacc $<

IIUC a degenerate form of this is to decide that "parse.ml" plays the
role of the stamp file, so you do

    parser.ml: parser.mly
    ocamlyacc $<
   
    parser.mli: parser.ml
    @:


-- Stefan


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