Comment spécifier la préférence du chemin de la bibliothèque?

91

Je compile un programme C ++ en utilisant g++et ld. J'ai une .sobibliothèque que je souhaite utiliser lors de la liaison. Cependant, une bibliothèque du même nom existe dans /usr/local/libet ldchoisit cette bibliothèque plutôt que celle que je spécifie directement. Comment puis-je réparer cela?

Pour les exemples ci-dessous, mon fichier de bibliothèque est /my/dir/libfoo.so.0. Les choses que j'ai essayées qui ne fonctionnent pas:

  • ma commande g ++ est g++ -g -Wall -o my_binary -L/my/dir -lfoo bar.cpp
  • ajout /my/dirau début ou à la fin de ma $PATHvariable en`
  • ajout /my/dir/libfoo.so.0comme argument à g ++
Heinrich Schmetterling
la source
1
Quels sont les autres libfoo.*fichiers existent et où - .sow / o .0, .a, etc etc?
Alex Martelli

Réponses:

92

Ajoutez le chemin d'accès à votre nouvelle bibliothèque LD_LIBRARY_PATH(son nom est légèrement différent sur Mac ...)

Votre solution doit fonctionner avec l'utilisation du -L/my/dir -lfoo options, à l'exécution, utilisez LD_LIBRARY_PATH pour pointer vers l'emplacement de votre bibliothèque.

Attention à l'utilisation de LD_LIBRARY_PATH - en bref (à partir du lien):

..implications ..:
Sécurité : Vous vous souvenez que les répertoires spécifiés dans LD_LIBRARY_PATH sont recherchés avant (!) les emplacements standard? De cette façon, une personne méchante pourrait amener votre application à charger une version d'une bibliothèque partagée contenant du code malveillant! C'est une des raisons pour lesquelles les exécutables setuid / setgid négligent cette variable!
Performance: Le chargeur de liens doit rechercher tous les répertoires spécifiés, jusqu'à ce qu'il trouve le répertoire où réside la bibliothèque partagée - pour TOUTES les bibliothèques partagées, l'application est liée! Cela signifie beaucoup d'appels système à open (), qui échoueront avec «ENOENT (aucun fichier ou répertoire de ce type)»! Si le chemin contient de nombreux répertoires, le nombre d'appels ayant échoué augmentera de manière linéaire, et vous pouvez le voir dès le démarrage de l'application. Si certains (ou tous) des répertoires se trouvent dans un environnement NFS, le temps de démarrage de vos applications peut vraiment être long - et cela peut ralentir tout le système!
Incohérence: C'est le problème le plus courant. LD_LIBRARY_PATH force une application à charger une bibliothèque partagée avec laquelle elle n'était pas liée, et qui n'est probablement pas compatible avec la version originale. Cela peut être très évident, c'est-à-dire que l'application plante, ou cela peut conduire à des résultats erronés, si la bibliothèque récupérée ne fait pas tout à fait ce que la version originale aurait fait. Surtout ce dernier est parfois difficile à déboguer.

OU

Utilisez l'option rpath via gcc vers l'éditeur de liens - le chemin de recherche de la bibliothèque d'exécution sera utilisé au lieu de chercher dans le répertoire standard (option gcc):

-Wl,-rpath,$(DEFAULT_LIB_INSTALL_PATH)

C'est bon pour une solution temporaire. Linker recherche d'abord LD_LIBRARY_PATH pour les bibliothèques avant de rechercher dans les répertoires standard.

Si vous ne souhaitez pas mettre à jour définitivement LD_LIBRARY_PATH, vous pouvez le faire à la volée en ligne de commande:

LD_LIBRARY_PATH=/some/custom/dir ./fooo

Vous pouvez vérifier ce que l'éditeur de liens de bibliothèques sait utiliser (exemple):

/sbin/ldconfig -p | grep libpthread
        libpthread.so.0 (libc6, OS ABI: Linux 2.6.4) => /lib/libpthread.so.0

Et vous pouvez vérifier quelle bibliothèque votre application utilise:

ldd foo
        linux-gate.so.1 =>  (0xffffe000)
        libpthread.so.0 => /lib/libpthread.so.0 (0xb7f9e000)
        libxml2.so.2 => /usr/lib/libxml2.so.2 (0xb7e6e000)
        librt.so.1 => /lib/librt.so.1 (0xb7e65000)
        libm.so.6 => /lib/libm.so.6 (0xb7d5b000)
        libc.so.6 => /lib/libc.so.6 (0xb7c2e000)
        /lib/ld-linux.so.2 (0xb7fc7000)
        libdl.so.2 => /lib/libdl.so.2 (0xb7c2a000)
        libz.so.1 => /lib/libz.so.1 (0xb7c18000)
stefanB
la source
21
LD_LIBRARY_PATHest recherché au moment de l'exécution, au moment de la compilation que vous souhaitez définir LIBRARY_PATH. Voir gcc.gnu.org/onlinedocs/gcc/Environment-Variables.html
Bjoern Dahlgren
1
Si votre bibliothèque est complètement différente de la bibliothèque système, c'est-à-dire qu'elle est toujours à utiliser, veuillez utiliser la solution rpath. LD_LIBRARY_PATH est un hack pour les tests et ne devrait pas être nécessaire pour faire fonctionner correctement un exécutable.
user2746401
1
son DYLD_LIBRARY_PATH pour Mac
cbinder
Voici un exemple de commande complet (pour C) qui fonctionne sur la base de cette réponse:gcc myFile.c -o myFile.o -l myLibraryBaseName -Wl,-rpath,locationOfMyLibrary -L locationOfMyLibrary
Jet Blue
25

C'est une vieille question, mais personne ne semble l'avoir mentionné.

Vous aviez de la chance que la chose soit reliée.

Vous aviez besoin de changer

g++ -g -Wall -o my_binary -L/my/dir -lfoo bar.cpp

pour ça:

g++ -g -Wall -o my_binary -L/my/dir bar.cpp -lfoo

Votre éditeur de liens garde une trace des symboles qu'il doit résoudre. S'il lit la bibliothèque en premier, il n'a aucun symbole nécessaire, il ignore donc les symboles qu'il contient. Spécifiez les bibliothèques après les éléments qui doivent y être liés afin que votre éditeur de liens ait des symboles à y trouver.

En outre, -lfooil recherche spécifiquement un fichier nommé libfoo.aou libfoo.soselon les besoins. Non libfoo.so.0. Donc, soit lnle nom, soit renommer la bibliothèque comme approprié.

Pour citer la page de manuel gcc:

-l library
   ...
   It makes a difference where in the command you 
   write this option; the linker searches and processes 
   libraries and object files in the order they are 
   specified.  Thus, foo.o -lz bar.o searches library z 
   after file foo.o but before bar.o.  If bar.o refers 
   to functions in z, those functions may not be loaded.

Ajouter le fichier directement à g++la ligne de commande de la ligne de commande aurait dû fonctionner, à moins bien sûr que vous ne le mettiez avant bar.cpp, ce qui oblige l'éditeur de liens à l'ignorer faute de symboles nécessaires, car aucun symbole n'était encore nécessaire.

Michael Speer
la source
21

La spécification du chemin absolu vers la bibliothèque devrait fonctionner correctement:

g++ /my/dir/libfoo.so.0  ...

Avez-vous pensé à supprimer le -lfooune fois que vous avez ajouté le chemin absolu?

R Samuel Klatchko
la source
1
Cette solution a également bien fonctionné pour moi - en essayant de créer un lien avec une version de Qt5 autre que le package de développement de distribution. Merci.
wump
Comment faire fonctionner cela pour les @symboles versionnés? Exemple minimal: github.com/cirosantilli/cpp-cheat/blob/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
11

Comme alternative, vous pouvez utiliser les variables d'environnement LIBRARY_PATHet CPLUS_INCLUDE_PATH, qui indiquent respectivement où chercher les bibliothèques et où chercher les en-têtes ( CPATHferont également le travail), sans spécifier les options -L et -I.

Edit: CPATHinclut l'en-tête avec -Iet CPLUS_INCLUDE_PATHavec -isystem.

Alexandre Hamez
la source
Pourriez-vous s'il vous plaît ajouter un exemple d'utilisation?
Hanna Khalil
export LIBRARY_PATH = /path/to/libdans la même session console où vous compilez
Alexandre Hamez
0

Si l'un d'entre eux est utilisé pour travailler avec DLL sous Windows et que vous souhaitez ignorer les numéros de version .so dans Linux / QT, l'ajout CONFIG += pluginsupprimera les numéros de version. Pour utiliser le chemin absolu vers .so, le donner à l'éditeur de liens fonctionne bien, comme l'a mentionné M. Klatchko.

Pekka Lehtikoski
la source