85 votes

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

Je compile un programme c++ en utilisant g++ y ld . J'ai un .so que je veux utiliser lors de la création de liens. Cependant, une bibliothèque du même nom existe dans le fichier /usr/local/lib y ld choisit cette bibliothèque au lieu de celle que je spécifie directement. Comment puis-je résoudre ce problème ?

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

  • ma commande g++ est g++ -g -Wall -o my_binary -L/my/dir -lfoo bar.cpp
  • en ajoutant /my/dir au début ou à la fin de mon $PATH en` variable
  • en ajoutant /my/dir/libfoo.so.0 comme argument à g++

86voto

stefanB Points 27796

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

Votre solution devrait fonctionner avec l'utilisation du -L/my/dir -lfoo à l'exécution, utilisez LD_LIBRARY_PATH pour indiquer 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 Ainsi, une personne mal intentionnée pourrait faire en sorte que votre application charge une version d'un fichier bibliothèque partagée qui contient du code malveillant ! C'est l'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ù se trouve la bibliothèque partagée. réside - pour TOUTES les bibliothèques partagées avec lesquelles l'application est liée ! Cela signifie beaucoup d'appels système à open(), qui échoueront avec "ENOENT (No such file or directory)" ! Si le chemin contient de nombreux répertoires, le nombre d'appels échoués augmentera de manière linéaire, et vous pouvez le constater en observant le temps de démarrage de l'application. Si certains (ou tous) les répertoires se trouvent dans un environnement NFS, le temps de de démarrage de vos applications peut vraiment devenir long - et cela peut ralentir l'ensemble du 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'a pas été liée, et qui n'est probablement pas compatible avec la bibliothèque originale. avec laquelle elle n'a pas été liée, et qui n'est très probablement pas version originale. Ce problème peut être très évident, c'est-à-dire que l'application l'application se bloque, ou cela peut conduire à des résultats erronés, si la bibliothèque récupérée fait pas tout à fait ce que la version originale aurait fait. Ce dernier cas Ce dernier cas est parfois difficile à déboguer.

OU

Utiliser l'option rpath via gcc pour 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 une bonne solution temporaire. Le linker recherche d'abord les bibliothèques dans LD_LIBRARY_PATH avant de chercher dans les répertoires standards.

Si vous ne voulez pas mettre à jour de façon 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 quelles sont les bibliothèques connues par le linker en utilisant (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)

33voto

Michael Speer Points 911

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

Vous avez eu de la chance que cette chose soit reliée à tout ça.

Vous deviez changer

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

à ça :

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

Votre éditeur de liens garde la trace des symboles qu'il doit résoudre. S'il lit la bibliothèque en premier, elle ne contient aucun symbole nécessaire, donc il ignore les symboles qu'elle contient. Spécifiez les bibliothèques après les éléments qui doivent de se lier à elles afin que votre éditeur de liens ait des symboles à trouver dans ces bibliothèques.

Aussi, -lfoo le fait rechercher spécifiquement un fichier nommé libfoo.a o libfoo.so au besoin. Non libfoo.so.0 . Donc, soit ln le nom ou renommer la bibliothèque selon le cas.

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 à g++ de la ligne de commande devrait avoir fonctionné, sauf, bien sûr, si vous l'avez placé avant bar.cpp ce qui fait que l'éditeur de liens l'ignore parce qu'il n'y a pas de symboles nécessaires, car aucun symbole n'est encore nécessaire.

21voto

R Samuel Klatchko Points 44549

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

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

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

11voto

Alexandre Hamez Points 1537

Comme alternative, vous pouvez utiliser les variables d'environnement LIBRARY_PATH y CPLUS_INCLUDE_PATH qui indiquent respectivement où chercher les bibliothèques et où chercher les en-têtes ( CPATH fera également l'affaire), sans spécifier les options -L et -I.

Edit : CPATH inclut l'en-tête avec -I y CPLUS_INCLUDE_PATH con -isystem .

0voto

Si l'on a l'habitude de travailler avec des DLL sous Windows et que l'on souhaite se passer des numéros de version .so sous linux/QT, il suffit d'ajouter CONFIG += plugin enlèvera les numéros de version. Pour utiliser le chemin absolu du .so, le donner au linker fonctionne bien, comme l'a mentionné M. Klatchko.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X