Quelle est la différence entre les affectations de variables GNU Makefile =,? =,: = Et + =?

765

Quelqu'un peut-il expliquer clairement comment fonctionne vraiment l'affectation des variables dans les Makefiles?

Quelle est la différence entre :

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

J'ai lu la section du manuel de GNU Make, mais cela n'a toujours pas de sens pour moi.

mmoris
la source

Réponses:

1029

Ensemble paresseux

VARIABLE = value

Réglage normal d'une variable, mais toutes les autres variables mentionnées avec le value champ sont récursivement développées avec leur valeur au point où la variable est utilisée, pas celle qu'elle avait lorsqu'elle a été déclarée

Ensemble immédiat

VARIABLE := value

Définition d'une variable avec simple expansion des valeurs à l'intérieur - les valeurs à l'intérieur sont développées au moment de la déclaration.

Paresseux si absent

VARIABLE ?= value

Définition d'une variable uniquement si elle n'a pas de valeur. valueest toujours évalué lors de l' VARIABLEaccès. C'est équivalent à

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

Voir la documentation pour plus de détails.

Ajouter

VARIABLE += value

Ajout de la valeur fournie à la valeur existante (ou définition de cette valeur si la variable n'existait pas)

Alnitak
la source
25
A + = B développe-t-il B? C'est-à-dire que si je fais A + = B, puis B + = C, A serait-il évalué à la concaténation de $ {B} et $ {C}?
Anton Daneyko
15
Comme le dit la section liée du manuel. + = fonctionne selon la sémantique simple ou récursive de l'affectation d'origine. Alors oui, cela étendra le RHS, mais le fait de le faire immédiatement ou de manière différée dépend du type de variable sur le LHS.
Etan Reisner
6
Que voulez-vous dire lorsque vous dites que la valeur de la variable est développée?
Sashko Lykhenko
3
@ СашкоЛихенко jetez un oeil ici pour obtenir le sens de l'expansion gnu.org/software/make/manual/make.html#Flavors
Umair R
7
est "réglé si absent" paresseux ou immédiat? puis-je "paresseux en cas d'absence" et "ensemble immédiat en cas d'abset"?
Woodrow Barlow du
268

L'utilisation =entraîne l'attribution d'une valeur à la variable. Si la variable avait déjà une valeur, elle est remplacée. Cette valeur sera développée lors de son utilisation. Par exemple:

HELLO = world
HELLO_WORLD = $(HELLO) world!

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

HELLO = hello

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

L'utilisation :=est similaire à l'utilisation =. Cependant, au lieu de développer la valeur lors de son utilisation, elle est développée lors de l'affectation. Par exemple:

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)

L'utilisation ?=affecte à la variable une valeur si la variable n'a pas été précédemment affectée. Si la variable a été précédemment affectée d'une valeur vide ( VAR=), elle est toujours considérée comme définie, je pense . Sinon, fonctionne exactement comme =.

Utiliser, +=c'est comme utiliser =, mais au lieu de remplacer la valeur, la valeur est ajoutée à la valeur actuelle, avec un espace entre les deux. Si la variable a été précédemment définie avec :=, elle est développée je pense . La valeur résultante est élargie lorsqu'elle est utilisée, je pense . Par exemple:

HELLO_WORLD = hello
HELLO_WORLD += world!

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

Si quelque chose du genre HELLO_WORLD = $(HELLO_WORLD) world!était utilisé, une récursivité en résulterait, ce qui mettrait très probablement fin à l'exécution de votre Makefile. Si elles A := $(A) $(B)étaient utilisées, le résultat ne serait pas exactement le même que celui utilisé +=car Best développé avec :=alors +=qu'il ne provoquerait pas Bde développement.

strager
la source
3
une conséquence de cela est donc VARIABLE = literal et VARIABLE := literalest toujours équivalente. Ai-je bien compris?
aiao
1
@aiao, oui car les littéraux sont invariants à leurs usages
Sebastian
Une subtile différence est la suivante: -?: Peut améliorer les performances des fichiers makefile récursifs. Par exemple, si $? = $ (shell some_command_that_runs_long_time). Dans les appels récursifs, cela ne sera évalué qu'une seule fois. entraînant des gains de performances de construction. : = sera plus lent car la commande s'exécute inutilement plusieurs fois
KeshV
61

Je vous suggère de faire quelques expériences en utilisant "make". Voici une démo simple, montrant la différence entre =et :=.

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

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

Vérifiez l'explication plus élaborée ici

nickand
la source
5
Il serait préférable d'utiliser un @devant chaque recette pour éviter cette répétition confuse des résultats.
Alexandro de Oliveira
2
Make ne supporte pas les /* ... */commentaires de bloc
yoonghm
31

Lorsque vous utilisez VARIABLE = value, si valueest en fait une référence à une autre variable, la valeur n'est déterminée que lorsqu'elle VARIABLEest utilisée. Ceci est mieux illustré par un exemple:

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

# VARIABLE and VAL will both evaluate to "bar"

Lorsque vous utilisez VARIABLE := value, vous obtenez la valeur de value ce qu'elle est maintenant . Par exemple:

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

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

L'utilisation VARIABLE ?= valsignifie que vous définissez uniquement la valeur de VARIABLE si VARIABLE n'est pas déjà définie. S'il n'est pas déjà défini, le réglage de la valeur est différé jusqu'à ce qu'il VARIABLEsoit utilisé (comme dans l'exemple 1).

VARIABLE += valueajoute juste valueà VARIABLE. La valeur réelle de valueest déterminée telle qu'elle était lorsqu'elle a été initialement définie, à l'aide de =ou :=.

mipadi
la source
En fait, dans votre premier exemple, VARIABLE est $ (VAL) et VAL est bar. VARIABLE élargie lorsqu'elle est utilisée.
strager
1
Oui, les commentaires expliquent ce qui se passerait lorsqu'ils seraient utilisés.
mipadi
Ah; Je suppose que vous l'avez corrigé, ou j'ai mal interprété "évaluer" comme "être".
strager
7

Dans les réponses ci-dessus, il est important de comprendre ce que l'on entend par "les valeurs sont développées au moment de la déclaration / de l'utilisation". Donner une valeur comme *.cn'implique aucune expansion. Ce n'est que lorsque cette chaîne est utilisée par une commande qu'elle déclenchera peut-être un globbing. De même, une valeur comme $(wildcard *.c)ou $(shell ls *.c)n'implique aucune expansion et est complètement évaluée au moment de la définition même si nous avons utilisé:= dans la définition de variable.

Essayez le Makefile suivant dans le répertoire où vous avez des fichiers 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'exécution makedéclenchera une règle qui crée un fichier C supplémentaire (vide), appelé foo.cmais aucune des 6 variables n'a foo.cde valeur.

phs
la source
Ceci est un excellent appel et contient de nombreux exemples d'expansion au moment de la déclaration, il serait utile d'étendre la réponse avec un exemple et quelques mots pour l'expansion au moment de l'utilisation
Robert Monfera