Lors du développement d'un logiciel (libre), il est souvent inutile de réinventer la roue lorsqu'il s'agit d'utiliser des algorithmes de gestion mémoire, ou pour utiliser les méthodes d'accès aux fichiers. Ces algorithmes et méthodes sont souvent regroupés par affinité (méthodes systèmes, gestion du chiffrement, algorithmes mathématiques …) sous forme de bibliothèques que d'autres programmes peuvent utiliser.
Le développeur d'une application peut choisir au moment de la création de l'exécutable de lier la ou les bibliothèques utilisées au programme de plusieurs façons:
avantage: tout est inclu, inconvénient: ça prend de la place sur le disque et en mémoire.
avantage: les ressources disque et mémoire sont optimisées, inconvénient: dépendances externes (type de distribution GNU/Linux, compatibilité et versions de bibliothèques).
Pour en savoir plus, vous pouvez consulter l'article bibliothèque logicielle de Wikipédia.
En tant qu'administrateur du système, nous pouvons être confrontés à des problèmes de programmes qui ne démarrent pas, car ils n'ont pas trouvé les bibliothèques partagées dont ils dépendent. Nous avons à notre disposition des outils pour:
La commande utilisée est (sous Ubuntu 12.04) :
/usr/bin/ldd
qui est un script shell qui pointe vers un exécutable:
/lib/ld-linux.so.2 (x86 32 bits) /lib64/ld-linux-x86-64.so.2 (x86_64 64 bits)
Cet exécutable charge le programme et trouve les références des bibliothèques partagées dont il a besoin. Exemple:
user@host:~$ ldd /bin/ls linux-gate.so.1 => (0xb7744000) libselinux.so.1 => /lib/i386-linux-gnu/libselinux.so.1 (0xb770f000) librt.so.1 => /lib/i386-linux-gnu/librt.so.1 (0xb7706000) libacl.so.1 => /lib/i386-linux-gnu/libacl.so.1 (0xb76fc000) libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7552000) libdl.so.2 => /lib/i386-linux-gnu/libdl.so.2 (0xb754d000) /lib/ld-linux.so.2 (0xb7745000) libpthread.so.0 => /lib/i386-linux-gnu/libpthread.so.0 (0xb7532000) libattr.so.1 => /lib/i386-linux-gnu/libattr.so.1 (0xb752c000)
et on s'aperçoit aussi que le programme contient lui-même le chargeur des dépendances des bibliothèques dynamiques, de manière statique (il est intégré avec le programme). Les valeurs entre parenthèses dépendent du système.
En cas de problème, le programme ldd nous montrera une erreur de dépendance (ou plusieurs) avec le nom de la bibliothèque dynamique qui n'a pas été trouvée.
Plusieurs cas, soit:
Ce deuxième outil est (sous Ubuntu 12.04):
/sbin/ldconfig
C'est un script shell qui demande les droits administrateurs pour l'utiliser. Le script pointe sur un exécutable:
/sbin/ldconfig.real
qui a la particularité d'être un exécutable lié statiquement (qui contient toutes les bibliothèques dont il a besoin pour fonctionner) pour éviter d'être coincé si jamais l'ensemble du système de gestion des bibliothèques partagées était cassé.
Cet exécutable pour trouver, gérer les bibliothèques partagées a besoin d'un certain nombre de fichiers de configuration et de variables d'environnement que l'on va décrire dans la section suivante.
Le programme ldconfig a besoin de fichier de configuration pour connaître, trouver et gérer les chemins et les fichiers qui contiennent les bibliothèques partagées.
Le fichier de configuration de ldconfig est:
/etc/ld.so.conf
Il contient (sous Ubuntu 12.04), le contenu suivant
include /etc/ld.so.conf.d/*.conf
qui en fait, lui demande d'importer l'ensemble des informations contenues dans les fichiers qui se trouvent dans le répertoire:
/etc/ld.so.conf.d/
Les fichiers de ce répertoire contiennent des chemins de recherche des bibliothèques partagées, exemple:
user@host:~$ more /etc/ld.so.conf.d/libc.conf # libc default configuration /usr/local/lib
user@host:~$ more /etc/ld.so.conf.d/i686-linux-gnu.conf # Multiarch support /lib/i386-linux-gnu /usr/lib/i386-linux-gnu /lib/i686-linux-gnu /usr/lib/i686-linux-gnu
Les noms des fichiers qui décrivent les bibliothèques partagées ont la particularité d'être formaté de la même façon:
lib<nom de la bibliothèque>.so.<version majeure>.<version mineur>.<version de production>
Lorsque ldconfig trouve une bibliothèque, il en fait un lien symbolique (dans le même répertoire) avec un nom sous une forme plus courte:
lib<nom de la bibliothèque>.so.<version majeure>
Il enregistre aussi ces informations dans un cache pour que le chargeur /lib/ld-linux.so.2 trouve les bibliothèques plus rapidement. Ce fichier de cache se trouve dans:
/etc/ld.so.cache
Il existe aussi une variable d'environnement que chaque utilisateur peut positionner pour ajouter des chemins de recherche pour ses propres bibliothèques partagées avant de lancer un exécutable qui les utilise:
LD_LIBRARY_PATH
Exemple:
export LD_LIBRARY_PATH=/home/user/lib:/home/user/local/lib
Il y a aussi une autre variable qui permet de charger une bibliothèque avant toutes les autres dans le but par exemple de tester une nouvelle version d'une bibliothèque. La variable s'appelle:
LD_PRELOAD
et contient le chemin et le nom de la bibliothèque, exemple:
export LD_PRELOAD = /root/lib/libc.so.7
Exemple d'utilisation de LD_PRELOAD: Changement de la carte son par défaut pour Spotify.