Que signifient les symboles de makefile $ @ et $ <?

CC=g++ CFLAGS=-c -Wall LDFLAGS= SOURCES=main.cpp hello.cpp factorial.cpp OBJECTS=$(SOURCES:.cpp=.o) EXECUTABLE=hello all: $(SOURCES) $(EXECUTABLE) $(EXECUTABLE): $(OBJECTS) $(CC) $(LDFLAGS) $(OBJECTS) -o $@ .cpp.o: $(CC) $(CFLAGS) $< -o $@ 

Que font les $@ et $< exactement?

$@ est le nom du fichier en cours de création et $< le premier prérequirejs (généralement le fichier source). Vous pouvez trouver une liste de toutes ces variables spéciales dans le manuel GNU Make .

Par exemple, considérons la déclaration suivante:

 all: library.cpp main.cpp 

Dans ce cas:

  • $@ évalue à all
  • $< évalue à library.cpp
  • $^ évalue à library.cpp main.cpp

Les $@ et $< sont appelés les variables automatiques. Le $@ est la variable de sortie. $< est la première variable d'entrée. Par exemple:

 hello.o: hello.c hello.h gcc -c $< -o $@ 

Ici, hello.o est le fichier de sortie. C'est à quoi $@ développe. La première dépendance est hello.c . C'est ce que $< étend à.

L'indicateur -c génère le fichier .o ; voir man gcc pour une explication plus détaillée. Le -o spécifie le fichier vers lequel sortir.

Pour plus de détails, vous pouvez lire ceci .

Vous pouvez également consulter les manuels GNU. Il existe un moyen de déboguer votre makefile pour mieux le comprendre.

Cela va sortir la firebase database makefile:

 $make -p 

Les $@ et $< sont des macros spéciales.

Où:

$@ est le nom de fichier de la cible.

$< est le nom de la première dépendance.

De la gestion de projets avec GNU Make, 3ème édition (c’est sous GNU Free Documentation License ):

Les variables automatiques sont définies par make après la correspondance d’une règle. Ils permettent d’accéder aux éléments des listes de cibles et de prérequirejs, ce qui vous évite de spécifier explicitement des noms de fichiers. Ils sont très utiles pour éviter la duplication de code, mais sont critiques lors de la définition de règles plus générales.

Il y a sept variables automatiques «de base»:

  • $@ : Le nom de fichier représentant la cible.

  • $% : Élément de nom de fichier d’une spécification de membre d’archive.

  • $< : Le nom de fichier du premier prérequirejs.

  • $? : Les noms de tous les prérequirejs plus récents que la cible, séparés par des espaces.

  • $^ : Les noms de fichiers de tous les prérequirejs, séparés par des espaces. Cette liste a des noms de fichiers en double supprimés car pour la plupart des utilisations, telles que la compilation, la copie, etc., les doublons ne sont pas souhaités.

  • $+ : Similaire à $^ , il s'agit des noms de tous les prérequirejs séparés par des espaces, sauf que $+ inclut les doublons. Cette variable a été créée pour des situations spécifiques telles que des arguments pour des éditeurs de liens où les valeurs en double ont un sens.

  • $* : La racine du nom de fichier cible. Une tige est généralement un nom de fichier sans son suffixe. Son utilisation en dehors des règles de motif est déconseillée.

De plus, chacune des variables ci-dessus a deux variantes pour la compatibilité avec d’autres marques. Une variante renvoie uniquement la partie répertoire de la valeur. Ceci est indiqué en ajoutant un «D» au symbole, $(@D) , $( , etc. L'autre variante ne renvoie que la partie fichier de la valeur. Ceci est indiqué en ajoutant un «F» au symbole, $(@F) , $( , etc. Notez que ces noms de variantes ont plus d'un caractère et doivent donc être placés entre parenthèses. GNU make fournit une alternative plus lisible avec les fonctions dir et notdir.

Le Makefile construit le fichier exécutable hello si l’un des main.cpp , hello.cpp , factorial.cpp modifié. Le plus petit Makefile possible pour atteindre cette spécification aurait pu être:

 hello: main.cpp hello.cpp factorial.cpp g++ -o hello main.cpp hello.cpp factorial.cpp 
  • pro: très facile à lire
  • con: cauchemar de maintenance, duplication des dépendances C ++
  • con: problème d’efficacité, nous recompilons tout C ++ même si un seul a été changé

Pour améliorer ce qui précède, nous ne compilons que les fichiers C ++ qui ont été modifiés. Ensuite, nous lions simplement les fichiers d’object résultants ensemble.

 OBJECTS=main.o hello.o factorial.o hello: $(OBJECTS) g++ -o hello $(OBJECTS) main.o: main.cpp g++ -c main.cpp hello.o: hello.cpp g++ -c hello.cpp factorial.o: factorial.cpp g++ -c factorial.cpp 
  • pro: corrige le problème d’efficacité
  • con: nouveau cauchemar de maintenance, typo potentielle sur les règles de fichiers object

Pour améliorer cela, nous pouvons remplacer toutes les règles de fichier object par une seule règle .cpp.o :

 OBJECTS=main.o hello.o factorial.o hello: $(OBJECTS) g++ -o hello $(OBJECTS) .cpp.o: g++ -c $< -o $@ 
  • pro: retour à un makefile court, un peu facile à lire

Ici, la règle .cpp.o définit comment construire anyfile.o partir de anyfile.cpp .

  • $< correspond à la première dépendance, dans ce cas, anyfile.cpp
  • $@ correspond à la cible, dans ce cas, anyfile.o .

Les autres modifications présentes dans le Makefile sont les suivantes:

  • Rendre plus facile le changement des compilateurs de g ++ à n'importe quel compilateur C ++.
  • Faciliter la modification des options du compilateur.
  • Faciliter la modification des options de l'éditeur de liens.
  • Faciliter la modification des fichiers source et de la sortie C ++.
  • Ajout d'une règle par défaut «tous» qui sert à vérifier rapidement que tous vos fichiers sources sont présents avant toute tentative de création de votre application.