13.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.

13.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.

13.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.

13.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).

13.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.

13.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 :

  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 systèmes 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 :

  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 !