Qual è la differenza tra le assegnazioni della variabile GNU Makefile =,? =,: = E + =?

Qualcuno può dare una chiara spiegazione di come l’assegnazione delle variabili funzioni davvero nei Makefile.

Qual è la differenza tra :

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

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

Set pigro

 VARIABLE = value 

Impostazione normale di una variabile: i valori al suo interno vengono espansi in modo ricorsivo quando viene utilizzata la variabile, non quando è dichiarata

Immediato Set

 VARIABLE := value 

Impostazione di una variabile con semplice espansione dei valori all’interno – i valori al suo interno vengono espansi al momento della dichiarazione.

Imposta se assente

 VARIABLE ?= value 

Impostazione di una variabile solo se non ha un valore

Aggiungere

 VARIABLE += value 

Aggiunta del valore fornito al valore esistente (o impostazione di quel valore se la variabile non esisteva)

L’utilizzo di = fa assegnare alla variabile un valore. Se la variabile ha 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) 

Usando := è simile all’utilizzo = . Tuttavia, al posto del valore espanso 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 assegnata in precedenza. Se alla variabile è stato assegnato in precedenza un valore vuoto ( VAR= ), è ancora considerato come impostato. Altrimenti, funziona esattamente come = .

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

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

Se qualcosa come HELLO_WORLD = $(HELLO_WORLD) world! sono stati utilizzati, ne risulterebbe la ricorsione, che molto probabilmente finirebbe l’esecuzione del tuo Makefile. Se A := $(A) $(B) sono stati usati, il risultato non sarebbe esattamente lo stesso di usare += perché B è espanso con := mentre += non causerebbe l’espansione di B

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 di make test :

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

Controlla qui la spiegazione più dettagliata

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

 VAL = foo VARIABLE = $(VAL) VAL = bar # VARIABLE and VAL will both evaluate to "bar" 

Quando si utilizza VARIABLE := value , si ottiene il valore del value come è ora . Per esempio:

 VAL = foo VARIABLE := $(VAL) VAL = bar # VAL will evaluate to "bar", but VARIABLE will evaluate to "foo" 

Usando VARIABLE ?= val significa che si imposta solo il valore di VARIABLE se VARIABLE non è già impostato. Se non è già impostato, l’impostazione del valore viene differita fino a quando viene utilizzato VARIABLE (come nell’esempio 1).

VARIABLE += value aggiunge semplicemente value a VARIABLE . Il valore effettivo del value è determinato com’era quando era stato inizialmente impostato, usando o = o := .

Nelle risposte di cui sopra, è importante capire cosa si intende per “i valori vengono espansi alla dichiarazione / tempo di utilizzo”. Fornire un valore come *.c non comporta alcuna espansione. È solo quando questa stringa viene usata da un comando che potrebbe innescare un po ‘di globbing. Allo stesso modo, un valore come $(wildcard *.c) o $(shell ls *.c) non comporta alcuna espansione ed è completamente valutato al momento della definizione anche se abbiamo usato := nella definizione della variabile.

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 di make attiverà una regola che crea un file C in più (vuoto), chiamato foo.c ma nessuna delle 6 variabili ha foo.c nel suo valore.