make sans Makefile, utilisation des règles implicites

Article suivant: Utilisation de swap et des fonctions utilitaires en général
Article précédent: Optimisation de script bash en limitant l'ouverture de processus

La commande GNU make possède énormément de commandes implicites regroupées dans un Makefile “par défaut” avec plein de règles. Celui-ci est visible en tapant make -pf /dev/null dans un terminal.

Rien qu’avec ça, on peut compiler des fichiers C, C++, archive, latex, etc. Il y a de quoi faire en fait.

Par exemple, je crée un fichier C nommé test.c:

int main(int ac, char** av)
{
  return ac;
}

Que je compile avec make test pour créer l’exécutable test. Mais si on veut avoir des fichiers objets, il faut le demander explicitement: make test.o test.

Maintenant, on remplace test.c par test.cpp et on inclut <iostream>.

La compilation se fait encore avec make test ou make test.o test pour avoir les fichiers objets.

Ah ! En fait non, le second ne fonctionne pas. test.o est compilé avec cc, et comme <iostream> est linké avec une lib, l’implémentation du constructeur std::ios_base::Init n’est pas trouvée. L’idéal serait d’utiliser g++ ou un autre compilateur C++ pour avoir les chemins de bibliothèque convenablement configurés.

Si ce n’est qu’une question de compilateur, changeons-le !

Tout d’abord, la règle de compilation d’un .o vers un exécutable:

make -pf/dev/null | grep '%: %.o' -A3
%: %.o
#  commands to execute (built-in):
        $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@

Cela utilise pour compiler la variable LINK.o. Soit, qu’est sa valeur ?

make -pf/dev/null | grep 'LINK.o ='
LINK.o = $(CC) $(LDFLAGS) $(TARGET_ARCH)

Qui fait référence à CC. On s’approche, vérifions:

make -pf/dev/null | grep 'CC ='
CC = cc

Bingo \o/. Il suffit donc de changer la valeur de CC.

On recommence avec make CC=g++ test.o test et ça fonctionne :).

Cette petite excursion permet mine de rien de découvrir pas mal de variables. Au passage, il est plus intéressant de les utiliser que d’en recréer des nouvelles. Idem dans les règles de dépendances. S’il faut les personnaliser, autant garder les mêmes commandes à exécuter.

Par exemple, pour compiler un .cpp en .o:

%.o: %.cpp
#  commands to execute (built-in):
        $(COMPILE.cpp) $(OUTPUT_OPTION) $&lt;

Généralement les sources sont également dépendantes de fichier d’en-tête. Si on fait une règle qui prend en compte cela, autant garder la même commande: (petite parenthèse pour dire que gcc possède l’option -MM pour lister les dépendances entre les fichiers.)

bidule.o: bidule.cpp bidule.h machin.h
        $(COMPILE.cpp) $(OUTPUT_OPTION) $&lt;

Ainsi, quand CXXFLAGS sera modifié, la règle le prendra en compte car

COMPILE.cpp = COMPILE.cc

Et

COMPILE.cc = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c

À noter que la variable CPPFLAGS fait référence à la commande cpp (ou option -E de gcc) et concerne le C-preprocessor.

Bien sûr, la technique du Makefile seul a des limites. Par exemple, s’il y a plusieurs fichiers C, je peux créer tous les fichiers objets avec make *.o, mais l’exécutable ne sera dépendant que d’un fichier. Au final les règles par défaut ne permettront pas de créer l’exécutable, il faudra faire gcc *.o ou un Makefile avec au minimum a.out: *.o.

Voilà, ce fut un petit post pour découvrir l’existence des règles implicites et des variables prédéfinies :).

Manual de make

Commentaires

Aucun commentaire pour le moment :'(

Le système de commentaire passe par les issues de github et aucun n'est associée au billet. Vous pouvez faire votre commentaire dans une issue qui a comme titre celui du billet. Je me chargerai de les associer.

Revenir en haut