17.4. Compilation

Maintenant que le logiciel est correctement configuré, il ne reste plus qu'à le compiler. C'est une étape qui est généralement très simple à effectuer, et qui ne pose pas de problèmes majeurs.

17.4.1. make

L'outil préféré de la communauté du logiciel libre pour compiler des sources est make. L'intérêt de make est double :

Les actions à exécuter pour arriver à une version compilée des sources sont stockées dans un fichier nommé habituellement Makefile, ou GNUMakefile. En fait, lorsque make est invoqué, il lit ce fichier, s'il existe, dans le répertoire courant. Si ce n'est pas le cas, il est possible de spécifier ce fichier en passant l'option -f à make.

17.4.2. Règles

make fonctionne selon un système de dépendances. C'est-à-dire que pour qu'un binaire soit compilé (« cible  »), un certain nombre d'étapes doivent être accomplies (« dépendances  »). Par exemple, pour créer le binaire (imaginaire) glloq, on a besoin de compiler les fichiers objets (fichiers intermédiaires de la compilation) main.o et init.o, puis de les lier. Ces fichiers objets sont eux aussi des cibles, dont les dépendances sont les fichiers sources.

Ceci n'est qu'une introduction sommaire pour survivre dans le monde impitoyable de make. Si vous voulez en savoir plus, nous vous conseillons de vous rendre sur le site d'APRIL pour une documentation un peu plus détaillée sur make. Pour une documentation exhaustive, voir Managing Projects with Make (La gestion de projets avec make (seconde édition) d'Andrew Oram et Steve Talbott chez O'Reilly.

17.4.3. C'est parti!

Généralement, l'utilisation de make obéit à plusieurs conventions. Par exemple :

La première étape est de compiler le programme, et donc de taper (exemple fictif) :

$ make
gcc -c glloq.c -o glloq.o
gcc -c init.c -o init.o
gcc -c main.c -o main.o
gcc -lgtk -lgdk -lglib -lXext -lX11 -lm glloq.o init.o main.o -o glloq

Parfait ! le binaire est compilé correctement. Nous sommes prêts à passer à l'étape suivante, qui est l'installation des fichiers de la distribution (binaires, fichiers de données, etc...); (voir la section Installation).

17.4.4. Explications

Si vous avez la curiosité de regarder ce qu'il y a dans le fichier Makefile, vous y trouverez des commandes connues (rm, mv, cp, ...), mais aussi des chaînes de caractères étranges, de la forme $(CFLAGS).

Il s'agit de variables, c'est-à-dire de chaînes qui sont fixées généralement au début du fichier Makefile, et qui seront ensuite remplacées par la valeur qui leur a été associée. C'est assez pratique pour utiliser plusieurs fois de suite les mêmes options de compilation.

Par exemple, pour afficher la chaîne « toto  » à l'écran en tapant un make all :

TEST = toto
all:
        echo $(TEST)

La plupart du temps, les variables suivantes sont définies :

  1. CC : il s'agit du compilateur que l'on va utiliser. Généralement, il s'agit de gcc, mais sur la plupart des systèmes libres, le compilateur par défaut utilisé par make (soit cc) est un synonyme de cc. Dans le doute, n'hésitez pas à mettre ici gcc;

  2. LD : il s'agit du programme utilisé parfois pour assurer la phase finale de la compilation (voir la section Les quatre phases de la compilation); par défaut, la valeur est ld;

  3. CFLAGS : ce sont les arguments supplémentaires qu'on passera au compilateur lors des premières phases de la compilation. Parmi ceux-ci :

    • -I<chemin> : spécifie au compilateur où chercher des fichiers d'en-têtes supplémentaires (ex : -I/usr/X11R6/include permet d'inclure les fichiers d'en-têtes se situant dans /usr/X11R6/include);

    • -D<symbole> : définit un symbole supplémentaire, utile dans certains programmes qui se compilent différemment selon les symboles définis (ex : utilise le fichier string.h si HAVE_STRING_H est défini).

    On trouve souvent des lignes de compilation de la forme :

    $(CC) $(CFLAGS) -c toto.c -o toto.o
  4. LDFLAGS (ou LFLAGS) : ce sont les arguments passés lors de la dernière phase de la compilation. Parmi ceux-ci :

    • -L<chemin> : spécifie un chemin supplémentaire où chercher des bibliothèques (ex : -L/usr/X11R6/lib);

    • -l<bibliothèque> : spécifie une bibliothèque supplémentaire à utiliser lors de la dernière phase de compilation.

17.4.5. Et si ça ne fonctionne pas?

