Idea: Enable .ONESHELL to be per-target

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

Idea: Enable .ONESHELL to be per-target

David A. Wheeler
Another idea: Enable .ONESHELL to be per-target.

Problem: According to the docs .ONESHELL is global in effect,
so using it in an existing makefile requires a lot of rework.
In many cases .ONESHELL is primarily only useful only
for specific rules, and there's no need to rewrite the rest.

The current rules are also oddly inconsistent with many
of the other special targets;
most other special targets allow a list of dependencies where
it makes sense to support them.


Solution:
Let's expand .ONESHELL so that
if specific prerequisites are identified for it,
it applies only to those prerequisites.

If no prerequisites are listed, it would work just like it does now.
As a result this change is completely backwards compatible.

Note that this works especially well with target-specific variables,
so you can even set SHELL and .SHELLFLAGS for a specific target:

~~~~
.ONESHELL: foo
foo: SHELL = /usr/bin/perl
foo: .SHELLFLAGS = -e
foo: ...
<TAB>commands that will run as a single shell.
~~~~

Note the ".SHELLFLAGS =", which is odd syntactically but should be allowed.

This also works nicely with "Idea: Allow certain special targets as dependencies":

~~~~
bar: .ONESHELL ...
<TAB>...commands that will run as a single shell
~~~~

--- David A. Wheeler

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

Re: Idea: Enable .ONESHELL to be per-target

Britton Kerin
On Mon, Jun 10, 2019 at 4:56 AM David A. Wheeler <[hidden email]> wrote:
>
> Another idea: Enable .ONESHELL to be per-target.
>
> Problem: According to the docs .ONESHELL is global in effect,
> so using it in an existing makefile requires a lot of rework.

Strongly seconded, I would definitely use this.  I've been
attracted to it many times but never dared try globally.
Would make use of shell vars much less ugly and full of \
lines etc.

I do think some thought on the syntax might be in order still
though.  With some of these it's not obvious which default
sense would be more useful, e.g.

     # GLobal setting
     .ONESHELL:

     tricky_target: .NOTONESHELL:

might be what is really wanted in many cases.

I guess these would taint prereqs, like local vars do.

> In many cases .ONESHELL is primarily only useful only
> for specific rules, and there's no need to rewrite the rest.
>
> The current rules are also oddly inconsistent with many
> of the other special targets;
> most other special targets allow a list of dependencies where
> it makes sense to support them.
>
>
> Solution:
> Let's expand .ONESHELL so that
> if specific prerequisites are identified for it,
> it applies only to those prerequisites.
>
> If no prerequisites are listed, it would work just like it does now.
> As a result this change is completely backwards compatible.
>
> Note that this works especially well with target-specific variables,
> so you can even set SHELL and .SHELLFLAGS for a specific target:
>
> ~~~~
> .ONESHELL: foo
> foo: SHELL = /usr/bin/perl
> foo: .SHELLFLAGS = -e
> foo: ...
> <TAB>commands that will run as a single shell.
> ~~~~
>
> Note the ".SHELLFLAGS =", which is odd syntactically but should be allowed.
>
> This also works nicely with "Idea: Allow certain special targets as dependencies":

Yes this would be nice.  And it's consistent with Make philosophy of
trying to be
very terse.  btw I assume these special prereqs would not be visible to $< etc

Britton

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

Re: Idea: Enable .ONESHELL to be per-target

David A. Wheeler
> On Mon, Jun 10, 2019 at 4:56 AM David A. Wheeler <[hidden email]> wrote:
> > Another idea: Enable .ONESHELL to be per-target.

On Mon, 10 Jun 2019 11:47:19 -0800, Britton Kerin <[hidden email]> wrote:
> Strongly seconded, I would definitely use this.  I've been
> attracted to it many times but never dared try globally.
> Would make use of shell vars much less ugly and full of \
> lines etc.

Excellent!

> I do think some thought on the syntax might be in order still
> though.  With some of these it's not obvious which default
> sense would be more useful, e.g.
>
>      # GLobal setting
>      .ONESHELL:
>
>      tricky_target: .NOTONESHELL:
>
> might be what is really wanted in many cases.

You can probably make a case for either one, but
.ONESHELL already exists, so let's just expand what's already there.
My theory is that in existing Makefiles
you would only enable .ONESHELL in specific cases,
so having ".ONESHELL" be the one you ask for in special cases
seems more sensible as the primary term.
Also, I think primary terms with a built-in negation are best
avoided. They force people work through double negatives
in many contexts.

If you want to disable a global special target
in a specific case, then I think there should be a general-purpose syntax
for this kind of thing.  Something like this:

~~~~
tricky_target: ! .ONESHELL
~~~~

(Instead of "!" it could be something else like ".NOT".)

I don't know if this negation case is worth supporting, but if it is,
having a reusable syntactic solution would be much better
than a weird special case.  It means there's less to remember
(the same approach works every time) and it's easy to generalize.


> I guess these would taint prereqs, like local vars do.

I don't think so; that wasn't my intention.

