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.
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 :
il permet au développeur de gagner du temps, car il présente des avantages permettant de gérer la compilation de son projet de manière efficace,
il permet à l'utilisateur final de compiler et d'installer le logiciel en quelques lignes de commande, et ceci sans connaissance préalable du développement.
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.
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' et chez O'Reilly.
Généralement, l'utilisation de make obéit à plusieurs conventions. Par exemple :
make sans argument exécute la compilation seule du programme, sans l'installer;
make install compile le programme (mais pas toujours) et
assure l'installation des fichiers nécessaires à la bonne place sur le
système de fichiers. Certains fichiers ne sont pas toujours installés
correctement (man
, info
), il faut alors les
copier à la main. Dans certains cas, il faut effectuer une nouvelle
fois un make install dans des sous-répertoires.
Généralement, il s'agit de modules développés par des tiers.
make clean efface tous les fichiers temporaires créés par la compilation, y compris le fichier exécutable dans la majorité des cas.
La première étape consiste à 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 Section 5, « Installation »).
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
qui sont des
chaînes, fixées généralement au début du fichier
Makefile
, et qui sont 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 :
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;
LD
: il s'agit du programme utilisé parfois pour
assurer la phase finale de la compilation (voir Section 1.2.2, « Les quatre phases de la compilation »); par défaut, la valeur est ld;
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
LDFLAGS
(ou LFLAGS
) : ce sont les
arguments passés lors de la dernière phase de la compilation. Parmi
ceux-ci :
Pas de panique, cela arrive à tout le monde. Parmi les causes les plus communes :
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 (pour
tester cela, tapez less
<chemin>/<fichier>.h
) ;
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[39]) 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=<quelque chose>
ou de la ligne
CC=<quelque chose>
;
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 Section 6.2, « Assistance technique »).
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 :
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.
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.
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 : supprimer des fichiers
temporaires ou les sources, désinstaller des programmes
dont vous ne vous servez pas, redimensionner une partition,
etc. Si vous l'avez décompressé 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
[40] sur le disque. Si oui, effacez-les ou faites-les effacer
s'ils appartiennent à un autre utilisateur.
/usr/bin/ld: cannot open -lglloq: No such file or
directory
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 :
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.
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 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).
glloq.c(.text+0x34): undefined reference to `glloq_init'
(
référence inconnue au symbole «
glloq.c(.text+0x34)
glloq_init
»)
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. À 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 consiste à 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.)
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 !
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, etc.). 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
. Le redimensionnement est aussi
une option, si vous avez assez d'espace ; une autre
partition peut aussi être réduite en taille.
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'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.
$ touch *
Ou encore plus barbare (mais efficace) :
$ find . | xargs touch
[39] 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/reine/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.
[40] 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 !