[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