Table des matières

Gestion des bibliothèques partagées

Introduction

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.

Outils

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:

Connaître les bibliothèques partagées utilisées par un programme

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:

Gérer les bibliothèques partagées du système

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.

Configuration

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.

En résumé

Voici un schéma récapitulatif: