export vs $(origin )

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

export vs $(origin )

Jan Beulich-2
Hello,

with documentation stating

"As a convenience, you can define a variable and export it at the same
 time by doing: ..."

It being merely a convenience, is it really intended for "export"
without any assignment done at the same time to change the origin of a
previously undefined variable from "undefined" to "file"? It doesn't
change "default" to "file" for a variable with a default value, for
comparison.

As to the use case - to be able to determine whether a variable has
been given a non-default value, and for such a check to be independent
of whether
- -R was passed to make
- export lives ahead or after the check
a change in behavior would seem to be needed, as such a check can,
afaict, only sensibly check for "undefined" and "default".

FAOD I checked up to 4.3, but not any newer development version of make.

Thanks, Jan

Reply | Threaded
Open this post in threaded view
|

Re: export vs $(origin )

Gnu - Make - Bugs mailing list
On Thu, Jul 2, 2020 at 8:49 AM Jan Beulich <[hidden email]> wrote:
> is it really intended for "export"
> without any assignment done at the same time to change the origin of a
> previously undefined variable from "undefined" to "file"?

"export" without any assignment done at the same time sets the origin
to "environment".

export wom
introduces the variable to the env and set origin to environment.

export wom=
also assigns the value of the variable and sets the origin to "file".


> It doesn't
> change "default" to "file" for a variable with a default value, for
> comparison.

export CC=
sets origin to "file" because a new value from the file is assigned.

export CC
keeps origin intact because the value does not change.



> As to the use case - to be able to determine whether a variable has
> been given a non-default value, and for such a check to be independent
> of whether
> - -R was passed to make
> - export lives ahead or after the check
> a change in behavior would seem to be needed, as such a check can,
> afaict, only sensibly check for "undefined" and "default".

Can you post a sample makefile which demonstrates what you want to achieve?

regards, Dmitry

Reply | Threaded
Open this post in threaded view
|

Re: export vs $(origin )

Jan Beulich-2
On 02.07.2020 17:01, Dmitry Goncharov wrote:

> On Thu, Jul 2, 2020 at 8:49 AM Jan Beulich <[hidden email]> wrote:
>> is it really intended for "export"
>> without any assignment done at the same time to change the origin of a
>> previously undefined variable from "undefined" to "file"?
>
> "export" without any assignment done at the same time sets the origin
> to "environment".
>
> export wom
> introduces the variable to the env and set origin to environment.

Not according to my observations.

> export wom=
> also assigns the value of the variable and sets the origin to "file".
>
>
>> It doesn't
>> change "default" to "file" for a variable with a default value, for
>> comparison.
>
> export CC=
> sets origin to "file" because a new value from the file is assigned.
>
> export CC
> keeps origin intact because the value does not change.
>
>
>
>> As to the use case - to be able to determine whether a variable has
>> been given a non-default value, and for such a check to be independent
>> of whether
>> - -R was passed to make
>> - export lives ahead or after the check
>> a change in behavior would seem to be needed, as such a check can,
>> afaict, only sensibly check for "undefined" and "default".
>
> Can you post a sample makefile which demonstrates what you want to achieve?

I can try to; will take a little bit of time though.

Jan

Reply | Threaded
Open this post in threaded view
|

Re: export vs $(origin )

Paul Smith-20
On Thu, 2020-07-02 at 17:16 +0200, Jan Beulich wrote:
> > export wom
> > introduces the variable to the env and set origin to environment.
>
> Not according to my observations.

The difference is whether the variable already exists in the
environment or not.

For this makefile:

  export FOO
  $(info FOO: $(origin FOO))
  all:;

If you run it like this:

  $ FOO= make
  FOO: environment
  make: 'all' is up to date.

But if you run it like this:

  $ unset FOO; make
  FOO: file
  make: 'all' is up to date.

Basically, if you run "export FOO" and FOO does not currently exist at
all, either in the environment or in the makefile, then it's created in
make and assigned a "file" origin.

