web-dev-qa-db-fra.com

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

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 exactement les $@ et $<?

355
Mohit Deshpande

$@ est le nom du fichier en cours de génération et $< le premier prérequis (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:

  • $@ est évalué à all
  • $< est évalué à library.cpp
  • $^ est évalué à library.cpp main.cpp
428
bdonlan

Les $@ et $< s'appellent des variables automatiques . La variable $@ représente le nom du fichier créé (c'est-à-dire la cible) et $< représente le premier pré-requis requis pour créer le fichier de sortie.
Par exemple:

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

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

L'indicateur -c génère le fichier .o; voir man gcc pour une explication plus détaillée. -o spécifie le fichier de sortie à créer.

Pour plus de détails, vous pouvez lire cet article sur les Makefiles Linux .

Vous pouvez également vérifier les manuels GNU make . Cela facilitera la création de Makefiles et leur débogage.

Si vous exécutez cette commande, la base de données Makefile sera générée:

make -p 
67
dexterous_stranger

Depuis Gestion des projets avec GNU Marque, 3ème édition (sous licence de documentation libre GNU ):

Les variables automatiques sont définies par make après la mise en correspondance d'une règle. Ils fournissent un accès aux éléments des listes de cibles et prérequises, vous évitant ainsi de spécifier explicitement les noms de fichiers. Ils sont très utiles pour éviter la duplication de code, mais ils sont essentiels pour définir des règles de modèle plus générales.

Il y a sept variables automatiques "principales":

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

  • $%: L'élément filename d'une spécification de membre d'archive.

  • $<: Nom du fichier du premier préalable.

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

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

  • $+: Semblable à $^, il s'agit des noms de tous les prérequis 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 lieurs où les valeurs en double ont une signification.

  • $*: La souche du nom de fichier cible. Un radical est typiquement un nom de fichier sans son suffixe. Son utilisation en dehors des règles de modèle est découragée.

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

51
alex

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

Où:

$@ est le nom du fichier de la cible.

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

35
Eric

Le Makefile construit l'exécutable hello si l'un des main.cpp, hello.cpp, factorial.cpp change. 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é, on recompile tout le 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 objets 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 un problème d'efficacité
  • con: nouveau cauchemar de maintenance, typo potentielle sur les règles de fichiers objet

Pour améliorer cela, nous pouvons remplacer toutes les règles de fichier objet 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 à avoir un fichier makefile court, assez 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:

  • Faciliter le passage des compilateurs de g ++ à n’importe quel compilateur C++.
  • Faciliter le changement des options du compilateur.
  • Faciliter le changement 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 'all' qui agit comme une vérification rapide pour s'assurer que tous vos fichiers source sont présents avant toute tentative de création de votre application.
18
Stephen Quan

par exemple si vous voulez compiler des sources mais que les objets se trouvent dans un autre répertoire:

vous devez faire:

gcc -c -o <obj/1.o> <srcs/1.c> <obj/2.o> <srcs/2.c> ...

mais dans la plupart des cas (avec d'autres macros), le résultat sera:

gcc -c -o <all OBJ path> <all SRC path>

donc cela ne compilera rien ^^ et vous ne pourrez pas mettre les fichiers de vos objets dans un répertoire différent :(

la solution est d'utiliser ces macros spéciales

$@ $<

cela générera un fichier .o (obj/file.o) pour chaque fichier .c dans SRC (src/file.c)

$(OBJ):$(SRC)
   gcc -c -o $@ $< $(HEADERS) $(FLAGS)

ça veut dire :

    $@ = $(OBJ)
    $< = $(SRC)

mais lignes par lignes au lieu de toutes les lignes de OBJ suivi de toutes les lignes de SRC

0
Aominé