Niveau :      
Résumé : bibliothèque

Une bibliothèque (et non pas une librairie) est un fichier qui contient des fonctions que vous allez réutiliser dans plusieurs programmes. Il en existe de plusieurs sortes.

Les bibliothèques statiques sont des fichiers qui seront inclus à votre programme lors de la compilation. Ce qui grossira d'autant plus le binaire résultant. Avantage, il sera indépendant de l'installation de bibliothèques par l'utilisateur. Pratique quand vous voulez faire installer un logiciel par tout le monde (plus de problème de version).

Les bibliothèques dynamiques sont des fichiers qui seront chargés automatiquement par le système lors du lancement de votre programme. Elles permettent de l'alléger de beaucoup, mais rendent ce dernier dépendant de l'installation du système. Ce sont bien évidemment les plus utilisées.

Comment se différencient-elles ? Petit exemple en C.
lib.c :

#include <stdio.h>
void hello()
{
	printf("Hello world !\n");
}

main.c :

int main()
{
	hello();
	return 0;
}

On va découper la compilation en étapes élémentaires pour bien la comprendre :

# compilation
# -fPIC pour permettre la réutilisation de la lib
$ gcc -fPIC -c -o libhello.o libhello.c

# création d'une bibliothèque statique
$ ar rcs libhello.a libhello.o

# création d'une bibliothèque dynamique
# en pratique vous utiliserez directement gcc, mais ici j'explique
$ ld libhello.o -o libhello.so -shared 

Vous voyez donc qu'une bibliothèque statique est une simple archive de fichiers objet. On peut lui faire faire tout ce que permettent les archives de type ar. Une bibliothèque dynamique par contre est un exécutable à part entière, certaines peuvent même être directement exécutées.

Maintenant compilons et testons notre programme

# En statique
$ gcc -o main-static main.c libhello.a
$ ./main-static
Hello world !


# en dynamique
$ gcc -o main-dynamic main.c -lhello -L.
# Étant donné que libhello n'est pas dans les chemins standards
# nous avons besoin de ceci pour l'exécution 
$ export LD_LIBRARY_PATH=.
$ ./main-dynamic 
Hello world !

Regardons la différence au niveau de la taille du code généré :

 9247 main-dynamic
 9308 main-static

Bon évidemment, la différence est ici minime car il ne s'agit que d'une fonction.

Ok, maintenant examinons le programme ainsi créé grâce à un outil qui peut nous dire ce qui se passe lors de l'édition de lien :

$ ldd main-static 
        linux-vdso.so.1 =>  (0x00007fff0fbfe000)
        libc.so.6 => /lib/libc.so.6 (0x00002b389b252000)
        /lib64/ld-linux-x86-64.so.2 (0x00002b389b034000)

$ ldd main-dynamic 
        linux-vdso.so.1 =>  (0x00007fff13ffe000)
        libhello.so => ./libhello.so (0x00002ac396d90000)
        libc.so.6 => /lib/libc.so.6 (0x00002ac396faf000)
        /lib64/ld-linux-x86-64.so.2 (0x00002ac396b72000)

On constate l'absence de dépendance à une bibliothèque dans le premier cas alors qu'elle est chargée par le système dans le deuxième.

L'édition de lien se produit lors de l'exécution du programme, elle consiste à mettre en relation les appels de fonction du programme et les fonctions se trouvant dans les bibliothèques dynamiques par des créations de tables de pointeurs.

Attention, toutefois, l'édition de lien est faite non pas par le noyau, mais par l'éditeur de lien dynamique. C'est tellement automatisé que personne ne s'en rend compte. C'est en fait un programme utilisateur (/lib/ld-linux.so) qui fait ça. Pour des programme suffisamment gros (genre openoffice) on commence à constater le phénomène car il y a un très grand nombre de bibliothèques et de fonctions. C'est pourquoi il existe un outil pour faire du preload, c'est à dire préparer la table des pointeurs à l'avance, ce qui accélérera le chargement (il se résumera à un chargement en ram).

Notez aussi que toutes les variables commençant par LD_ sont justement destinées à ld-linux. Pensez à LD_PRELOAD LD_LIBRARY_PATH mais aussi d'autres, bien utiles pour le débuggage, toutes disponibles dans man ld-linux.

PS : tout ceci fonctionne de la même façon sous windows à l'exception des noms de commande. Notez aussi que sous les autres unix, ld-linux change de nom :-)