Obligement - L'Amiga au maximum

Samedi 31 mai 2025 - 15:13  

Translate

En De Nl Nl
Es Pt It Nl


Rubriques

Actualité (récente)
Actualité (archive)
Comparatifs
Dossiers
Entrevues
Matériel (tests)
Matériel (bidouilles)
Points de vue
En pratique
Programmation
Reportages
Quizz
Tests de jeux
Tests de logiciels
Tests de compilations
Trucs et astuces
Articles divers

Articles in English


Réseaux sociaux

Suivez-nous sur X




Liste des jeux Amiga

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z,
ALL


Trucs et astuces

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Glossaire

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Galeries

Menu des galeries

BD d'Amiga Spécial
Caricatures Dudai
Caricatures Jet d'ail
Diagrammes de Jay Miner
Images insolites
Fin de jeux (de A à E)
Fin de Jeux (de F à O)
Fin de jeux (de P à Z)
Galerie de Mike Dafunk
Logos d'Obligement
Pubs pour matériels
Systèmes d'exploitation
Trombinoscope Alchimie 7
Vidéos


Téléchargement

Documents
Jeux
Logiciels
Magazines
Divers


Liens

Associations
Jeux
Logiciels
Matériel
Magazines et médias
Pages personnelles
Réparateurs
Revendeurs
Scène démo
Sites de téléchargement
Divers


Partenaires

Annuaire Amiga

Amedia Computer

Relec


A Propos

A propos d'Obligement

A Propos


Contact

David Brunet

Courriel

 


Programmation : Introduction aux makefiles
(Article écrit par l'équipe de GuruMed et extrait de GuruMed.net - décembre 2003)


Le problème

Tant qu'on écrit de petits programmes qui se compilent vite, on peut se contenter d'un unique fichier source par programme, et taper une ligne de commande dans le Shell pour les compiler. Cependant, plus les programmes deviennent grands et complexes, plus il devient important de séparer ses sources en plusieurs fichiers afin de les clarifier, éventuellement permettre la réutilisation de certaines parties telles-quelles dans d'autres projets, et diminuer les temps de compilation. Un besoin d'automatisation se fait alors sentir pour ne pas avoir à taper une ligne de commande par fichier.

La solution

Si vous utilisez un IDE comme StormC, ce problème ne devrait pas se poser car l'IDE s'occupe de tout (ou presque). Avec un compilateur en ligne de commande comme GCC ou vbcc, vous pouvez utiliser la commande "make" pour exécuter des fichiers makefiles automatisant la compilation de votre projet. En plus de n'avoir qu'une ligne à taper dans le Shell pour construire l'exécutable, cela permet de ne compiler que les fichiers source ayant été modifiés depuis la dernière compilation, ce qui diminue grandement le temps de compilation sur les gros projets.

Les outils

Il existe différentes variantes de make, dont notamment smake (livré avec SAS/C), dmake (livré avec DICE C), GNU make version GeekGadgets et d'autres portages de ce même GNU make pour Amiga que l'on peut trouver sur Aminet.

Je ne parlerai pas de smake et dmake qui ont leur propre syntaxe, et sont peu utilisés (ou presque introuvable légalement en ce qui concerne smake).

Deux versions de GNU make seront abordées :
La version de GeekGadgets a besoin de l'ixemul.library, mais pas celle d'Aminet. D'autres différences entre ces deux versions de make seront mentionnées un peu plus bas.

Le contenu d'un makefile

Ce qu'il faut mettre dans un makefile dépend grandement de votre projet. Un makefile peut servir à bien d'autres choses que la compilation d'un programme ! Mais nous n'en parlerons pas ici :-). Commençons par réaliser un makefile très simple destiné à compiler un programme composé de trois fichiers source.

Voici les fichiers source :

toto.c

#include "titi.h"

int main( void )
{
	ma_jolie_fonction();
	return 0;
}

titi.c

#include <stdio.h>
#include "titi.h"

void ma_jolie_fonction( void )
{
	puts("bonjour");
}

titi.h

void ma_jolie_fonction( void );

Si vous vous demandez la raison de l'inclusion de "titi.h" dans "titi.c", sachez que c'est pour être sûr que le prototype de "ma_jolie_fonction()" se trouvant dans le ".h" est bien conforme à la définition de la fonction dans le ".c". En effet, il arrive parfois que l'on modifie les paramètres d'une fonction dans un fichier en oubliant de les modifier dans l'autre...

Et voici le makefile correspondant :

# makefile pour créer programme_executable
# à partir de toto.c et titi.c

