web-dev-qa-db-fra.com

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

Je compile un programme c ++ en utilisant g++ et ld. J'ai un .so bibliothèque que je veux utiliser lors de la liaison. Cependant, une bibliothèque du même nom existe dans /usr/local/lib, et ld choisit cette bibliothèque par rapport à 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
  • ajouter /my/dir au début ou à la fin de mon $PATH en` variable
  • ajouter /my/dir/libfoo.so.0 comme argument de g ++
82

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

Votre solution devrait fonctionner avec le -L/my/dir -lfoo options, utilisez LD_LIBRARY_PATH pour indiquer l'emplacement de votre bibliothèque.

Attention à utiliser LD_LIBRARY_PATH - en bref (à partir du lien):

..implications ..:
Sécurité : N'oubliez pas que les répertoires spécifiés dans LD_LIBRARY_PATH sont recherchés avant (!) Les emplacements standard? De cette manière, une personne méchante pourrait faire en sorte que votre application charge 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 dans tous les répertoires spécifiés jusqu'à ce qu'il trouve le répertoire dans lequel réside la bibliothèque partagée - pour TOUT partagé bibliothèques auxquelles 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 linéairement, et vous pourrez le savoir dès le démarrage de l'application. Si certains (ou tous les) répertoires se trouvent dans un environnement NFS, le temps de démarrage de vos applications peut être très long, voire ralentir le système dans son ensemble!
Incohérence : Il s’agit du problème le plus courant. LD_LIBRARY_PATH oblige une application à charger une bibliothèque partagée à laquelle elle n’était pas liée, ce qui est probablement incompatible avec la version originale. Cela peut être très évident, c’est-à-dire que l’application se bloque, ou cela peut donner 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.

OR

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 un répertoire standard (option gcc):

-Wl,-rpath,$(DEFAULT_LIB_INSTALL_PATH)

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

Si vous ne souhaitez pas mettre à jour de manière permanente 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 les bibliothèques que l'éditeur de liens 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)
83
stefanB

Spécifier le chemin absolu de la bibliothèque devrait fonctionner correctement:

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

Avez-vous pensé à retirer le -lfoo une fois que vous avez ajouté le chemin absolu?

20
R Samuel Klatchko

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

Vous deveniez chanceux que la chose liait du tout.

Tu avais 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 la trace des symboles à résoudre. Si elle lit d'abord la bibliothèque, elle n'a pas les symboles nécessaires, elle ignore donc les symboles qu'elle 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 à trouver.

De plus, -lfoo permet de rechercher spécifiquement un fichier nommé libfoo.a ou libfoo.so selon les besoins. Pas libfoo.so.0. Donc soit ln le nom ou renommez la bibliothèque comme il convient.

Pour citer la page de manuel de 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 à la ligne de commande de g++ aurait dû fonctionner, à moins bien entendu que vous le placiez avant bar.cpp, ce qui oblige l'éditeur de liens à l'ignorer car aucun symbole ne lui était nécessaire, étaient encore nécessaires.

17
Michael Speer

Vous pouvez également utiliser les variables d’environnement LIBRARY_PATH et CPLUS_INCLUDE_PATH, qui indique respectivement où chercher les bibliothèques et où chercher les en-têtes (CPATH fera également le travail), sans spécifier les options -L et -I.

Edit: CPATH inclut un en-tête avec -I et CPLUS_INCLUDE_PATH avec -isystem.

11
Alexandre Hamez

Si on est habitué à travailler avec DLL dans Windows et souhaite ignorer les numéros de version .so dans linux/QT, ajouter CONFIG += plugin prendra les numéros de version. Utiliser le chemin absolu vers .so, le donner à l'éditeur de liens fonctionne bien, comme l'a mentionné M. Klatchko.

0
Pekka Lehtikoski