Qual è la differenza tra le assegnazioni di variabili GNU Makefile =,? =,: = E + =?


765

Qualcuno può dare una chiara spiegazione di come funziona effettivamente l'assegnazione delle variabili nei Makefile.

Qual è la differenza tra :

 VARIABLE = value
 VARIABLE ?= value
 VARIABLE := value
 VARIABLE += value

Ho letto la sezione del manuale di GNU Make, ma per me non ha ancora senso.

Risposte:


1029

Set pigro

VARIABLE = value

Impostazione normale di una variabile, ma tutte le altre variabili menzionate con il valuecampo vengono espanse in modo ricorsivo con il loro valore nel punto in cui viene utilizzata la variabile, non quella che aveva quando è stata dichiarata

Set immediato

VARIABLE := value

Impostazione di una variabile con semplice espansione dei valori interni - i valori al suo interno vengono espansi al momento della dichiarazione.

Set pigro se assente

VARIABLE ?= value

Impostazione di una variabile solo se non ha un valore. valueviene sempre valutato quando VARIABLEsi accede. È equivalente a

ifeq ($(origin FOO), undefined)
  FOO = bar
endif

Vedi la documentazione per maggiori dettagli.

Aggiungere

VARIABLE += value

Aggiunta del valore fornito al valore esistente (o impostazione su quel valore se la variabile non esistesse)


25
A + = B espande B? Cioè se se faccio A + = B, e quindi B + = C, A valuterebbe la concatenazione di $ {B} e $ {C}?
Anton Daneyko,

15
Come dice la sezione collegata del manuale. + = opera secondo la semantica semplice o ricorsiva dell'incarico originale. Quindi sì, espanderà l'RHS ma se lo fa immediatamente o in modo differito dipende dal tipo di variabile sull'LHS.
Etan Reisner,

6
Cosa intendi quando dici che il valore della variabile è espanso?
Sashko Lykhenko,

3
@ СашкоЛихенко dai un'occhiata qui per ottenere un significato di espansione gnu.org/software/make/manual/make.html#Flavours
Umair R

7
"impostato se assente" è pigro o immediato? posso "impostare pigro se assente" e "impostare immediatamente se assente"?
Woodrow Barlow

268

L'uso =fa sì che alla variabile venga assegnato un valore. Se la variabile aveva già un valore, viene sostituita. Questo valore verrà espanso quando viene utilizzato. Per esempio:

HELLO = world
HELLO_WORLD = $(HELLO) world!

# This echoes "world world!"
echo $(HELLO_WORLD)

HELLO = hello

# This echoes "hello world!"
echo $(HELLO_WORLD)

L'uso :=è simile all'utilizzo =. Tuttavia, invece di espandere il valore quando viene utilizzato, viene espanso durante l'assegnazione. Per esempio:

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)

Utilizzando ?=assegna alla variabile un valore se la variabile non è stata precedentemente assegnata. Se alla variabile era stato precedentemente assegnato un valore vuoto ( VAR=), è comunque considerato impostato penso . Altrimenti, funziona esattamente come =.

Usare +=è come usare =, ma invece di sostituire il valore, il valore viene aggiunto a quello corrente, con uno spazio in mezzo. Se la variabile è stata precedentemente impostata con :=, penso che sia espansa . Il valore risultante viene espanso quando viene utilizzato, credo . Per esempio:

HELLO_WORLD = hello
HELLO_WORLD += world!

# This echoes "hello world!"
echo $(HELLO_WORLD)

Se HELLO_WORLD = $(HELLO_WORLD) world!venisse usato qualcosa di simile , si verificherebbe la ricorsione, che molto probabilmente finirebbe l'esecuzione del tuo Makefile. Se A := $(A) $(B)fossero usati, il risultato non sarebbe lo stesso dell'uso +=perché Bè espanso con :=mentre +=non causerebbe Bl'espansione.


3
una conseguenza di ciò è quindi VARIABLE = literale VARIABLE := literalsono sempre equivalenti. Ho capito bene?
aiao,

1
@aiao, sì, poiché i letterali sono invarianti rispetto ai loro usi
Sebastian,

Una sottile differenza è: -?: Può migliorare le prestazioni in ricorsivi chiamati makefile. Ad esempio se $? = $ (shell some_command_that_runs_long_time). Nelle chiamate ricorsive questo verrà valutato una sola volta. causando guadagni nelle prestazioni della build. : = sarà più lento poiché il comando viene inutilmente eseguito più volte
KeshV

61

Ti suggerisco di fare alcuni esperimenti usando "make". Ecco una semplice demo, che mostra la differenza tra =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 stampe:

x - later
y - foo bar
a - later
b - later bar

Controlla qui una spiegazione più elaborata


5
Sarebbe meglio usare una @prima di ogni ricetta per evitare questa ripetizione confusa dei risultati.
Alexandro de Oliveira,

2
Make non supporta il /* ... */commento di blocco
yoonghm,

31

Quando si utilizza VARIABLE = value, se in valuerealtà è un riferimento a un'altra variabile, il valore viene determinato solo quando VARIABLEviene utilizzato. Questo è meglio illustrato con un esempio:

VAL = foo
VARIABLE = $(VAL)
VAL = bar

# VARIABLE and VAL will both evaluate to "bar"

Quando lo usi VARIABLE := value, ottieni il valore di value com'è ora . Per esempio:

VAL = foo
VARIABLE := $(VAL)
VAL = bar

# VAL will evaluate to "bar", but VARIABLE will evaluate to "foo"

L'uso VARIABLE ?= valsignifica che si imposta solo il valore di VARIABLE if VARIABLE non è già impostato. Se non è già impostato, l'impostazione del valore viene rinviata fino a quando non VARIABLEviene utilizzata (come nell'esempio 1).

VARIABLE += valueaggiunge solo valuea VARIABLE. Il valore effettivo di valueviene determinato com'era quando è stato impostato inizialmente, usando =o :=.


In realtà, nel tuo primo esempio, VARIABLE è $ (VAL) e VAL è barra. VARIABILE espanso quando viene utilizzato.
Strager

1
Sì, i commenti spiegano cosa accadrebbe quando vengono utilizzati.
mipadi,

ah; Immagino che tu l'abbia corretto, o ho letto male "valutare" come "essere".
Strager

7

Nelle risposte di cui sopra, è importante comprendere cosa si intende per "valori espansi al momento della dichiarazione / utilizzo". Dare un valore come *.cnon comporta alcuna espansione. È solo quando questa stringa viene utilizzata da un comando che può innescare un po 'di globbing. Allo stesso modo, un valore simile $(wildcard *.c)o $(shell ls *.c)non comporta alcuna espansione e viene completamente valutato al momento della definizione anche se :=nella definizione della variabile è stato utilizzato.

Prova il seguente Makefile nella directory in cui hai alcuni file 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

L'esecuzione makeinnescherà una regola che crea un file C (vuoto) aggiuntivo, chiamato foo.cma nessuna delle 6 variabili ha il foo.csuo valore.


Questa è un'ottima chiamata e ha molti esempi di espansione al momento della dichiarazione, sarebbe utile estendere la risposta con un esempio e alcune parole per l'espansione al momento dell'uso
Robert Monfera
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.