programme_executable : toto.o titi.o
	vc -o programme_executable toto.o titi.o

toto.o : toto.c titi.h
	vc -c -o toto.o toto.c

titi.o : titi.c titi.h
	vc -c -o titi.o titi.c

Les "#" servent aux commentaires. Pour le reste, nous avons ici trois règles. Les règles sont la base d'un makefile. Elles sont de la forme :

cible(s) : dépendance(s)

	commande

	...

Une cible est souvent le nom d'un fichier à générer, comme ici "programme_executable", "toto.o" et "titi.o" ; cependant, il peut aussi s'agir du simple nom d'une action à effectuer. Nous verrons cela par la suite.

Une dépendance est le nom d'un fichier dont dépend la cible de cette règle. Si la cible est un fichier, alors la règle ne sera exécutée que si une des dépendances est plus récente que la cible. Par exemple, ici, la première règle ne sera exécutée que si "toto.o" ou "titi.o" ont une date plus récente que "programme_executable".

Quant aux commandes, il s'agit simplement de commandes telles qu'on pourrait les taper dans un Shell AmigaDOS. Il peut y avoir plusieurs commandes par règle, sur plusieurs lignes consécutives, tout comme il peut n'y avoir aucune commande.

Attention : les lignes de commande doivent commencer par une tabulation (et pas par des espaces !). Pensez-y si vous utilisez un vieil éditeur de texte pourri comme GoldEd 5. ;-)

Différences entre le make de GeekGadgets et celui d'Aminet : le make de GeekGadgets lance chaque commande dans un Shell Unix "sh", tandis que le portage disponible sur Aminet utilise un Shell AmigaDOS normal. En pratique, cela a surtout une influence sur l'utilisation des jokers. Si vous voulez par exemple lancer la commande suivante :

	delete #?.o

...il n'y aura pas de problème avec le make d'Aminet ; mais cela ne marchera pas avec celui de GeekGadgets. Pour ce dernier, il vous faudra écrire :

	delete \#\?.o

De plus, le make de GeekGadgets ne reconnaît pas les chemins d'accès du type "VOLUME:chemin". Il faut écrire "/VOLUME/chemin", et ceci aussi bien dans les cibles que les dépendances et les commandes.

Les règles en détail

Examinons maintenant une par une les règles de notre makefile :

programme_executable : toto.o titi.o

	vc -o programme_executable toto.o titi.o

Cette règle dit à make comment générer la cible "programme_executable". Les dépendances étant "toto.o" et "titi.o", la commande ne sera exécutée que si au moins un de ces deux fichiers est plus récent que "programme_executable", ou bien sûr si ce dernier n'existe pas encore.

Quant à la commande, c'est un simple appel à vc (l'interface de vbcc) servant à lier "toto.o" avec "titi.o" pour former l'exécutable.

Passons à la deuxième règle :

toto.o : toto.c titi.h

	vc -c -o toto.o toto.c

Celle-ci décrit la façon de générer "toto.o". Elle sera déclenchée si "toto.c" ou "titi.h" sont plus récents que "toto.o", c'est-à-dire si les fichiers source ont été modifiés depuis la dernière compilation. C'est très intéressant car cela signifie que seuls les fichiers modifiés seront recompilés, évitant par là une grosse perte de temps.

Puisque le fichier "toto.c" inclut "titi.h", "toto.o" peut changer si l'un ou l'autre de ces fichiers source a été modifié. C'est pourquoi ils sont tous deux dans les dépendances.

La commande "vc -c -o toto.o toto.c" crée "toto.o" à partir de "toto.c". Le "-c" dit à vbcc de ne pas générer d'exécutable, mais au contraire de juste générer le fichier objet (GCC fonctionne pareil).

La troisième et dernière règle est identique à celle que nous venons de voir, hormis les noms de fichiers qui diffèrent.

Vous pouvez essayer ce makefile en tapant tout simplement "make" dans un Shell, en étant bien sûr dans le répertoire où se trouvent le makefile et les différents fichiers source. make devrait lancer la compilation de "toto.o", puis de "titi.o", puis finalement le lien de ces deux fichiers pour obtenir "programme_executable".

Améliorations

Ce makefile est parfaitement fonctionnel, mais il a néanmoins plusieurs défauts :
  • Il ne fonctionne qu'avec vbcc, et le passer à un autre compilateur demande de changer plusieurs lignes de commande.
  • Il y a des répétitions. Si on change le nom d'une cible, il faut aussi le changer dans la ligne de commande associée. Pareil pour une dépendance.
  • De même, chaque fichier objet ("toto.o", "titi.o") est généré par une ligne de commande similaire aux autres fichiers objets (seuls les noms de fichier changent). Pourtant, on est obligé de la réécrire pour chaque fichier.