I'm not sure how it could be otherwise: by specifying "export" you ARE
creating that variable, because it will be placed into the child's
environment when a recipe is invoked, even if it's not set.  In other
words, if FOO is not already a variable make knows about then running
"export FOO" makes it into a variable that make knows about, which has
its "export" flag set.

For example if you change the above makefile:

  export FOO
  $(info FOO: $(origin FOO))
  all: ; @env | grep FOO

then you run:

  $ unset FOO; make
  FOO: file
  FOO=
  make: 'all' is up to date.

you can see that "FOO" is in the environment in the recipe even though
it wasn't in the environment when make started.


Reply | Threaded
Open this post in threaded view
|

Re: export vs $(origin )

Gnu - Make - Bugs mailing list
In reply to this post by Jan Beulich-2
On Thu, Jul 2, 2020 at 11:22 AM Jan Beulich <[hidden email]> wrote:
> Not according to my observations.

You are right.

regards, Dmitry

Reply | Threaded
Open this post in threaded view
|

Re: export vs $(origin )

Jan Beulich-2
In reply to this post by Paul Smith-20
On 02.07.2020 17:31, Paul Smith wrote:

> On Thu, 2020-07-02 at 17:16 +0200, Jan Beulich wrote:
>>> export wom
>>> introduces the variable to the env and set origin to environment.
>>
>> Not according to my observations.
>
> The difference is whether the variable already exists in the
> environment or not.
>
> For this makefile:
>
>   export FOO
>   $(info FOO: $(origin FOO))
>   all:;
>
> If you run it like this:
>
>   $ FOO= make
>   FOO: environment
>   make: 'all' is up to date.
>
> But if you run it like this:
>
>   $ unset FOO; make
>   FOO: file
>   make: 'all' is up to date.
>
> Basically, if you run "export FOO" and FOO does not currently exist at
> all, either in the environment or in the makefile, then it's created in
> make and assigned a "file" origin.
>
> I'm not sure how it could be otherwise: by specifying "export" you ARE
> creating that variable, because it will be placed into the child's
> environment when a recipe is invoked, even if it's not set.  In other
> words, if FOO is not already a variable make knows about then running
> "export FOO" makes it into a variable that make knows about, which has
> its "export" flag set.
>
> For example if you change the above makefile:
>
>   export FOO
>   $(info FOO: $(origin FOO))
>   all: ; @env | grep FOO
>
> then you run:
>
>   $ unset FOO; make
>   FOO: file
>   FOO=
>   make: 'all' is up to date.
>
> you can see that "FOO" is in the environment in the recipe even though
> it wasn't in the environment when make started.

Well, okay, if this behavior is intentional, then may I ask that
the documentation be adjusted to clarify this behavior (i.e. it
is not just a convenience that the variables _can_ be assigned a
value, but instead they always _will_ be assigned one, potentially
empty)? In the case having triggered this report, it has taken me
half a day to wade through makefiles, further complicated by some
non-standard way of recursing as well as the underlying problem
really triggering only on an older version (3.82 in the specific
case) related to how -r and -R get handled when appended to
MAKEFLAGS in a makefile, and when some of the included makefiles
gets remade and hence a re-invocation of make gets triggered.

Also, if this is intentional, then I suppose there is no solution
to the problem I'm having except moving the export line(s) until
after the variable(s) have been assigned to (or moving the
$(origin ) checks ahead of the export, which in my specific case
is not really possible).

As an aside, I am still unconvinced the behavior you describe is
the only one possibly sensible. I could as well view "export" as
a directive to indicate to put the given variable(s) into the
environment, but only if they've been assigned a (potentially
empty) value. I.e. these two would then have different behavior:

export XYZ
export XYZ=

Which means the current behavior could be achieved for people
wanting it, while export wouldn't unconditionally have the effect
of also defining the variable(s) (i.e. more along the lines of
what current documentation says).

Thanks again, Jan

Reply | Threaded
Open this post in threaded view
|

Re: export vs $(origin )

Paul Smith-20
On Fri, 2020-07-03 at 11:50 +0200, Jan Beulich wrote:

