Recherche de site Web

Une brève introduction aux « Makefiles » dans le développement de logiciels Open Source avec GNU Make


GNU Make est un utilitaire de développement qui détermine les parties d'une base de code particulière qui doivent être recompilées et peut émettre des commandes pour effectuer ces opérations sur la base de code. Cet utilitaire make particulier peut être utilisé avec n'importe quel langage de programmation à condition que sa compilation puisse être effectuée à partir du shell en émettant des commandes.

Afin d'utiliser GNU Make, nous avons besoin d'un ensemble de règles qui définissent la relation entre les différents fichiers de notre programme et des commandes pour mettre à jour chaque fichier. Ceux-ci sont écrits dans un fichier spécial appelé « makefile ». La commande 'make' utilise la base de données 'makefile' et les dernières heures de modification des fichiers pour décider dont tous les fichiers doivent être recompilés à nouveau.

Contenu d'un Makefile

Généralement, les « makefiles » contiennent 5 types de choses, à savoir : des règles implicites, des règles explicites et des définitions de variables. , directives et commentaires.

  1. Une règle explicite spécifie comment créer/refaire un ou plusieurs fichiers (appelés cibles, sera expliqué plus tard) et quand faire de même.
  2. Une règle implicite précise comment créer/refaire un ou plusieurs fichiers en fonction de leurs noms. Il décrit comment un nom de fichier cible est lié à un fichier portant un nom similaire à celui de la cible.
  3. Une définition de variable est une ligne qui spécifie une valeur de chaîne pour une variable à remplacer ultérieurement.
  4. Une directive est une instruction permettant à make de faire quelque chose de spécial lors de la lecture du makefile.
  5. Un symbole '#' est utilisé pour représenter le début d'un commentaire dans les makefiles . Une ligne commençant par « # » est simplement ignorée.

Structure des Makefiles

Les informations qui indiquent à make comment recompiler un système proviennent de la lecture d'une base de données appelée makefile. Un simple makefile sera constitué de règles de la syntaxe suivante :

target ... : prerequisites ... 
	recipe 
... 
...

Une cible est définie comme étant le fichier de sortie généré par le programme. Il peut également s'agir de cibles bidons, ce qui sera expliqué ci-dessous. Des exemples de fichiers cibles incluent des exécutables, des fichiers objets ou des cibles factices comme clean, installer, désinstaller etc.

Un prérequis est un fichier utilisé comme entrée pour créer les fichiers cibles.

Une recette est l'action que make effectue pour créer le fichier cible en fonction des prérequis. Il est nécessaire de mettre un caractère de tabulation avant chaque recette dans les makefiles sauf si nous spécifions la variable '.RECIPEPREFIX' pour définir un autre caractère comme préfixe. à la recette.

Un exemple de Makefile

final: main.o end.o inter.o start.o
	gcc -o final main.o end.o inter.o start.o
main.o: main.c global.h
	gcc -c main.c
end.o: end.c local.h global.h
	gcc -c end.c
inter.o: inter.c global.h
	gcc -c inter.c
start.o: start.c global.h
	gcc -c start.c
clean:
	rm -f main.o end.o inter.o start.o

Dans l'exemple ci-dessus, nous avons utilisé des fichiers sources 4 C et deux fichiers d'en-tête pour créer l'exécutable final. Ici, chaque fichier « .o » est à la fois une cible et un prérequis dans le makefile. Jetez maintenant un œil au dernier nom de la cible clean. Il s'agit simplement d'une action plutôt que d'un fichier cible.

Puisque nous n’en avons normalement pas besoin lors de la compilation, cela n’est écrit comme condition préalable dans aucune autre règle. Les cibles qui ne font pas référence à des fichiers mais sont simplement des actions sont appelées cibles factices. Ils n’auront aucun prérequis comme les autres fichiers cibles.

Comment GNU Make traite un Makefile

Par défaut, make commence par la première cible du 'makefile' et est appelé ' objectif par défaut'. En considérant notre exemple, nous avons final comme première cible. Étant donné que ses prérequis incluent d'autres fichiers objets, ceux-ci doivent être mis à jour avant de créer le final. Chacun de ces prérequis est traité selon ses propres règles.

La recompilation se produit si des modifications sont apportées aux fichiers sources ou aux fichiers d'en-tête ou si le fichier objet n'existe pas du tout. Après avoir recompilé les fichiers objets nécessaires, make décide s'il faut relier final ou non. Cela doit être fait si le fichier final n'existe pas, ou si l'un des fichiers objets est plus récent que lui.

Ainsi, si nous modifions le fichier inter.c, alors en exécutant make, il recompilera le fichier source pour le mettre à jour. le fichier objet inter.o puis le lien final.

Utiliser des variables dans les Makefiles

Dans notre exemple, nous avons dû lister tous les fichiers objets deux fois dans la règle finale comme indiqué ci-dessous.

final: main.o end.o inter.o start.o
	gcc -o final main.o end.o inter.o start.o

Afin d'éviter de telles duplications, nous pouvons introduire des variables pour stocker la liste des fichiers objets utilisés dans le makefile. En utilisant la variable OBJ, nous pouvons réécrire l'exemple de makefile en un exemple similaire présenté ci-dessous.

OBJ = main.o end.o inter.o start.o
final: $(OBJ)
	gcc -o final $(OBJ)
main.o: main.c global.h
	gcc -c main.c
end.o: end.c local.h global.h
	gcc -c end.c
inter.o: inter.c global.h
	gcc -c inter.c
start.o: start.c global.h
	gcc -c start.c
clean:
	rm -f $(OBJ)

Règles de nettoyage du répertoire source

Comme nous l'avons vu dans l'exemple makefile, nous pouvons définir des règles pour nettoyer le répertoire source en supprimant les fichiers objets indésirables après la compilation. Supposons que nous ayons un fichier cible appelé clean. Comment faire peut-il différencier les deux situations ci-dessus ? Voici le concept de cibles factices.

Une cible factice n'est pas vraiment le nom d'un fichier, mais plutôt le nom d'une recette à exécuter chaque fois qu'une requête explicite est faite à partir du makefile<.. L'une des principales raisons d'utiliser phony target est d'éviter un conflit avec un fichier du même nom. Une autre raison est d'améliorer les performances.

Pour expliquer cette chose, je vais révéler une tournure inattendue. La recette pour clean ne sera pas exécutée par défaut lors de l'exécution de make. Au lieu de cela, il est nécessaire de l'invoquer en émettant la commande make clean.

.PHONY: clean
clean:
	rm -f $(OBJ)

Essayez maintenant de créer des makefiles pour votre propre base de code. N'hésitez pas à commenter ici avec vos doutes.