Qual é a diferença entre a atribuições de variáveis ??GNU Makefile =, =,:? = E + =?
Pergunta
Alguém pode dar uma explicação clara de como atribuição de variável realmente funciona em Makefiles.
O que é a diferença entre:
VARIABLE = value
VARIABLE ?= value
VARIABLE := value
VARIABLE += value
Eu li o seção no GNU make de manual, mas ele ainda não faz sentido para mim.
Solução
preguiçoso Set
VARIABLE = value
A configuração normal de uma variável - valores dentro dele são expandidos de forma recursiva quando a variável é usada, não quando ele é declarado
Imediato Set
VARIABLE := value
Configuração de uma variável com simples expansão dos valores dentro -. Valores dentro dele são expandidas em tempo de declaração
Set Se Ausente
VARIABLE ?= value
Configuração de uma variável somente se ele não tem um valor
Anexar
VARIABLE += value
Acrescentando o valor fornecido para o valor existente (ou ajuste a esse valor se a variável não existia)
Outras dicas
Usando =
faz com que a variável a ser atribuído um valor. Se a variável já tinha um valor, ele é substituído. Este valor será ampliada quando ele é usado. Por exemplo:
HELLO = world
HELLO_WORLD = $(HELLO) world!
# This echoes "world world!"
echo $(HELLO_WORLD)
HELLO = hello
# This echoes "hello world!"
echo $(HELLO_WORLD)
Usando :=
é semelhante ao uso =
. No entanto, em vez do valor que está sendo expandida quando ele é usado, ele é expandido durante a atribuição. Por exemplo:
HELLO = world
HELLO_WORLD := $(HELLO) world!
# This echoes "world world!"
echo $(HELLO_WORLD)
HELLO = hello
# Still echoes "world world!"
echo $(HELLO_WORLD)
HELLO_WORLD := $(HELLO) world!
# This echoes "hello world!"
echo $(HELLO_WORLD)
Usando ?=
atribui à variável um valor sse a variável não foi atribuído anteriormente. Se a variável foi anteriormente atribuído um valor em branco (VAR=
), ainda é considerado set Eu acho . Caso contrário, funciona exatamente como =
.
Usando +=
é como usar =
, mas em vez de substituir o valor, o valor é acrescentado ao atual, com um espaço entre elas. Se a variável foi definida anteriormente com :=
, ele é expandido Eu acho . O valor resultante é expandido quando ele é usado Eu acho . Por exemplo:
HELLO_WORLD = hello
HELLO_WORLD += world!
# This echoes "hello world!"
echo $(HELLO_WORLD)
Se foram usados ??algo como HELLO_WORLD = $(HELLO_WORLD) world!
, recursão resultaria, que provavelmente terminará a execução de seu Makefile. Se foram utilizados A := $(A) $(B)
, o resultado não seria exatamente o mesmo que usar +=
porque B
é expandido com :=
enquanto +=
que não causa B
para ser expandido.
Eu sugiro que você faça algumas experiências usando "make". Aqui é um simples demo, mostrando a diferença entre =
e :=
.
/* Filename: Makefile*/
x := foo
y := $(x) bar
x := later
a = foo
b = $(a) bar
a = later
test:
@echo x - $(x)
@echo y - $(y)
@echo a - $(a)
@echo b - $(b)
make test
impressões:
x - later
y - foo bar
a - later
b - later bar
Quando você usa VARIABLE = value
, se value
é realmente uma referência a outra variável, então o valor é determinada apenas quando VARIABLE
é usado. Isto é melhor ilustrado com um exemplo:
VAL = foo
VARIABLE = $(VAL)
VAL = bar
# VARIABLE and VAL will both evaluate to "bar"
Quando você usa VARIABLE := value
, você obter o valor de value
como é agora . Por exemplo:
VAL = foo
VARIABLE := $(VAL)
VAL = bar
# VAL will evaluate to "bar", but VARIABLE will evaluate to "foo"
Usando meios VARIABLE ?= val
que você só definir o valor da VARIABLE
se VARIABLE
ainda não estiver definido. Se ainda não estiver definido, a definição do valor é adiada até VARIABLE
é utilizado (como no exemplo 1).
VARIABLE += value
apenas acrescenta value
para VARIABLE
. O valor real de value
é determinada como estava quando foi inicialmente definido, utilizando quer =
ou :=
.
Nas respostas acima, É importante compreender que se entende por "valores são expandidas em tempo de declaração / uso". Dando um valor como *.c
não implica qualquer expansão. É somente quando este texto é utilizado por um comando que vai talvez provocar alguma englobamento. Da mesma forma, um valor como $(wildcard *.c)
ou $(shell ls *.c)
não implica qualquer expansão e está completamente avaliada em tempo de definição, mesmo que usado :=
na definição variável.
Tente o seguinte Makefile no diretório onde você tem alguns arquivos C:
VAR1 = *.c
VAR2 := *.c
VAR3 = $(wildcard *.c)
VAR4 := $(wildcard *.c)
VAR5 = $(shell ls *.c)
VAR6 := $(shell ls *.c)
all :
touch foo.c
@echo "now VAR1 = \"$(VAR1)\"" ; ls $(VAR1)
@echo "now VAR2 = \"$(VAR2)\"" ; ls $(VAR2)
@echo "now VAR3 = \"$(VAR3)\"" ; ls $(VAR3)
@echo "now VAR4 = \"$(VAR4)\"" ; ls $(VAR4)
@echo "now VAR5 = \"$(VAR5)\"" ; ls $(VAR5)
@echo "now VAR6 = \"$(VAR6)\"" ; ls $(VAR6)
rm -v foo.c
Running make
irá desencadear uma regra que cria um (Vazio) arquivo extra C, chamado foo.c
mas nenhuma das 6 variáveis ??tem foo.c
em seu valor.