861 votes

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

Quelqu'un peut-il donner une explication claire de la façon dont l'affectation des variables fonctionne réellement dans Makefiles.

Quelle est la différence entre :

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

J'ai lu le section dans le manuel de GNU Make, mais ça n'a toujours pas de sens pour moi.

1143voto

Alnitak Points 143355

Ensemble paresseux

VARIABLE = value

Paramétrage normal d'une variable, mais toute autre variable mentionnée avec le symbole value sont développés récursivement avec leur valeur au moment où la variable est utilisée, et non celle qu'elle avait au moment de sa déclaration.

Ensemble immédiat

VARIABLE := value

Définition d'une variable avec expansion simple des valeurs qu'elle contient - les valeurs qu'elle contient sont étendues au moment de la déclaration.

Lazy Set If Absent

VARIABLE ?= value

Paramétrage d'une variable uniquement si elle n'a pas de valeur. value est toujours évalué lorsque VARIABLE est accessible. Il est équivalent à

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

Voir le documentation pour plus de détails.

Ajouter

VARIABLE += value

Ajout de la valeur fournie à la valeur existante (ou mise à cette valeur si la variable n'existe pas).

28 votes

Est-ce que A += B développe B ? C'est-à-dire que si je fais A += B, puis B += C, est-ce que A est évalué comme la concaténation de ${B} et ${C} ?

18 votes

Comme le dit la section liée du manuel. += opère selon la sémantique simple ou récursive de l'affectation originale. Donc, oui, il développera le RHS mais le fait qu'il le fasse immédiatement ou de manière différée dépend du type de la variable sur le LHS.

6 votes

Que voulez-vous dire quand vous dites que la valeur de la variable est étendue ?

301voto

strager Points 41713

Utilisation de = fait en sorte qu'une valeur soit attribuée à la variable. Si la variable avait déjà une valeur, celle-ci est remplacée. Cette valeur sera développée lorsqu'elle sera utilisée. Par exemple :

HELLO = world
HELLO_WORLD = $(HELLO) world!

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

HELLO = hello

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

Utilisation de := est similaire à l'utilisation de = . Cependant, au lieu que la valeur soit développée lorsqu'elle est utilisée, elle est développée pendant 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)

Utilisation de ?= attribue une valeur à la variable si la variable n'a pas été précédemment assignée. Si la variable a été précédemment assignée à une valeur vide ( VAR= ), il est toujours considéré comme un ensemble Je pense . Sinon, des fonctions exactement comme = .

Utilisation de += 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 := il est étendu Je pense . La valeur résultante est étendue 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 comme HELLO_WORLD = $(HELLO_WORLD) world! était utilisé, une récursion en résulterait, ce qui mettrait très probablement fin à l'exécution de votre Makefile. Si A := $(A) $(B) était utilisé, le résultat ne serait pas exactement le même qu'en utilisant += parce que B est élargi avec := alors que += ne causerait pas B à développer.

5 votes

une conséquence de cela est donc VARIABLE = literal et VARIABLE := literal sont toujours équivalentes. Est-ce que j'ai bien compris ?

3 votes

@aiao, oui, car les littéraux sont invariants par rapport à leur utilisation.

0 votes

Une différence subtile est :- ? : peut améliorer les performances dans les makefiles récursifs appelés. Par exemple, si $ ? = $(shell quelque_commande_qui_exécute_long_temps). Dans les appels récursifs, cette commande ne sera évaluée qu'une seule fois, ce qui améliorera les performances de la compilation. := sera plus lent car la commande sera exécutée inutilement plusieurs fois.

75voto

nickand Points 59

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 des empreintes :

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

Pour une explication plus détaillée, cliquez ici.

5 votes

Il serait préférable d'utiliser un @ devant chaque recette pour éviter cette répétition confuse de résultats.

4 votes

Make ne prend pas en charge /* ... */ commentaire de bloc

34voto

mipadi Points 135410

Lorsque vous utilisez VARIABLE = value si value est en fait une référence à une autre variable, alors la valeur n'est déterminée que quand VARIABLE est utilisé. La meilleure façon d'illustrer ce point est de prendre 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 tel qu'il est maintenant . Par exemple :

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

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

Utilisation de VARIABLE ?= val signifie que vous ne définissez que la valeur de VARIABLE si VARIABLE n'est pas déjà défini. Si elle n'est pas déjà définie, la définition de la valeur est reportée jusqu'à ce que VARIABLE est utilisé (comme dans l'exemple 1).

VARIABLE += value ajoute simplement value à VARIABLE . La valeur réelle de value est déterminé comme il l'était lorsqu'il a été initialement défini, en utilisant l'une des deux méthodes suivantes = ou := .

0 votes

En fait, dans votre premier exemple, VARIABLE est $(VAL) et VAL est bar. VARIABLE se développe lorsqu'il est utilisé.

1 votes

Oui, les commentaires expliquent ce qui se passerait s'ils étaient utilisés.

0 votes

Ah ; je suppose que vous l'avez corrigé, ou j'ai mal interprété "évaluer" comme "être".

10voto

phs Points 254

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

Essayez le Makefile suivant dans le répertoire où vous avez quelques 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

Running make va déclencher une règle qui crée un fichier C supplémentaire (vide), appelé foo.c mais aucune des 6 variables n'a foo.c dans sa valeur.

0 votes

C'est un excellent appel et il y a beaucoup d'exemples pour l'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.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X