Currently .ONESHELL is a special target, not a (target-specific) variable,
and I intended to keep it that way.
It's my understanding that normally special targets
don't propagate when building their prerequisites.
E.g., a .PHONY target can depend on a non-.PHONY target.

Target-specific variables *do* propagate through their prerequisites
recursively, but that's different than a special target,
and I proposed this as a special target.
Did I misunderstand something?

Now the variables SHELL and .SHELLFLAGS *are* variables, and if you set
either one as a typical target-specific variable then that
*WOULD* propagate through the
prerequisites (like any other such variable).
The documentation for this should probably recommend that
if you set a target-specific value of SHELL then you should consider
defining it as a "private" value. I think that's probably a good idea
whether or not .ONESHELL had this extension.
But since GNU make already has private, override, etc.,
I think there's plenty of opportunity for control over these variables.

> > Note the ".SHELLFLAGS =", which is odd syntactically but should be allowed.
> > This also works nicely with "Idea: Allow certain special targets as dependencies":
>
> Yes this would be nice.  And it's consistent with Make philosophy of
> trying to be
> very terse.  btw I assume these special prereqs would not be visible to $< etc

Whups, I totally forgot to spec that. Thanks for noting that!

Yes, I completely agree, these special prerequisites should *NOT* be
visible to $< etc., since they're directives syntactically expressed as
dependencies, not actual prerequisites.

Any other comments?

--- David A. Wheeler

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

Re: Idea: Enable .ONESHELL to be per-target

David Boyce-3
> You can probably make a case for either one, but .ONESHELL already exists, so let's just expand what's already there.

It's also worth noting that .ONESHELL is a recommendation from POSIX. There's a note in POSIX.2 that says something along the lines of "Recipes should have been passed to a single shell all along but we can't change that here because (a) it would break a lot of existing makefiles and (b) our job is not to invent things, it's to standardize existing practices. However, we think it would be a great idea to define a special target called .ONESHELL to request the improved behavior."

On Mon, Jun 10, 2019 at 4:16 PM David A. Wheeler <[hidden email]> wrote:
> On Mon, Jun 10, 2019 at 4:56 AM David A. Wheeler <[hidden email]> wrote:
> > Another idea: Enable .ONESHELL to be per-target.

On Mon, 10 Jun 2019 11:47:19 -0800, Britton Kerin <[hidden email]> wrote:
> Strongly seconded, I would definitely use this.  I've been
> attracted to it many times but never dared try globally.
> Would make use of shell vars much less ugly and full of \
> lines etc.

Excellent!

> I do think some thought on the syntax might be in order still
> though.  With some of these it's not obvious which default
> sense would be more useful, e.g.
>
>      # GLobal setting
>      .ONESHELL:
>
>      tricky_target: .NOTONESHELL:
>
> might be what is really wanted in many cases.

You can probably make a case for either one, but
.ONESHELL already exists, so let's just expand what's already there.
My theory is that in existing Makefiles
you would only enable .ONESHELL in specific cases,
so having ".ONESHELL" be the one you ask for in special cases
seems more sensible as the primary term.
Also, I think primary terms with a built-in negation are best
avoided. They force people work through double negatives
in many contexts.

If you want to disable a global special target
in a specific case, then I think there should be a general-purpose syntax
for this kind of thing.  Something like this:

~~~~
tricky_target: ! .ONESHELL
~~~~

(Instead of "!" it could be something else like ".NOT".)

I don't know if this negation case is worth supporting, but if it is,
having a reusable syntactic solution would be much better
than a weird special case.  It means there's less to remember
(the same approach works every time) and it's easy to generalize.


> I guess these would taint prereqs, like local vars do.

I don't think so; that wasn't my intention.

Currently .ONESHELL is a special target, not a (target-specific) variable,
and I intended to keep it that way.
It's my understanding that normally special targets
don't propagate when building their prerequisites.
E.g., a .PHONY target can depend on a non-.PHONY target.

Target-specific variables *do* propagate through their prerequisites
recursively, but that's different than a special target,
and I proposed this as a special target.
Did I misunderstand something?

Now the variables SHELL and .SHELLFLAGS *are* variables, and if you set
either one as a typical target-specific variable then that
*WOULD* propagate through the
prerequisites (like any other such variable).
The documentation for this should probably recommend that
if you set a target-specific value of SHELL then you should consider
defining it as a "private" value. I think that's probably a good idea
whether or not .ONESHELL had this extension.
But since GNU make already has private, override, etc.,
I think there's plenty of opportunity for control over these variables.

> > Note the ".SHELLFLAGS =", which is odd syntactically but should be allowed.
> > This also works nicely with "Idea: Allow certain special targets as dependencies":
>
> Yes this would be nice.  And it's consistent with Make philosophy of
> trying to be
> very terse.  btw I assume these special prereqs would not be visible to $< etc

Whups, I totally forgot to spec that. Thanks for noting that!

Yes, I completely agree, these special prerequisites should *NOT* be
visible to $< etc., since they're directives syntactically expressed as
dependencies, not actual prerequisites.

Any other comments?

--- David A. Wheeler

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

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