> > For example if you change the above makefile:
> >    export FOO
> >    $(info FOO: $(origin FOO))
> >    all: ; @env | grep FOO
> > then you run:
> >    $ unset FOO; make
> >    FOO: file
> >    FOO=
> >    make: 'all' is up to date.
> > you can see that "FOO" is in the environment in the recipe even
> > though it wasn't in the environment when make started.
>
>
> Well, okay, if this behavior is intentional, then may I ask that the
> documentation be adjusted to clarify this behavior (i.e. it is not
> just a convenience that the variables _can_ be assigned a value, but
> instead they always _will_ be assigned one, potentially empty)?

I think you are reading a lot more into the phrase "as a convenience"
than it was intended to convey.  As the text/example after it makes
pretty clear (IMO), it's saying that instead of writing:

  VAR = value
  export VAR

That "as a convenience" you could instead write:

  export VAR = value

The convenience is just allowing this same behavior to be obtained in
one line instead of two lines.  It's basically mimicking the same
behavior in the shell, where you can write either:

  VAR=value
  export VAR

or, more conveniently:

  export VAR=value

If it's confusing then the change we could make is simply removing the
phrase "As a convenience", which would leave it saying:

  You can define a variable and export it at the same time by doing:

We can also make clear, as a separate statement, that "export FOO" will
cause the variable FOO to be defined.

> Also, if this is intentional, then I suppose there is no solution to
> the problem I'm having except moving the export line(s) until after
> the variable(s) have been assigned to (or moving the $(origin )
> checks ahead of the export, which in my specific case is not really
> possible).

Well, it's not really clear to me what the problem you're having is,
but if you want to ensure that variables that are not defined in the
makefile are not exported at all, but if they are defined in the
makefile they are exported, then you need to either always export them
when defining them but not elsewhere, or else if you have to put the
export line somewhere else other than the definition then you have test
the variable with $(origin ...) to make sure it's defined before
exporting it, because exporting it will force it to be defined as we've
seen.

> As an aside, I am still unconvinced the behavior you describe is the
> only one possibly sensible.

Sorry, I didn't mean to imply there was no other possible way this
could work.  I agree there are other possibilities.

> I could as well view "export" as a directive to indicate to put the
> given variable(s) into the environment, but only if they've been
> assigned a (potentially empty) value. I.e. these two would then have
> different behavior:
>
> export XYZ
> export XYZ=
>
> Which means the current behavior could be achieved for people wanting
> it, while export wouldn't unconditionally have the effect of also
> defining the variable(s)

This would be backward-incompatible, and also it would add some
complexity: we'd have to add a new state to variable storage to allow a
variable to be known to make (to hold the flag that says it's
exportable) but to actually not be considered defined (until/unless it
was set), so it wouldn't be added to the child's environment.  This
latter is not a huge amount of work, I'm just saying it's not free :).

I have to say I'm not convinced that the behavior you're suggesting is
better.  Although obviously you have a need for it so the fact that
it's hard to accomplish today makes that change seem attractive, to me
it seems confusing and unexpected.  I think people will expect that
they have "export XYZ" in their makefile, they will have the variable
XYZ in their environment.  Even if they don't set it to a value.  And
the subtlety of "export FOO" versus "export FOO=" seems a bit too much
"inside baseball" to me.

> (i.e. more along the lines of what current documentation says).

As above, I disagree that this is what the documentation says... I do
believe it describes exactly what the current behavior is.  However
obviously this is not clear to everyone :) so we should address it.


Reply | Threaded
Open this post in threaded view
|

Re: export vs $(origin )

Andreas Schwab
On Jul 03 2020, Paul Smith wrote:

> This would be backward-incompatible, and also it would add some
> complexity: we'd have to add a new state to variable storage to allow a
> variable to be known to make (to hold the flag that says it's
> exportable) but to actually not be considered defined (until/unless it
> was set), so it wouldn't be added to the child's environment.

Note that this is how export works in the shell.  `export FOO' only sets
the export attribute, but keeps the variable unset (and does not appear
in the environment of subsequent commands) if it doesn't have a value
yet.

Andreas.

--
Andreas Schwab, SUSE Labs, [hidden email]
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."