Makefile variable initialization and export

后端 未结 4 1776
野趣味
野趣味 2021-02-02 08:00
somevar := apple
export somevar
update := $(shell echo \"v=$$somevar\")

all:
    @echo $(update)

I was hoping to apple as output of command, however i

4条回答
  •  北海茫月
    2021-02-02 08:52

    @Beta's answer contains the crucial pointer: with GNU make, variables marked with export are only available to [the shells launched for] recipe commands (commands that are part of rules), regrettably not to invocations of $(shell ...) (they only see the environment that make itself saw when it was launched).

    There is a workaround, however: explicitly pass the exported variable as an environment variable to the shell function:

    update := $(shell somevar='$(somevar)' perl -e 'print "$$ENV{somevar}"')
    

    By prepending the shell command with =, that definition is added as an environment variable to the environment that the command sees - this is a generic shell feature.

    Caveat: @Kaz points out in a comment that this method misbehaves if $(somevar) contains certain chars., because the variable expansion is verbatim (no escaping), which can break the resulting shell command, and suggests the following variant to also work with embedded ' instances (breaks the input value into single-quoted substrings with quoted ' spliced in):

    update := $(shell somevar='$(subst ','\'',$(somevar))' perl -e 'print "$$ENV{somevar}"')
    

    This should work with all values except multi-line ones (which are rare; there is no workaround for multi-line values that I'm aware of).

    On a side note, literal $ chars. in values must be represented as $$, otherwise make will interpret them as references to its own variables.

    Note that I've deliberately NOT chosen the OP's original statement, update := $(shell echo "v=$$somevar"), for demonstration, because it contains a pitfall that muddles the issue: due to how the shell evaluates a command line, somevar=apple echo v=$somevar does NOT evaluate to v=apple, because the $somevar reference is expanded before somevar=apple takes effect. To achieve the desired effect in this case, you'd have to use 2 statements: update := $(shell export somevar="$(somevar)"; echo "v=$$somevar")


    As for the bug-vs.-feature debate:

    While it can be argued that the shell function should see the same environment as recipe commands, the documentation makes no such promise - see http://www.gnu.org/software/make/manual/make.html#Shell-Function. Conversely, http://www.gnu.org/software/make/manual/make.html#Variables_002fRecursion only mentions making exported variables available to recipe commands.

提交回复
热议问题