(Courriels de diversion: <vraisemblance@ordinairement-horripiles.com> <fetu@percussion-vissages.com> <rejeton@contre-visite-insoupconnee.com> <vasodilatatrices@fame-entrelarder.com> <sombraient@remployez-meconnaîtras.com> <guider@muterais-diminuaient.com> <percutants@sevrions-interpellerait.com> <transnationales@avorteras-artistiques.com> <deplafonnais@check-up-ardentes.com> <moyenâgeuse@amadoueras-tampon.com> )


Le 30 Mar, Sebastien Renard écrit :

> Enfin, voila ce qui m'amène : je suis en train de compiler un projet
> en c++ et j'utilise une librairie (libxerces-c1_1.so) du parseur XML
> de Apache. Pour compiler, no pb j'ai inclu la lib dans le makefile,
> mais pour l'execution il ne la trouve pas. J'ai mis le fichier dans
> /lib, mais j'ai un vague souvenir de "ld" qu'il faut je crois utiliser
> pour signaler au systeme la presence de la nouvelle librairie. Quelqu'un
> peut-il m'eclairer sur le sujet ?

  Je ne vais pas répondre directement à ta question. Je vais plutôt
tenter d'expliquer comment cela fonctionne, du point de vue de
l'utilisation et de la création.

  D'abord les bibliothèques statiques. Leur nom se termine
traditionnellement par '.a'. Ce sont des collections de fichiers
objets (.o). On peut extraire ou ajouter des fichiers objets à la
bibliothèque avec la commande « ar ».

  Quand on fait l'édition de liens avec la bibliothèque, les fichiers objets 
nécessaires pour satisfaire les symboles non encore connus (par exemple
printf) sont intégrés dans l'exécutable en cours de création. Tout se passe 
donc comme si l'on avait cité ces fichiers objets sur la ligne de commande
de l'édition de liens.

  Lors de l'édition de liens, on spécifie la bibliothèque soit par son
chemin d'accès (/usr/libi/libtoto.a), soit par -ltoto (auquel cas l'éditeur
de liens va la chercher sous le nom de libtoto.a dans divers
répertoires). La première méthode permet seule d'avoir des bibliothèques
qui soient nommées autrement que libquelquechose.

  Lors de l'exécution du programme, tout le code est disponible, puisqu'il
a été intégré dans le binaire lors de l'édition de liens.

  C'est du gaspillage, puisque printf.o se retrouve en mémoire autant de