Ces défauts ne sont pas vraiment importants pour un aussi petit makefile, mais ils deviendraient gênants lors d'un travail sur un projet de dizaines de fichiers source.

Nous allons améliorer ce makefile en utilisant des variables et une règle dite "de motif" ("pattern rule" en anglais).

# makefile pour créer programme_executable
# à partir de toto.c et titi.c

CC = vc

programme_executable : toto.o titi.o
	$(CC) -o $@ $^

%.o : %.c
	$(CC) -c -o $@ $<

toto.o : toto.c titi.h
titi.o : titi.c titi.h

La première variable rajoutée ici est CC. C'est la variable standard utilisée pour représenter le nom du compilateur. Nous lui donnons donc tout naturellement la valeur "vc" pour utiliser vbcc.

Pour ensuite utiliser cette variable, nous écrirons "$(CC)". Chaque occurrence de "$(CC)" sera remplacée par "vc".

Passons à la première règle :

programme_executable : toto.o titi.o

	$(CC) -o $@ $^

La cible et les dépendances n'ont pas changé ; par contre, la ligne de commande utilise maintenant trois variables. Nous avons déjà vu "$(CC)". Les deux autres, "$@" et "$^", sont des variables dites automatiques car elles sont créées automatiquement par make.

"$@" va tout simplement être remplacé par la cible de la règle en cours (ici, "programme_executable").

"$^" va elle être remplacé par toutes les dépendances (ici, "toto.o titi.o").

Cette ligne est donc équivalente à :

	vc -o programme_executable toto.o titi.o

La deuxième règle introduit la notion de règle implicite :

%.o : %.c

	vc -c -o $@ $<

Cette règle (de type règle de motif ou "pattern rule") définit une règle implicite disant à make comment créer un fichier ".o" à partir de son ".c" correspondant.

Nous avons déjà vu la variable automatique "$@", qui sera remplacée par la cible, c'est-à-dire ici le fichier ".o".

"$<" est aussi une variable automatique, et sera elle remplacée par la première dépendance, c'est-à-dire le fichier ".c".

Les deux règles suivantes sont les mêmes que dans la première version du makefile, mais sans les commandes associées :

toto.o : toto.c titi.h

titi.o : titi.c titi.h

En l'absence de commande spécifique, make va utiliser la règle implicite que nous venons de définir. Ces deux règles couplées à la règle de motif donnent donc un résultat identique aux deux dernières règles du premier makefile.

Avec ce nouveau makefile, vous pouvez :
  • Changer de compilateur en modifiant une seule ligne ("CC = gcc").
  • Ajouter un fichier objet en ajoutant une seule ligne ("objet : dépendances").
A propos des dépendances, il peut être assez fastidieux de les maintenir quand on commence à avoir de nombreux fichiers source. Vous pourrez alors utiliser un outil pour les générer automatiquement. Si vous utilisez GCC, vous pouvez vous en servir avec l'option "-M". Sinon, LFMakeMaker de Laurent Faillie fera l'affaire (sur Aminet). Tapez simplement "LFMakeMaker #?.c" dans le Shell pour avoir vos dépendances.

Nettoyage

Une cible "clean" est généralement incluse dans un makefile pour effacer tous les fichiers objet, afin de forcer la recompilation de tout le projet :

clean :

	delete #?.o

(attention, vous devez écrire "\#\?.o" si vous utilisez le make de GeekGadgets)

Comme vous pouvez le constater, une règle n'a pas forcément de dépendance, et sa cible n'est pas forcément un nom de fichier.

Pour exécuter cette règle, vous n'avez qu'à taper "make clean" dans le Shell (en l'absence d'argument, make exécute par défaut la première règle du makefile).

Le mot de la fin

Cette introduction devrait vous avoir appris le nécessaire pour faire des makefiles basiques, permettant de compiler des programmes composés de nombreux fichiers source sans souci.

Il reste cependant de nombreuses possibilités d'extension : faire un makefile qui gère plusieurs compilateurs, des options de compilation différentes (avec ou sans débogage, pour 68k ou PowerPC...), la création de l'archive lha contenant votre programme et sa documentation, etc.

Si le besoin s'en fait sentir, un deuxième article sur les makefiles pourrait voir le jour ; mais en attendant vous pouvez examiner les makefiles qui vous passeront sous les yeux et consulter la documentation AmigaGuide fournie avec le make de GeekGadgets pour plus de précisions.


[Retour en haut] / [Retour aux articles]