Was ist der Unterschied zwischen den GNU Makefile-Variablenzuweisungen = ,? = ,: = Und + =?

764

Kann jemand eine klare Erklärung geben, wie die Variablenzuweisung in Makefiles wirklich funktioniert?

Was ist der Unterschied zwischen :

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

Ich habe den Abschnitt im Handbuch von GNU Make gelesen , aber er macht für mich immer noch keinen Sinn.

mmoris
quelle

Antworten:

1029

Fauler Satz

VARIABLE = value

Die normale Einstellung einer Variablen, aber alle anderen mit dem valueFeld erwähnten Variablen werden rekursiv mit ihrem Wert an dem Punkt erweitert, an dem die Variable verwendet wird, und nicht an dem Punkt, an dem sie deklariert wurde

Sofortiges Set

VARIABLE := value

Festlegen einer Variablen mit einfacher Erweiterung der darin enthaltenen Werte - Die darin enthaltenen Werte werden zur Deklarationszeit erweitert.

Fauler Satz, wenn nicht vorhanden

VARIABLE ?= value

Festlegen einer Variablen nur, wenn sie keinen Wert hat. valuewird immer ausgewertet, wenn darauf VARIABLEzugegriffen wird. Es ist äquivalent zu

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

Weitere Informationen finden Sie in der Dokumentation .

Anhängen

VARIABLE += value

Anhängen des angegebenen Werts an den vorhandenen Wert (oder Festlegen dieses Werts, wenn die Variable nicht vorhanden war)

Alnitak
quelle
25
Erweitert A + = B B? Das heißt, wenn ich A + = B und dann B + = C mache, würde A die Verkettung von $ {B} und $ {C} bewerten?
Anton Daneyko
15
Wie der verlinkte Abschnitt des Handbuchs sagt. + = arbeitet nach der einfachen oder rekursiven Semantik der ursprünglichen Zuordnung. Ja, es wird die RHS erweitern, aber ob dies sofort oder auf verzögerte Weise geschieht, hängt vom Typ der Variablen auf der LHS ab.
Etan Reisner
6
Was meinst du, wenn du sagst, dass der Variablenwert erweitert wird?
Sashko Lykhenko
2
@ СашкоЛихенко Schauen Sie hier, um die Bedeutung der Erweiterung zu erfahren. Gnu.org/software/make/manual/make.html#Flavors
Umair R
7
ist "gesetzt wenn abwesend" faul oder sofort? Kann ich "faul setzen, wenn abwesend" und "sofort setzen, wenn abset"?
Woodrow Barlow
268

Durch Verwenden =wird der Variablen ein Wert zugewiesen. Wenn die Variable bereits einen Wert hatte, wird sie ersetzt. Dieser Wert wird erweitert, wenn er verwendet wird. Zum Beispiel:

HELLO = world
HELLO_WORLD = $(HELLO) world!

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

HELLO = hello

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

Die Verwendung :=ähnelt der Verwendung =. Anstatt den Wert zu erweitern, wenn er verwendet wird, wird er jedoch während der Zuweisung erweitert. Zum Beispiel:

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)

Mit ?=weist der Variablen einen Wert zu, wenn die Variable zuvor nicht zugewiesen wurde. Wenn der Variablen zuvor ein leerer Wert ( VAR=) zugewiesen wurde , wird er meiner Meinung nach immer noch als gesetzt betrachtet . Ansonsten funktioniert genau so =.

Verwenden +=ist wie Verwenden =, aber anstatt den Wert zu ersetzen, wird der Wert mit einem Leerzeichen dazwischen an den aktuellen Wert angehängt. Wenn die Variable zuvor mit gesetzt wurde :=, wird sie meiner Meinung nach erweitert . Der resultierende Wert wird erweitert, wenn er verwendet wird, denke ich . Zum Beispiel:

HELLO_WORLD = hello
HELLO_WORLD += world!

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

Wenn so etwas HELLO_WORLD = $(HELLO_WORLD) world!verwendet würde, würde sich eine Rekursion ergeben, die höchstwahrscheinlich die Ausführung Ihres Makefiles beenden würde. Wenn A := $(A) $(B)verwendet würde, wäre das Ergebnis nicht genau das gleiche wie bei Verwendung, +=da Bes mit erweitert wird, :=während +=es nicht Bzu einer Erweiterung führen würde.

