2.3. Utilisation de bibliothèques avec GCC
Ce chapitre décrit l'utilisation des bibliothèques dans le code.
2.3.1. Conventions de dénomination des bibliothèques
Une convention spéciale sur les noms de fichiers est utilisée pour les bibliothèques : une bibliothèque connue sous le nom de foo est censée exister sous la forme d'un fichier libfoo.so
ou libfoo.a
. Cette convention est automatiquement comprise par les options d'entrée de GCC, mais pas par les options de sortie :
Lors de l'établissement d'un lien avec la bibliothèque, celle-ci ne peut être spécifiée que par son nom foo avec l'option
-l
, comme suit-lfoo
:$ gcc ... -lfoo...
-
Lors de la création de la bibliothèque, le nom complet du fichier
libfoo.so
oulibfoo.a
doit être spécifié.
2.3.2. Liaison statique et dynamique
Les développeurs ont le choix d'utiliser la liaison statique ou dynamique lorsqu'ils construisent des applications avec des langages entièrement compilés. Il est important de comprendre les différences entre l'enchaînement statique et l'enchaînement dynamique, en particulier dans le contexte de l'utilisation des langages C et C sur Red Hat Enterprise Linux. En résumé, Red Hat déconseille l'utilisation de l'édition statique de liens dans les applications pour Red Hat Enterprise Linux.
Comparaison de la liaison statique et de la liaison dynamique
L'enchaînement statique intègre les bibliothèques dans le fichier exécutable résultant. L'enchaînement dynamique conserve ces bibliothèques dans des fichiers distincts.
La liaison dynamique et la liaison statique peuvent être comparées de plusieurs façons :
- Utilisation des ressources
L'établissement de liens statiques donne lieu à des fichiers exécutables plus volumineux qui contiennent plus de code. Ce code supplémentaire provenant des bibliothèques ne peut pas être partagé entre plusieurs programmes sur le système, ce qui augmente l'utilisation du système de fichiers et de la mémoire au moment de l'exécution. Plusieurs processus exécutant le même programme lié statiquement partageront toujours le code.
D'autre part, les applications statiques nécessitent moins de relocalisations pendant l'exécution, ce qui réduit le temps de démarrage, et requièrent moins de mémoire privée de taille d'ensemble résident (RSS). Le code généré pour l'enchaînement statique peut être plus efficace que pour l'enchaînement dynamique en raison de la surcharge introduite par le code indépendant de la position (PIC).
- Sécurité
- Les bibliothèques liées dynamiquement qui assurent la compatibilité ABI peuvent être mises à jour sans modifier les fichiers exécutables qui dépendent de ces bibliothèques. Ceci est particulièrement important pour les bibliothèques fournies par Red Hat dans le cadre de Red Hat Enterprise Linux, où Red Hat fournit des mises à jour de sécurité. L'établissement de liens statiques avec de telles bibliothèques est fortement déconseillé.
- Compatibilité
La liaison statique semble fournir des fichiers exécutables indépendants des versions des bibliothèques fournies par le système d'exploitation. Cependant, la plupart des bibliothèques dépendent d'autres bibliothèques. Avec l'édition de liens statiques, cette dépendance devient inflexible et, par conséquent, la compatibilité ascendante et descendante est perdue. L'enchaînement statique est garanti pour fonctionner uniquement sur le système où le fichier exécutable a été construit.
AvertissementLes applications liant statiquement les bibliothèques de la bibliothèque GNU C (glibc) nécessitent toujours que glibc soit présent sur le système en tant que bibliothèque dynamique. En outre, la variante de la bibliothèque dynamique glibc disponible au moment de l'exécution de l'application doit être une version bitwise identique à celle présente lors de l'édition de liens de l'application. Par conséquent, l'établissement de liens statiques n'est garanti que sur le système où le fichier exécutable a été créé.
- Couverture de soutien
- La plupart des bibliothèques statiques fournies par Red Hat se trouvent dans le canal CodeReady Linux Builder et ne sont pas prises en charge par Red Hat.
- Fonctionnalité
Certaines bibliothèques, notamment la bibliothèque GNU C (glibc), offrent des fonctionnalités réduites lorsqu'elles sont liées de manière statique.
Par exemple, lorsqu'il est lié statiquement, le site glibc ne prend pas en charge les threads et toute forme d'appel à la fonction
dlopen()
dans le même programme.
En raison de ces inconvénients, l'établissement de liens statiques doit être évité à tout prix, en particulier pour les applications entières et les bibliothèques glibc et libstdc .
Cas de la liaison statique
La création de liens statiques peut être un choix raisonnable dans certains cas, par exemple :
- Utilisation d'une bibliothèque qui n'est pas activée pour la liaison dynamique.
-
Une liaison entièrement statique peut être nécessaire pour exécuter un code dans un environnement ou un conteneur chroot vide. Cependant, l'établissement de liens statiques à l'aide du paquetage
glibc-static
n'est pas pris en charge par Red Hat.
2.3.3. Optimisation du temps de liaison
L'optimisation au moment de la liaison (LTO) permet au compilateur d'effectuer diverses optimisations sur toutes les unités de traduction de votre programme en utilisant sa représentation intermédiaire au moment de la liaison. Par conséquent, vos fichiers exécutables et vos bibliothèques sont plus petits et s'exécutent plus rapidement. En outre, vous pouvez analyser le code source du paquet au moment de la compilation de manière plus approfondie en utilisant l'OLT, ce qui améliore les différents diagnostics de GCC pour les erreurs de codage potentielles.
Problèmes connus
La violation de la règle de la définition unique (ODR) entraîne l'envoi d'un avertissement à l'adresse
-Wodr
Les violations de l'ODR entraînant un comportement indéfini produisent un avertissement à l'adresse
-Wodr
. Cela indique généralement un bogue dans votre programme. L'avertissement-Wodr
est activé par défaut.LTO entraîne une augmentation de la consommation de mémoire
Le compilateur consomme plus de mémoire lorsqu'il traite les unités de traduction du programme. Sur les systèmes disposant d'une mémoire limitée, désactivez le LTO ou réduisez le niveau de parallélisme lors de la construction de votre programme.
GCC supprime les fonctions apparemment inutilisées
GCC peut supprimer des fonctions qu'il considère comme inutilisées parce que le compilateur n'est pas en mesure de reconnaître les symboles auxquels une instruction asm() fait référence. Une erreur de compilation peut en résulter. Pour éviter cela, ajoutez
__attribute__((used))
aux symboles que vous utilisez dans votre programme.La compilation avec l'option
-fPIC
provoque des erreursGCC n'analysant pas le contenu des instructions asm(), la compilation de votre code avec l'option de ligne de commande
-fPIC
peut provoquer des erreurs. Pour éviter cela, utilisez l'option-fno-lto
lors de la compilation de votre unité de traduction.
Pour plus d'informations, consultez la FAQ LTO - Utilisation de symboles à partir du langage d'assemblage.Le versionnage des symboles à l'aide de la directive
.symver
n'est pas compatible avec LTOL'implémentation du versionnage des symboles en utilisant la directive
.symver
dans une instruction asm() n'est pas compatible avec le LTO. Cependant, il est possible d'implémenter le versionnage des symboles en utilisant l'attributsymver
. Par exemple, il est possible d'implémenter la version d'un symbole en utilisant l'attribut :__attribute__ ((_symver_ ("<symbol>@VERS_1"))) void <symbol>_v1 (void) { }
Ressources supplémentaires
2.3.4. Utilisation d'une bibliothèque avec GCC
Une bibliothèque est un ensemble de codes qui peuvent être réutilisés dans votre programme. Une bibliothèque C ou C se compose de deux parties :
- Le code de la bibliothèque
- Fichiers d'en-tête
Compiler un code qui utilise une bibliothèque
Les fichiers d'en-tête décrivent l'interface de la bibliothèque : les fonctions et les variables disponibles dans la bibliothèque. Les informations contenues dans les fichiers d'en-tête sont nécessaires à la compilation du code.
Généralement, les fichiers d'en-tête d'une bibliothèque sont placés dans un répertoire différent de celui du code de votre application. Pour indiquer à GCC où se trouvent les fichiers d'en-tête, utilisez l'option -I
:
$ gcc ... -Iinclude_path...
Remplacez include_path par le chemin d'accès au répertoire du fichier d'en-tête.
L'option -I
peut être utilisée plusieurs fois pour ajouter plusieurs répertoires contenant des fichiers d'en-tête. Lors de la recherche d'un fichier d'en-tête, ces répertoires sont parcourus dans l'ordre de leur apparition dans les options -I
.
Lier un code qui utilise une bibliothèque
Lors de la liaison du fichier exécutable, le code objet de votre application et le code binaire de la bibliothèque doivent être disponibles. Le code des bibliothèques statiques et dynamiques se présente sous différentes formes :
-
Les bibliothèques statiques sont disponibles sous forme de fichiers d'archive. Elles contiennent un groupe de fichiers objets. Le fichier d'archive a une extension de nom de fichier
.a
. -
Les bibliothèques dynamiques sont disponibles sous forme d'objets partagés. Elles constituent une forme de fichier exécutable. Un objet partagé a une extension de nom de fichier
.so
.
Pour indiquer à GCC où se trouvent les archives ou les fichiers d'objets partagés d'une bibliothèque, utilisez l'option -L
:
$ gcc ... -Llibrary_path -lfoo...
Remplacez library_path par le chemin d'accès au répertoire de la bibliothèque.
L'option -L
peut être utilisée plusieurs fois pour ajouter plusieurs répertoires. Lors de la recherche d'une bibliothèque, ces répertoires sont parcourus dans l'ordre des options -L
.
L'ordre des options est important : GCC ne peut pas établir un lien avec une bibliothèque foo s'il ne connaît pas le répertoire contenant cette bibliothèque. Par conséquent, utilisez les options -L
pour spécifier les répertoires de bibliothèques avant d'utiliser les options -l
pour l'édition de liens avec les bibliothèques.
Compiler et lier le code qui utilise une bibliothèque en une seule étape
Lorsque la situation permet de compiler et de lier le code en une seule commande gcc
, utilisez les options pour les deux situations mentionnées ci-dessus en une seule fois.
Ressources supplémentaires
- Utilisation de la collection de compilateurs GNU (GCC) - Options pour la recherche dans les répertoires
- Utilisation de la collection de compilateurs GNU (GCC) - Options pour l'établissement de liens
2.3.5. Utilisation d'une bibliothèque statique avec GCC
Les bibliothèques statiques sont disponibles sous forme d'archives contenant des fichiers objets. Après l'établissement d'un lien, elles font partie du fichier exécutable résultant.
Red Hat déconseille l'utilisation de liens statiques pour des raisons de sécurité. Voir Section 2.3.2, « Liaison statique et dynamique ». N'utilisez l'édition de liens statiques qu'en cas de nécessité, en particulier pour les bibliothèques fournies par Red Hat.
Conditions préalables
- GCC doit être installé sur votre système.
- Vous devez comprendre ce que sont les liens statiques et dynamiques.
- Vous disposez d'un ensemble de fichiers source ou objet formant un programme valide, nécessitant une bibliothèque statique foo et aucune autre bibliothèque.
-
La bibliothèque foo est disponible sous la forme d'un fichier
libfoo.a
, et aucun fichierlibfoo.so
n'est fourni pour la liaison dynamique.
La plupart des bibliothèques qui font partie de Red Hat Enterprise Linux ne sont prises en charge que pour l'édition de liens dynamiques. Les étapes ci-dessous ne fonctionnent que pour les bibliothèques qui sont not activées pour l'édition de liens dynamiques.
Procédure
Pour lier un programme à partir des fichiers source et objet, ajouter une bibliothèque statiquement liée foo, qui se trouve dans le fichier libfoo.a
:
- Allez dans le répertoire contenant votre code.
Compiler les fichiers sources du programme avec les en-têtes de la bibliothèque foo:
$ gcc ... -Iheader_path -c ...
Remplacez header_path par un chemin vers un répertoire contenant les fichiers d'en-tête de la bibliothèque foo.
Lier le programme à la bibliothèque foo:
$ gcc ... -Llibrary_path -lfoo...
Remplacez library_path par un chemin d'accès à un répertoire contenant le fichier
libfoo.a
.Pour exécuter le programme ultérieurement, il suffit de
$ ./program
L'option -static
de GCC relative à l'édition statique de liens interdit toute édition dynamique de liens. Utilisez plutôt les options -Wl,-Bstatic
et -Wl,-Bdynamic
pour contrôler plus précisément le comportement de l'éditeur de liens. Voir Section 2.3.7, « Utiliser des bibliothèques statiques et dynamiques avec GCC ».
2.3.6. Utilisation d'une bibliothèque dynamique avec GCC
Les bibliothèques dynamiques sont disponibles sous forme de fichiers exécutables autonomes, nécessaires à la fois au moment de l'établissement des liens et au moment de l'exécution. Elles restent indépendantes du fichier exécutable de votre application.
Conditions préalables
- GCC doit être installé sur le système.
- Ensemble de fichiers source ou objet formant un programme valide, nécessitant une bibliothèque dynamique foo et aucune autre bibliothèque.
- La bibliothèque foo doit être disponible sous la forme d'un fichier libfoo.so.
Lier un programme à une bibliothèque dynamique
Pour lier un programme à une bibliothèque dynamique foo:
$ gcc ... -Llibrary_path -lfoo...
Lorsqu'un programme est lié à une bibliothèque dynamique, le programme résultant doit toujours charger la bibliothèque au moment de l'exécution. Il existe deux options pour localiser la bibliothèque :
-
Utilisation d'une valeur
rpath
stockée dans le fichier exécutable lui-même -
Utilisation de la variable
LD_LIBRARY_PATH
au moment de l'exécution
Utilisation d'une valeur rpath
stockée dans le fichier exécutable
La valeur rpath
est une valeur spéciale enregistrée dans un fichier exécutable lorsqu'il est lié. Plus tard, lorsque le programme sera chargé à partir de son fichier exécutable, l'éditeur de liens utilisera la valeur rpath
pour localiser les fichiers de la bibliothèque.
Lors de l'établissement d'un lien avec GCC, le chemin library_path est enregistré sous rpath
:
$ gcc ... -Llibrary_path -lfoo -Wl,-rpath=library_path...
Le chemin library_path doit pointer vers un répertoire contenant le fichier libfoo.so.
N'ajoutez pas d'espace après la virgule dans l'option -Wl,-rpath=
.
Pour exécuter le programme ultérieurement :
$ ./program
Utilisation de la variable d'environnement LD_LIBRARY_PATH
Si le fichier exécutable du programme ne contient pas rpath
, l'éditeur de liens utilisera la variable d'environnement LD_LIBRARY_PATH
. La valeur de cette variable doit être modifiée pour chaque programme. Cette valeur doit représenter le chemin où se trouvent les objets de la bibliothèque partagée.
Pour exécuter le programme sans rpath
, avec les bibliothèques présentes dans le chemin library_path:
$ export LD_LIBRARY_PATH=library_path:$LD_LIBRARY_PATH
$ ./program
L'omission de la valeur rpath
offre une certaine souplesse, mais nécessite la définition de la variable LD_LIBRARY_PATH
à chaque fois que le programme doit être exécuté.
Placer la bibliothèque dans les répertoires par défaut
La configuration de l'éditeur de liens d'exécution spécifie un certain nombre de répertoires comme emplacement par défaut des fichiers de bibliothèque dynamique. Pour utiliser ce comportement par défaut, copiez votre bibliothèque dans le répertoire approprié.
Une description complète du comportement de l'éditeur de liens dynamiques n'entre pas dans le cadre de ce document. Pour plus d'informations, voir les ressources suivantes :
Pages de manuel Linux pour l'éditeur de liens dynamiques :
$ man ld.so
Contenu du fichier de configuration
/etc/ld.so.conf
:$ cat /etc/ld.so.conf
Rapport des bibliothèques reconnues par l'éditeur de liens dynamiques sans configuration supplémentaire, qui inclut les répertoires :
$ ldconfig -v
2.3.7. Utiliser des bibliothèques statiques et dynamiques avec GCC
Il est parfois nécessaire de lier certaines bibliothèques de manière statique et d'autres de manière dynamique. Cette situation pose quelques problèmes.
Conditions préalables
- Comprendre les liens statiques et dynamiques
Introduction
gcc reconnaît les bibliothèques dynamiques et statiques. Lorsque l'option -lfoo
est rencontrée, gcc tentera d'abord de localiser un objet partagé (un fichier .so
) contenant une version liée dynamiquement de la bibliothèque foo, puis cherchera le fichier d'archive (.a
) contenant une version statique de la bibliothèque. Ainsi, les situations suivantes peuvent résulter de cette recherche :
- Seul l'objet partagé est trouvé et gcc s'y réfère de manière dynamique.
- Seule l'archive est trouvée, et gcc s'y réfère de manière statique.
- L'objet partagé et l'archive sont tous deux trouvés et, par défaut, gcc sélectionne la liaison dynamique avec l'objet partagé.
- Aucun objet partagé ni archive n'est trouvé et la liaison échoue.
En raison de ces règles, la meilleure façon de sélectionner la version statique ou dynamique d'une bibliothèque pour l'édition de liens est de n'avoir que la version trouvée par gcc. Ceci peut être contrôlé dans une certaine mesure en utilisant ou en supprimant les répertoires contenant les versions des bibliothèques, lors de la spécification des options -Lpath
options.
En outre, comme l'enchaînement dynamique est la valeur par défaut, la seule situation où l'enchaînement doit être explicitement spécifié est celle où une bibliothèque dont les deux versions sont présentes doit être liée de manière statique. Il existe deux solutions possibles :
-
Spécification des bibliothèques statiques par chemin d'accès au lieu de l'option
-l
-
Utilisation de l'option
-Wl
pour passer des options à l'éditeur de liens
Spécifier les bibliothèques statiques par fichier
Habituellement, gcc est chargé d'établir un lien avec la bibliothèque foo à l'aide de l'option -lfoo
. Cependant, il est possible de spécifier le chemin complet du fichier libfoo.a
contenant la bibliothèque :
$ gcc ... path/to/libfoo.a ...
D'après l'extension du fichier .a
, gcc comprendra qu'il s'agit d'une bibliothèque à lier au programme. Cependant, spécifier le chemin complet du fichier de la bibliothèque est une méthode moins souple.
Utilisation de l'option -Wl
L'option gcc -Wl
est une option spéciale permettant de passer des options à l'éditeur de liens sous-jacent. La syntaxe de cette option diffère de celle des autres options gcc. L'option -Wl
est suivie d'une liste d'options de l'éditeur de liens séparée par des virgules, alors que les autres options gcc nécessitent une liste d'options séparées par des espaces.
L'éditeur de liens ld utilisé par gcc propose les options -Bstatic
et -Bdynamic
pour spécifier si les bibliothèques suivant cette option doivent être liées statiquement ou dynamiquement, respectivement. Après avoir transmis -Bstatic
et une bibliothèque à l'éditeur de liens, le comportement de liaison dynamique par défaut doit être rétabli manuellement pour que les bibliothèques suivantes soient liées dynamiquement avec l'option -Bdynamic
.
Pour lier un programme, liez la bibliothèque first de manière statique (libfirst.a
) et second de manière dynamique (libsecond.so
) :
$ gcc ... -Wl,-Bstatic -lfirst -Wl,-Bdynamic -lsecond...
gcc peut être configuré pour utiliser d'autres linkers que celui par défaut ld.
Ressources supplémentaires
- Utilisation de la collection de compilateurs GNU (GCC) - 3.14 Options d'édition de liens
- Documentation pour binutils 2.27 - 2.1 Options de ligne de commande