Les librairies
Introduction aux librairies
Les librairies sont des fichiers contenant de fonctions qui peuvent être réutilisées par différentes applications (simultanément ou non)
Il existe deux types de librairies:
- Les librairies statiques qui sont des librairies qui fonctionnent de façon similaires aux objets (.o) que vous créez lors de la compilation d'un code source.
Pour rappel, les fichiers objets (.o) sont des fichiers contenant du code compilé de votre source en C/C++ donc presque exécutable (code machine). Presque car ils manquent certaines informations, comme les adresses des fonctions ou variables qui ne sont pas déclarées dans ce fichier objet, mais dans un tout autre fichier. Ce sera alors le rôle du linker de déterminer ces adresses pour ces fonctions ou variables et de construire à partir des différents fichiers objets (linker <=> lier les différents objets du projet) le code exécutable correspondant.
En fait, il ne s'agit ni plus ni moins que d'un ensemble de fichiers objets (.o) contenus dans un même fichier. Un peu comme une archive, d'où l'extension utilisée .a !
Les avantages étant:
- le fichier exécutable généré contient tout le code nécessaire pour fonctionner (sera inclus dans le code les fonctions de la librairie utilisée).
- Je n'en vois pas d'autres...
Les inconvénients étant:
- qu'il est nécessaire de recompiler tous les programmes utilisant une librairie statique, si celle-ci se voit corrigée d'un bug.
- La taille de l'exécutable est importante (puisqu'il contient tout le code nécessaire).
- Il y a en quelque sorte duplication du code (toutes les applications utilisant la librairie posséde le code binaire de celle-ci).
- Les librairies dynamiques qui sont des librairies que les programmes vont utiliser au moment de l'exécution et non plus au moment de la compilation.
Leurs avantages:
- Votre programme n'aura pas une taille démesurée (comme ce serait le cas avec les librairies statiques).
- Facilité de maintenance, puisqu'il suffira de corriger un bug présent dans la librairie pour qu'automatiquement les applications soient maj.
- Chargées qu'une seule fois en mémoire même si plusieurs programmes l'utilisent (classique, mais bon à rappeler)
Les inconvénients:
- Vous ne pouvez pas apporter de grosses modifications sur une librairie (par exemple pas de modifications de signatures des fonctions permises, car cela rendrait tous les applications l'utilisant incompatibles avec votre nouvelle librairie !)
- Il n'est pas autorisé de supprimer une librairie dynamique, les applications l'utilisant ne fonctionneraient plus. Voire à ne pas la déplacer.
Principe de nommage des librairies
Les librairies statiques se nomment libXXXXX.a (a pour archive)
Sur AIX, les
librairies libXXXXX.a peuvent aussi être dynamiques ! Je ne trouve pas
cela très propre...mais ce n'est que mon avis.
Les librairies dynamiques se nomment libXXXXX.so (so pour shared object)
où XXXXX est le nom de la librairie (par exemple la librairie dynamique jpeg sera le fichier libjpeg.so...)
Evidemment, je
suis contraint de mettre une note par rapport à ce que j'indique ci-dessus
sur l'AIX:
Les .so sont valables sur SUN Solaris/OS et le monde Linux. Vous pouvez aussi en trouver parfois sur AIX.
Emplacement des librairies
Les librairies sont recherchées dans:
/usr/local/lib/ pour les librairies perso. utilisables par tous.
/usr/lib/ pour les librairies standards.
Il sera possible de stipuler d'autres chemins lors de la compilation.
De même, il existe des solutions pour indiquer d'autres chemins pour les librairies lors de l'exécution (Voir paragraphe "Les chemins des librairies dynamiques" ci-dessous).
Création d'une librairie
Développement
Vous développez votre code normalement, puis vous le compilez tout aussi normalement. Vous aurez un fichier include avec les fonctions que vous voulez voir utilisables. Il vous restera à fournir cet include pour une utilisation dans d'autres applications.
Rien n'empêche
d'utiliser des librairies dans votre librairie...
Les librairies statiques:
Les librairies statiques sont générées à partir des fichiers objets. Il suffit d'utiliser la commande ar pour produire ces librairies. Cette fonction va archiver dans un fichier l'ensemble de vos fichiers .o
ar -rv nom_librairie liste_des_objets
Exemple : ar -rv libXXXXX.a prog1.o prog2.o prog3.o ... progn.o
Il est possible de créer un index des symboles des membres (ou objets) d'une archive. Pour créer l'index des symboles, il suffit d'utiliser 'ranlib nom_archive' (similaire à 'ar -s'). Elle aura l'avantage d'accélérer la compilation.
Les librairies dynamiques:
Les librairies dynamiques sont aussi générées à partir des fichiers objets. Mais là, vous utiliserez le compilateur gcc pour générer la librairie .so de la manière suivante:
gcc -o libXXXXX.so -shared prog1.o prog2.o prog3.o ... progn.o
où en passant par le linkeur:
ld -dY -G -o prog1.o prog2.o prog3.o ... progn.o libXXXXX.so
Afficher les dépendances
Il est possible d'afficher les dépendances d'un programme avec des librairies dynamiques en utilisant la commande ldd
ldd nomprogramme
Utiliser une librairie dynamique dans votre code
Ce qui suit
est en principe devenu inutile, le but était de charger une librairie
en mémoire, puis de déterminer l'adresse de la (des) fonction(s)
à appeler. et de libérer la librairie lorsque le code n'en avait
plus besoin. Le compilateur fait maintenant tout ce travail automatiquement.
Les chemins des librairies dynamiques
Lorsqu'un programme s'exécute et a besoin d'une librairie dynamique, il va chercher cette librairie sur un chemin connu (courant, /lib/usr/lib).
Parfois, les librairies dynamiques ne se trouvent pas dans le bon répertoire,
et le programme s'arrête car il ne la trouve pas ! Il faudra alors modifier
le cache système lié aux librairies dynamiques pour résoudre
ce problème de chemin.
- Vous pourrez modifier la variable d’environnement LD_LIBRARY_PATH afin
d’y ajouter le chemin souhaité :
setenv LD_LIBRARY_PATH $LD_LIBRARY_PATH:/ nouveau_chemin
ou export LD_LIBRARY_PATH= $LD_LIBRARY_PATH:/ nouveau_chemin
Par exemple, vous pourrez ajouter votre répertoire si vous créez vos propres librairies (~\lib par exemple si vos librairies se trouvent sous lib à partir de votre répertoire courant).
Toujours sur
AIX ! la variable se nomme : LIBPATH et non LD_LIBRARY_PATH.
Ne fonctionne pas sous Linux...on utilisera la méthode suivante:
Modification du fichier de paramétrage du cache : /etc/ld.so.conf
Suite à la modification, il faut regénérer le cache: /sbin/ldconfig
(Evidemment, il faudra être administrateur !)
Compiler des programmes utilisant une librairie
Voir chapitre sur le compilateur GCC/G++ ainsi que sur la commande make.
Connaître le contenu d'une librairie statique
La commande ar permet de construire une librairie statique. De même, elle pourra lister son contenu (chaque objet .o):
ar -t nomlibrairie
Vous pourrez aussi lister la table de symboles via la fonction nm:
/usr/bin/nm libXXXXX.a
Dans le résultat:
U : undefined (implémentation externe)
T : implémenté à l’intérieur
De la même manière, si l'index des symboles est défini (voir création d'une librairie), il sera possible de lister les symboles par membre (objet) de l'archive
Pour cela, utilisez 'nm -s' ou 'nm --print-armap' pour lister cet index.
Exemple de librairies
Source de la librairieL'include
utile pour les codes y faisant appel
un
exemple de code
Bête librairie retournant le résultat d'une addition deux arguments passés en paramètre...
Compilez la librairie (exemple gcc -c add.c -o add.o)
Construisez votre librairie statique (ar -rv libadd.a add.o) ou dynamique (gcc -o libadd.so -shared -o add.o, avec une remarque sur AIX, l'extension de la librairie devant être .a et vous ne pourrez donc pas avoir les deux en même temps !!!)
Recopiez votre
librairie dynamique (sous /usr/lib en administrateur par exemple) ou configurez
comme il faut votre plate-forme pour qu'il trouve votre librairie dynamique...(Je
n'ai jamais eu à faire cela sur un AIX, mais à faire sous Linux
!)
Compilez l'exemple de test addition (gcc -c testadd.c -o testadd.o)
Puis linkez votre librairie avec votre code de test:
gcc testadd.o -Lchemin_ou_se_trouve_votre_librairie -ladd -o testadd
Testez votre programme.
Vous pourrez tester
ensuite si votre code est compilé avec une librairie statique, le fait
de renommer votre librairie n'empêchera pas le lancement du code, alors
que votre code râlera si compilé avec une librairie dynamique...