Pas de panique, cela arrive à tout le monde. Parmi les causes les plus communes :

  1. glloq.c:16: decl.h: No such file or directory (glloq.c:16 : decl.h : aucun fichier ou répertoire ne porte ce nom)

    Le compilateur n'a pas réussi à trouver le fichier d'en-têtes correspondant. Pourtant, l'étape de configuration du logiciel aurait dû anticiper cette erreur. Comment résoudre ce problème :

    • vérifiez que l'en-tête existe vraiment sur le disque dans un des répertoires suivants : /usr/include, /usr/local/include, /usr/X11R6/include ou un de leurs sous-répertoires. Si ce n'est pas le cas, recherchez-le sur tout le disque (avec find ou locate), et si vous ne le trouvez toujours pas, alors vérifiez à deux fois que vous avez installé la bibliothèque correspondant à cette en-tête. Vous trouverez des exemples des commandes find et locate dans leurs pages de manuel respectives;

    • vérifiez que l'en-tête est bien accessible en lecture (tapez less <chemin>/<fichier>.h pour tester cela);

    • s'il se trouve dans un répertoire comme /usr/local/include ou /usr/X11R6/include, il est parfois nécessaire de passer un argument supplémentaire au compilateur. Ouvrez le fichier Makefile correspondant (prenez garde à ouvrir le bon, celui qui se trouve dans le répertoire où la compilation échoue[1]) avec votre éditeur de textes favori (Emacs, Vi, ...). Recherchez la ligne fautive, et ajoutez la chaîne de caractères -I<path> (où <chemin> est le chemin où se trouve l'en-tête en question juste après l'appel du compilateur (gcc, ou parfois $(CC)). Si vous ne savez pas où rajouter cette option, rajoutez-la au début du fichier, à la fin de la ligne CFLAGS=<quelquechose> ou de la ligne CC=<quelquechose>;

    • exécutez make de nouveau, et si cela ne fonctionne toujours pas, vérifiez que cette option (cf point précédent) est bien ajoutée à la compilation sur la ligne fautive;

    • si cela ne fonctionne toujours pas, demandez à votre gourou local ou faites appel à la communauté du logiciel libre pour résoudre votre problème (voir la section Assistance technique).

  2. glloq.c:28: `struct toto' undeclared (first use this function) (glloq.c:28 : « struct toto  » n'est pas déclarée (ceci est la première utilisation de cette fonction))

    Les structures sont des types de données spéciaux, que tous les programmes utilisent. Beaucoup sont définies par le système dans les fichiers d'en-têtes. Ce qui signifie que le problème vient certainement d'une en-tête manquante ou mal utilisée. La marche à suivre pour résoudre le problème est la suivante :

    • tenter de vérifier si la structure en question est une structure définie dans le programme ou bien par le système. Une solution est d'utiliser la commande grep afin de vérifier si la structure est définie dans un des fichiers d'en-têtes.

      Par exemple, après vous être rendu dans la racine de la distribution :

      $ find . -name '*.h'| xargs grep 'struct toto' | less

      il est possible que plusieurs dizaines de lignes apparaissent à l'écran (à chaque fois qu'une fonction utilisant ce type de structure est définie, par exemple). Si elle existe, repérez la ligne où la structure est définie en regardant le fichier d'en-têtes obtenu par l'utilisation de grep.

      La définition d'une structure est :

      struct toto {
              <contenu de la structure>
      };

      Vérifiez si cela correspond à ce que vous avez. Si ce n'est pas le cas, c'est que ce fichier d'en-têtes n'est pas inclus dans le fichier .c fautif. Deux solutions s'offrent alors à vous :

      • ajouter la ligne #include "<nom_du_fichier>.h" au début du fichier .c fautif.

      • ou bien copier-coller la définition de la structure au début de ce fichier (ce qui n'est pas très propre, mais ça a le mérite de fonctionner, en général).

    • si ce n'est pas le cas, faites la même chose sur les fichiers d'en-têtes du système (qui se trouvent sur /usr/include, /usr/X11R6/include, ou /usr/local/include en général). Mais cette fois-ci, utilisez la ligne #include <<nom_du_fichier>.h>.

    • si cette structure n'existe toujours pas, essayez de trouver dans quelle bibliothèque (au sens d'ensemble de fonctions regroupées dans un seul paquetage), elle devrait être définie (regardez dans le fichier INSTALL ou README quelles sont les bibliothèques utilisées par le programme et la version nécessaire). Si la version que le programme nécessite n'est pas celle installée sur votre système, alors effectuez une mise à jour de cette bibliothèque ;

    • si cela ne fonctionne toujours pas, vérifiez que le programme fonctionne correctement sur votre architecture (certains programmes n'ont pas encore été portés sur tous les Unix). Vérifiez aussi que vous avez bien configuré le programme (au moment du configure, par exemple) pour votre architecture.

  3. parse error (erreur d'analyse syntaxique)

    C'est un problème assez compliqué à résoudre, car généralement il s'agit d'une erreur que le compilateur rencontre plus haut, mais qui ne se manifeste qu'à une certaine ligne. Parfois, il s'agit simplement d'un type de donnée qui n'est pas défini. Si vous rencontrez un message d'erreur de type :

    main.c:1: parse error before `glloq_t
    main.c:1: warning: data definition has no type or storage class

    alors, le problème est que le type glloq_t n'est pas défini. La solution pour résoudre ce problème est environ la même que pour le problème précédent.

    Note

    il peut y avoir une erreur de type parse error dans les vieilles bibliothèques curses si ma mémoire est bonne.

  4. no space left on device (plus de place disponible sur le périphérique)

    Le problème est assez simple à régler : la place sur le disque est insuffisante pour générer un binaire à partir du fichier source. La solution consiste à libérer de la place dans la partition abritant le répertoire d'installation: supprimez les fichiers temporaires ou les sources, désinstallez les programmes dont vous ne vous servez pas. Si vous l'avez décompacté dans /tmp, faites-le plutôt dans /usr/local/src ce qui évite de saturer inutilement la partition /tmp. Vérifiez de plus que vous n'avez pas de fichiers core[2] sur le disque. Si oui, effacez-les ou faites-les effacer s'ils appartiennent à un autre utilisateur.

  5. /usr/bin/ld: cannot open -lglloq: No such file or directory (/usr/bin/ld: je ne peux pas ouvrir -lglloq : aucun fichier ou répertoire ne porte ce nom)

    Clairement, le programme ld (utilisé par gcc lors de la dernière phase de la compilation) n'a pas réussi à trouver une bibliothèque. Il faut savoir que pour inclure une bibliothèque, ld va chercher un fichier dont le nom est passé par l'argument -l<bibliothèque>. Ce fichier porte le nom de lib<bibliothèque>.so. Si ld n'arrive pas à le trouver, alors il produit ce message d'erreur. Pour résoudre ce problème, procédons par étapes :

    1. Vérifions que ce fichier existe bien sur le disque dur, en utilisant la commande locate. Généralement, les bibliothèques graphiques se trouvent dans /usr/X11R6/lib. Par exemple :

      $ locate libglloq

      Si cela ne produit rien, vous pouvez faire une recherche avec la commande find (ex : find /usr -name libglloq.so*). Si vous ne trouvez toujours pas la bibliothèque, alors il vous reste plus qu'à l'installer.

    2. Une fois la bibliothèque localisée, vérifiez que cette bibliothèque est bien accessible pour la commande ld : le fichier /etc/ld.so.conf spécifie où trouver ces bibliothèques. Rajoutez le répertoire incriminé à la fin (il est possible que vous ayez à réinitialiser la machine pour que cela soit pris en compte). Il est aussi possible de rajouter ce répertoire en modifiant le contenu de la variable d'environnement LD_LIBRARY_PATH. Par exemple, en imaginant que le répertoire à ajouter est /usr/X11R6/lib, tapez :

      export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/X11R6/lib

      (si votre shell est bash).

    3. Si cela ne fonctionne toujours pas, vérifiez que la bibliothèque incriminée est bien au format ELF (avec la commande file). Si c'est un lien symbolique, vérifiez que ce lien est correct et ne pointe pas vers un fichier inexistant (par exemple, en tapant nm libglloq.so). Les permissions peuvent de plus être incorrectes (si vous utilisez un compte autre que root et que la bibliothèque est protégée en lecture par exemple).

  6. glloq.c(.text+0x34): undefined reference to `glloq_init' (glloq.c(.text+0x34) référence inconnue au symbole « glloq_init  »)

    Aïe! Aïe! Aïe! Pourquoi cette noirceur? Il s'agit d'un symbole non résolu lors de la dernière phase de la compilation. Généralement, il s'agit d'un problème de bibliothèque. A priori, plusieurs causes possibles :

    • la première chose à faire est de savoir si le symbole est censé être présent dans une bibliothèque. Par exemple, s'il s'agit d'un symbole commençant par gtk, il appartient très certainement à la bibliothèque gtk. Si le nom de la bibliothèque est difficilement identifiable (comme par exemple zorglub_gloubiboulga), il est possible de lister les symboles d'une bibliothèque avec la commande nm. Par exemple,

      $ nm libglloq.so
      0000000000109df0 d glloq_message_func
      000000000010a984 b glloq_msg
      0000000000008a58 t glloq_nearest_pow
      0000000000109dd8 d glloq_free_list
      0000000000109cf8 d glloq_mem_chunk

      Rajouter l'option -o à nm permet de plus d'afficher le nom de la bibliothèque sur chaque ligne, ce qui simplifie les recherches. Imaginons que nous cherchions le symbole bulgroz_max, une solution de barbare est d'effectuer une recherche de ce genre :

      $ nm /usr/lib/lib*.so | grep bulgroz_max
      $ nm /usr/X11R6/lib/lib*.so | grep bulgroz_max
      $ nm /usr/local/lib/lib*.so | grep bulgroz_max
      /usr/local/lib/libzorglub.so:000000000004d848 T bulgroz_max

      Formidable! Le symbole bulgroz_max est défini dans la bibliothèque zorglub (la lettre majuscule T se trouve devant son nom). Il suffit de rajouter la chaîne -lzorglub dans la ligne de compilation en éditant le fichier Makefile : rajoutez-la à la fin de la ligne où LDFLAGS ou LFGLAGS (ou au pire CC) sont définis, ou alors sur la ligne responsable de la création du fichier binaire final.

    • la compilation se fait avec une version de la bibliothèque qui n'est pas la même que celle prévue pour le logiciel. Lisez le fichier README ou INSTALL de la distribution pour savoir quelle version de la bibliothèque doit être utilisée.

    • tous les fichiers objets de la distribution ne sont pas correctement liés. Il manque le fichier dans lequel cette fonction est définie. Tapez nm -o *.o pour connaître son nom et ajoutez le fichier .o correspondant sur la ligne de compilation s'il est manquant.

    • la fonction ou variable incriminée est peut-être fantaisiste. Essayez de la supprimer : éditez le fichier source incriminé (son nom est spécifié au début du message d'erreur). C'est une solution désespérée, qui va avoir pour conséquence un fonctionnement très probablement anarchique du programme (erreur de segmentation au démarrage, etc.)

  7. Segmentation fault (core dumped) (erreur de segmentation, fichier core produit)

    Parfois, le compilateur échoue lamentablement et produit ce message d'erreur. Nous n'avons pas d'autre conseil que celui-ci : installez une version plus récente de votre compilateur !

  8. plus de place sur /tmp

    La compilation a besoin d'espace temporaire de travail lors de ses différentes étapes; si elle ne l'a pas, elle échoue. Il faut donc faire du ménage. Mais attention ! la suppression de certains fichiers risque de faire échouer des programmes en cours d'exécution (serveur X, tubes...). Il faut maîtriser parfaitement ce que l'on fait! Si /tmp fait partie d'une partition qui ne contient pas que lui (par exemple, la racine), recherchez et supprimez d'éventuels fichiers core.

  9. make/configure en boucle

    Il s'agit généralement d'un problème d'heure sur votre système. make a en effet besoin de connaître la date et l'heure ainsi que celles des fichiers qu'il vérifie. Il compare les dates des fichiers et utilise le résultat pour savoir si la cible est plus récente que la dépendance.

    Il se peut que des problèmes de date amènent make à se reconstruire sans fin (ou de construire et reconstruire un arborescence en boucle). Dans ce cas-là, l'utilisation de la commande touch (qui a pour conséquence de mettre à l'heure courante les fichiers passés en argument) permet de résoudre le problème dans la plupart des cas.

    Par exemple :

    $ touch *

    Ou encore plus barbare (mais efficace) :

    $ find . | xargs touch

 

 

 

Notes

[1]

Analysez le message d'erreur renvoyé par make. Normalement, les dernières lignes devraient contenir un répertoire (un message de la forme make[1] : Leaving directory `/home/benj/Projet/toto'). Repérez celle dont le numéro est le plus grand. Pour vérifier qu'il s'agit bien du bon répertoire, rendez-vous dans ce répertoire, et exécutez make à nouveau pour obtenir la même erreur.

[2]

Fichiers expectorés par le système quand un processus tente d'accéder à une partie de la mémoire qui lui est interdite, et qui servent à analyser la raison de ce comportement pour corriger le programme fautif. Littéralement, trognon !


Tux sur Étoile de MandrakeSoft Linux est une marque déposée de Linus Torvalds. Toutes les autres marques et copyrights sont la propriété de leurs auteurs respectifs.
Sauf mention contraire, tout le contenu de ces pages et toutes les images sont Copyright MandrakeSoft S.A. et MandrakeSoft Inc. 2001.
http://www.mandrakelinux.com/