fois qu'il y a de programmes actifs qui utilisent printf.

  C'est pour cela qu'on été inventées les bibliothèques dynamiques (entre
autre, car il y a d'autres avantages).

  Là, le code n'est plus agrégé au binaire du programme : à la place, le
binaire se « souvient » qu'il a besoin de tel bout de code (printf), et
qu'il peut le trouver dans telle bibliothèque dynamique (libc.so.6).

  Ces deux informations doivent être enregistrées dans le binaire lors de
l'édition de liens. C'est pour cela qu'il faut citer la bibliothèque
dynamique sur la ligne de commande de l'édition de liens.

  Mais la bibliothèque doit aussi être retrouvée lors de l'exécution.

  Une difficulté supplémentaire vient de ce que le code de la bibliothèque
peut évoluer : des bogues sont corrigées, des fonctionnalités ajoutées. Et
ce serait con qu'un binaire lié à une version de la bibliothèque ne puisse
pas fonctionner si une autre version compatible est seule disponible lors
de l'exécution.

  C'est pour cela que l'éditeur de liens n'enregistre pas le chemin de la
bibliothèque (ni même son nom) dans le binaire en cours de création.

  À la place l'éditeur de liens enregistre le soname de la bibliothèque et
une liste de chemins d'accès où chercher lors de l'exécution.

  Imaginons que je développe une bibliothèque « ation ». Je commence par la 
version 1.1, mais j'ai la ferme intention de maintenir les versions
suivantes compatibles de manière ascendante (c'est-à-dire qu'un programme
lié avec la 1.1 fonctionnera avec la 1.2) tant que je ne changerai pas le
premier chiffre de la version.

  Je vais donc créer ma bibliothèque dans un fichier que je nommerai
libation.so.1.1. Mais je lui donnerai comme soname « libation.so.1 ». Par
exemple avec la ligne de commande :
   gcc -shared -o libation.so.1.1 -Wl,-h,libation.so.1 -fpic leverLeCoude.c

  De même pour la 1.2 :
   gcc -shared -o libation.so.1.2 -Wl,-h,libation.so.1 -fpic leverLeCoude.c

  De la sorte, je pourrai compiler un programme ainsi :
   gcc -o 3eme boire.c libation.so.1.1
et, lors de l'exécution, il cherchera le fichier « libation.so.1 ».

  D'habitude, on préfère citer les bibliothèque par l'option « -l » de
l'édition des liens :
   gcc -o 3eme boire.c -lation
L'éditeur de liens va alors chercher le fichier libation.so dans les
répertoires cités dans la variable d'environnement LD_LIBRARY_PATH et
dans l'option « -L » (plus les répertoires standards /lib et /usr/lib).

  Mais il n'enregistrera pas dans le binaire le répertoire dans lequel le
fichier a été trouvé. À la place, il enregistrera dans le binaire les
répertoires cités dans la variable d'environnement LD_RUN_PATH et dans le
options « -R » et « -rpath ». C'est là que le binaire ira chercher en
priorité sa bibliothèque lors de l'exécution.

  Mais vous avez remarqué que je n'ai jamais créé de fichier nommé
libation.so.1. Comment le programme va-t-il le trouver lors de l'exécution ? 
Ben, c'est simple : il ne va pas le trouver ; il faut que le fichier
existe. C'est un des rôles de ldconfig : il créé un lien symbolique qui
renvoie le soname vers le vrai fichier contenant la bibliothèque, celui qui 
a le plus haut numéro de version s'il y en a plusieurs.

  Lors de l'exécution, mon programme va tenter de trouver sa bibliothèque
dynamique libation.so.1 dans l'ordre :
  - dans les répertoires cités dans la variable d'environnement
    LD_LIBRARY_PATH (autre usage de cette variable, donc) ;
  - dans les répertoires enregistrés dans le binaire lors de l'édition de
    liens ;
  - dans les répertoires standards.

  Mais la plupart des bibliothèques dynamiques seront des bibliothèques
contenant des fonctionnalités assez courantes, et ces bibliothèques sont
stables : elles ne sont pas souvent changées. C'est donc con de les
chercher dans pleins de répertoires : cela ralentit l'exécution.

  C'est pour cela que l'éditeur de liens dynamique utilise un cache. Le
cache est un fichier qui contient une correspondance soname -> fichier pour 
des répertoires choisis (configurables dans /etc/ld.so.conf). La
maintenance de ce cache est l'autre rôle de ldconfig.

  Résumons :
   - le chemin de recherche des bibliothèques dynamique n'est pas
     (forcément) le même lors de l'édition de liens et lors de l'exécution
     du binaire résultant ;
   - un fichier libation.so est normalement un lien vers la vraie
     bibliothèque ; ce lien n'est utilisé que lors de l'édition de liens
     avec l'option « -l » ;
   - un fichier libation.x est normalement un lien vers la bibliothèque
     libation.x.y [*] avec y le plus élevé ; ce lien n'est utilisé que lors 
     de l'exécution.

  À ma connaissance, tous les systèmes ELF fonctionnent ainsi (du moins,
j'en suis sûr pour Sun Solaris).

[*] Il peut arriver qu'il y ait plus de nombres dans le nom du fichier.

-- 
Marc Thirion              | Toulouse, France
Un Travail pour Chacun    : http://www.multimania.com/untravailchacun/
Marc.Thirion@ISOscope.com : http://www.ISOscope.com/Pérennité des logiciels et des systèmes




---------------------------------------------------------------------
Aide sur la liste: <URL:mailto:linux-31-help@savage.iut-blagnac.fr>Le CULTe sur le web: <URL:http://savage.iut-blagnac.fr/>