Strager
quelle
3
eine Folge davon ist daher VARIABLE = literalund VARIABLE := literalsind immer gleichwertig. Habe ich das richtig verstanden?
Aiao
1
@aiao, ja, da Literale für ihre Verwendung unveränderlich sind
Sebastian
Ein subtiler Unterschied ist: - ?: Kann die Leistung in rekursiven Makefiles verbessern. Zum Beispiel wenn $? = $ (Shell some_command_that_runs_long_time). Bei rekursiven Aufrufen wird dies nur einmal ausgewertet. Dies führt zu einer Steigerung der Build-Leistung. : = wird langsamer sein, da der Befehl unnötig mehrmals ausgeführt wird
KeshV
61

Ich schlage vor, Sie machen einige Experimente mit "make". Hier ist eine einfache Demo, die den Unterschied zwischen =und zeigt :=.

/* 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 Drucke:

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

Weitere ausführliche Erklärungen finden Sie hier

Nickand
quelle
5
Es ist besser, @vor jedem Rezept ein vorangestelltes Rezept zu verwenden, um diese verwirrende Wiederholung der Ergebnisse zu vermeiden.
Alexandro de Oliveira
2
Jetzt unterstützt keinen /* ... */Block Kommentar
yoonghm
31

Wenn Sie verwenden VARIABLE = value, wenn valuetatsächlich eine Referenz auf eine andere Variable ist, wird der Wert nur bestimmt, wenn er VARIABLEverwendet wird. Dies lässt sich am besten anhand eines Beispiels veranschaulichen:

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

# VARIABLE and VAL will both evaluate to "bar"

Wenn Sie verwenden VARIABLE := value, erhalten Sie den Wert von value wie er jetzt ist . Zum Beispiel:

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

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

Verwenden VARIABLE ?= valbedeutet, dass Sie nur den Wert von VARIABLE if festlegen, der noch VARIABLEnicht festgelegt wurde. Wenn es noch nicht festgelegt ist, wird die Einstellung des Werts verschoben, bis er VARIABLEverwendet wird (wie in Beispiel 1).

VARIABLE += valuehängt einfach valuean VARIABLE. Der tatsächliche Wert von valuewird so bestimmt, wie er war, als er ursprünglich eingestellt wurde, entweder mit =oder :=.

Mipadi
quelle
In Ihrem ersten Beispiel ist VARIABLE $ (VAL) und VAL ist bar. VARIABLE wurde erweitert, wenn es verwendet wird.
Strager
1
Ja, die Kommentare erklären, was passieren würde, wenn sie verwendet werden.
Mipadi
Ah; Ich denke, Sie haben es korrigiert, oder ich habe "bewerten" als "sein" falsch verstanden.
Strager
7

In den obigen Antworten ist es wichtig zu verstehen, was unter "Werte werden zum Zeitpunkt der Deklaration / Verwendung erweitert" zu verstehen ist. Einen Wert wie zu geben, *.cbedeutet keine Erweiterung. Nur wenn diese Zeichenfolge von einem Befehl verwendet wird, wird möglicherweise ein Globbing ausgelöst. In ähnlicher Weise beinhaltet ein Wert wie $(wildcard *.c)oder $(shell ls *.c)keine Erweiterung und wird zum Zeitpunkt der Definition vollständig ausgewertet, selbst wenn wir ihn :=in der Variablendefinition verwendet haben.

Versuchen Sie das folgende Makefile in einem Verzeichnis, in dem Sie einige C-Dateien haben:

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

Durch Ausführen makewird eine Regel ausgelöst, die eine zusätzliche (leere) C-Datei erstellt, die aufgerufen wird, foo.caber keine der 6 Variablen enthält foo.c.

phs
quelle
Dies ist ein großartiger Aufruf und enthält viele Beispiele für die Erweiterung zur Deklarationszeit. Es wäre nützlich, die Antwort mit einem Beispiel und einigen Worten zur Erweiterung zur Nutzungszeit zu erweitern
Robert Monfera,