help-make
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Changes to --printf-directory handling in Make 4.4


From: Kaz Kylheku
Subject: Re: Changes to --printf-directory handling in Make 4.4
Date: Wed, 05 Jul 2023 00:54:38 -0700
User-agent: Roundcube Webmail/1.4.13

On 2023-07-04 10:08, Paul Smith wrote:
> On Mon, 2023-07-03 at 16:32 +0100, Jonathan Wakely wrote:
>> This left me puzzled for a while, but what's happening is that the output of
>> $(shell $(MAKE) bar)
>> now includes the --print-directory output, so where the recipe for
>> 'foo' used to do simply `make baz` now it is `make make[1] Entering
>> directory etc.`
>>
>> Is this an intended consequence of the changes to --print-directory
>> handling in 4.4?
> 
> I don't think it's related to that.
> 
> I think it's related to this change:
> 
>> * WARNING: Backward-incompatibility!
>>   Previously makefile variables marked as export were not exported to 
>> commands
>>   started by the $(shell ...) function.  Now, all exported variables are
>>   exported to $(shell ...).  If this leads to recursion during expansion, 
>> then
>>   for backward-compatibility the value from the original environment is used.
>>   To detect this change search for 'shell-export' in the .FEATURES variable.
> 
> Previously the only environment variables passed to $(shell ...)
> commands were the ones inherited from the parent environment; changes
> made in the makefile were not sent to $(shell ...).  Now, exported
> variables (such as MAKEFLAGS) set in the makefile itself are also
> passed to $(shell ...) commands.

May I suggest an ugly, but potentially general solution sketch?
This relies on GNU Coreutils env, GNU grep.

The idea is to create a custom shell invocation command which uses
an arbitrarily sanitized environment. We can remove unwanted variables
from it.

The command is invoked as $(call sh,<command>) rather than $(shell <command>).

How this works is that we generate a command of the following form which
executes in the environment in which there are unwanted variables:

   env -i -- "var1=$var1" "var2=$var2" ... /bin/sh -c 'target command'

Because this shell command has all the environments in its dynamic scope,
it is able to interpolate their values into the env command line.

But "env -i" clears the environment to empty, and then performs the
specified environment bindings, so then the payload
/bin/sh -c 'target command' executes in an environment which has
only those variables that we choose to mention in the env command line.

Implementation follows:

# Get list of all environment variable names visible to shell command
env_var_names := $(shell env -0 | grep -z -E -o '^[^=]+' | tr '\0' '\n')

# Filter out environment names starting with MAKE
env_var_names := $(filter-out MAKE,$(env_var_names))

# Shell command which invokes with only the filtered environment: use as $(call 
sh, ...)
# Get list of all environment variable names visible to shell command
env_var_names := $(shell env -0 | grep -z -E -o '^[^=]+' | tr '\0' '\n')

# Filter out environment names starting with MAKE
env_var_names := $(filter-out MAKE,$(env_var_names))

# Shell command which invokes with only the filtered environment: use as $(call 
sh, ...)
sh = $(shell env -i -- $(foreach name,$(env_var_names),"$(name)=$$$(name)") 
/bin/sh -c '$(1)')

# Invoke 'env > out' command via $(call sh, ...)
$(call sh, env > out)

# Print content of out: no MAKE variables should be shown
all:
        cat out


# Invoke 'env > out' command via $(call sh, ...)
$(call sh, env > out)

# Print content of out: no MAKE variables should be shown
all:
        cat out




reply via email to

[Prev in Thread] Current Thread [Next in Thread]