0

Consider the following Makefile:

X = macro-X-value
foo:
        echo $$X $(X)

The intention here is to use X both as a name of an environment variable and of a macro. When using bmake, it works as intended:

$ env X=env-X-value /usr/bin/bmake
  echo $X macro-X-value
  env-X-value macro-X-value

$ env -i /usr/bin/bmake
  echo $X macro-X-value
  macro-X-value

But when using GNU Make (v. 4.2.1), the behaviour gets weird:

$ env X=env-X-value /usr/bin/gmake
  echo $X macro-X-value
  macro-X-value macro-X-value

$ env -i /usr/bin/gmake
  echo $X macro-X-value
  macro-X-value

So, it seems like gmake exports the value of the macro X as an environment variable X, but only when the outer environment already exports X.

I can't find anything about this in the POSIX Make description. In fact, there is this bit there:

Macros are not exported to the environment of commands to be run. […]

Is this behaviour documented? Is this a bug? Can it be disabled?

3
  • 1
    GNU Make manual says (in 5.7.2) "Except by explicit request, make exports a variable only if it is either defined in the environment initially or set on the command line", and then says that the export and unexport keywords can be used to control that. But as far as I tested, using unexport X just removes it completely from the environment of the launched process. – ilkkachu Apr 22 at 15:46
  • 1
    Then again, it also says (in 6.10) that "Every environment variable that make sees when it starts up is transformed into a make variable with the same name and value.", which seems to imply it treats envvars and internal vars in the same way the shells do, that you can't have them with the same name and a different value since they're really one and the same. – ilkkachu Apr 22 at 15:49
  • @ilkkachu, I see, thank you. If you post that as an answer, I'll accept it. I guess I'll have to rename the macro. – Ainar-G Apr 22 at 17:01
1

Based on what I can read from the manual, it seems GNU make treats its variables a bit like the shell. When it starts, it imports variables from the environment to its internal set, and when running commands, exports to their environment the ones marked for export. Which implies it only has a single table for all variables, and no way to have environment variable and a non-environment variable of the same name.

6.10 Variables from the Environment:

Variables in make can come from the environment in which make is run. Every environment variable that make sees when it starts up is transformed into a make variable with the same name and value.

and 5.7.2 Communicating Variables to a Sub-make:

Except by explicit request, make exports a variable only if it is either defined in the environment initially or set on the command line [...] If you want to export specific variables to a sub-make, use the export directive, like this:

export variable …

If you want to prevent a variable from being exported, use the unexport directive, like this:

unexport variable …

As far as I tested, using unexport X just removes it from the environment of the launched process completely, with seemingly no way to keep a different value than the one the internal variable has.


Using the .POSIX built-in target didn't seem to change that behaviour either, but then, the opinion seems to be that no Make is too strict on POSIX behaviour anyway.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.