Pourquoi Python ne trouve-t-il pas les objets partagés qui se trouvent dans les répertoires de sys.path?

124

J'essaye d'importer pycurl:

$ python -c "import pycurl"
Traceback (most recent call last):
File "<string>", line 1, in <module>
ImportError: libcurl.so.4: cannot open shared object file: No such file or directory

Maintenant, libcurl.so.4c'est parti /usr/local/lib. Comme vous pouvez le voir, c'est dans sys.path:

$ python -c "import sys; print(sys.path)"
['', '/usr/local/lib/python2.5/site-packages/setuptools-0.6c9-py2.5.egg', 
'/usr/local/lib/python25.zip', '/usr/local/lib/python2.5', 
'/usr/local/lib/python2.5/plat-linux2', '/usr/local/lib/python2.5/lib-tk', 
'/usr/local/lib/python2.5/lib-dynload', 
'/usr/local/lib/python2.5/sitepackages', '/usr/local/lib', 
'/usr/local/lib/python2.5/site-packages']

Toute aide sera fortement appréciée.

BR123
la source
Voir ma réponse mise à jour, au cas où vous n'auriez pas défini LD_LIBRARY_PATHcorrectement (je pensais que votre commentaire avait un deux-points manquant).
Vinay Sajip
1
Y a-t-il un lien symbolique cassé quelque part nommé libcurl.so.4? Il me semble qu'il trouve le fichier mais qu'il est incapable de l'ouvrir. Si tout le reste échoue, stracez l'interpréteur et recherchez l'appel échoué.
Charles Duffy

Réponses:

158

sys.pathn'est recherché que pour les modules Python. Pour les bibliothèques liées dynamiques, les chemins recherchés doivent être dans LD_LIBRARY_PATH. Vérifiez si votre LD_LIBRARY_PATHinclut /usr/local/lib, et si ce n'est pas le cas, ajoutez-le et réessayez.

Quelques informations supplémentaires ( source ):

Sous Linux, la variable d'environnement LD_LIBRARY_PATH est un ensemble de répertoires séparés par deux-points où les bibliothèques doivent être recherchées en premier, avant l'ensemble standard de répertoires; cela est utile lors du débogage d'une nouvelle bibliothèque ou de l'utilisation d'une bibliothèque non standard à des fins spéciales. La variable d'environnement LD_PRELOAD répertorie les bibliothèques partagées avec des fonctions qui remplacent l'ensemble standard, tout comme le fait /etc/ld.so.preload. Ceux-ci sont implémentés par le chargeur /lib/ld-linux.so. Je dois noter que, bien que LD_LIBRARY_PATH fonctionne sur de nombreux systèmes de type Unix, il ne fonctionne pas sur tous; par exemple, cette fonctionnalité est disponible sur HP-UX mais en tant que variable d'environnement SHLIB_PATH, et sous AIX, cette fonctionnalité se fait via la variable LIBPATH (avec la même syntaxe, une liste séparée par deux-points).

Mise à jour: pour définir LD_LIBRARY_PATH, utilisez l'un des éléments suivants, idéalement dans votre ~/.bashrc fichier ou équivalent:

export LD_LIBRARY_PATH=/usr/local/lib

ou

export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH

Utilisez le premier formulaire s'il est vide (équivalent à la chaîne vide, ou pas du tout présent), et le second formulaire s'il ne l'est pas. Notez l'utilisation de l' exportation .

Vinay Sajip
la source
2
Merci. Mon LD_LIBRARY_PATH n'a pas été défini, donc: $ LD_LIBRARY_PATH = / usr / local / lib $ LD_LIBRARY_PATH / usr / local / lib Mais j'obtiens toujours la même erreur: $ python -c "import pycurl" Traceback (dernier appel en dernier): Fichier "<string>", ligne 1, dans <module> ImportError: libcurl.so.4: impossible d'ouvrir le fichier objet partagé: aucun fichier ou répertoire de ce type
2
J'ai également dû donner des autorisations à mon utilisateur pour lire la bibliothèque après avoir défini la variable LD_LIBRARY_PATH. Maintenant ça marche enfin.
José Ricardo
56

Assurez-vous que votre module libcurl.so se trouve dans le chemin de la bibliothèque système, qui est distinct et séparé du chemin de la bibliothèque python.

Une «solution rapide» consiste à ajouter ce chemin à une variable LD_LIBRARY_PATH. Cependant, définir ce système à l'échelle du système (ou même à l'échelle du compte) est une mauvaise idée, car il est possible de le configurer de telle sorte que certains programmes trouvent une bibliothèque qu'il ne devrait pas, ou pire encore, ouvrir des failles de sécurité.

Si vos "bibliothèques installées localement" sont installées dans, par exemple, / usr / local / lib, ajoutez ce répertoire à /etc/ld.so.conf (c'est un fichier texte) et exécutez "ldconfig"

La commande exécutera un utilitaire de mise en cache, mais créera également tous les "liens symboliques" nécessaires au fonctionnement du système de chargement. Il est surprenant que le "make install" de libcurl n'ait pas déjà fait cela, mais il est possible qu'il ne le fasse pas si / usr / local / lib n'est pas déjà dans /etc/ld.so.conf.

PS: il est possible que votre /etc/ld.so.conf ne contienne rien d'autre que "include ld.so.conf.d / *. Conf". Vous pouvez toujours ajouter un chemin de répertoire après lui, ou simplement créer un nouveau fichier dans le répertoire à partir duquel il est inclus. N'oubliez pas d'exécuter "ldconfig" après.

Faites attention. Se tromper peut endommager votre système.

De plus: assurez-vous que votre module python est compilé avec CETTE version de libcurl. Si vous venez de copier des fichiers à partir d'un autre système, cela ne fonctionnera pas toujours. En cas de doute, compilez vos modules sur le système sur lequel vous comptez les exécuter.

Ch'marr
la source
Merci - cela a fonctionné. Je me demande pourquoi ma précédente tentative de "correction rapide" de la variable LD_LIBRARY_PATH ne l'a pas fait.
2
Dépend de nombreux facteurs. Voici une possibilité: votre code était exécuté depuis apache ou cron. Ces programmes "nettoient" généralement l'environnement, vous devez donc faire des choses supplémentaires pour y insérer les variables d'environnement. Par exemple, "SetEnv" dans apache, ou définir la variable directement dans le fichier crontab pour cron. Les possibilités d'erreurs sont infinies!
Ch'marr le
24

Vous pouvez également définir LD_RUN_PATH sur / usr / local / lib dans votre environnement utilisateur lorsque vous compilez pycurl en premier lieu. Cela intégrera / usr / local / lib dans l'attribut RPATH du module d'extension C. Afin qu'il sache automatiquement où trouver la bibliothèque au moment de l'exécution sans avoir à définir LD_LIBRARY_PATH au moment de l'exécution.

Graham Dumpleton
la source
4
Vous pouvez également l'utiliser python setup.py build_ext --rpath=/usr/local/liblors de la construction du module d'extension pour cuire dans le rpath
kynan
10

Eu exactement le même problème. J'ai installé curl 7.19 dans / opt / curl / pour m'assurer que je n'affecterais pas la boucle actuelle sur nos serveurs de production. Une fois que j'ai lié libcurl.so.4 à / usr / lib:

sudo ln -s /opt/curl/lib/libcurl.so /usr/lib/libcurl.so.4

J'ai toujours la même erreur! Durf.

Mais exécuter ldconfig a créé le lien pour moi et cela a fonctionné. Il n'est pas du tout nécessaire de définir LD_RUN_PATH ou LD_LIBRARY_PATH. Juste besoin d'exécuter ldconfig.

Mat
la source
Et si je n'ai pas le privilège sudo? Je ne peux pas exécuter ldconfig? Existe-t-il alors un moyen d'effacer l'erreur ci-dessus?
Prasanna
2
@SPRajagopal: si vous ne disposez pas des privilèges pour modifier les attributs système, vous devez utiliser la LD_LIBRARY_PATHméthode de variable d'environnement décrite ci-dessus. Si vous ne voulez pas le définir dans votre ~/.bashrc(ajouter ce paramètre n'est pas une bonne idée IMO), vous pouvez écrire un script shell qui définit cette variable puis exécute python, puis appelez ce script.
MadScientist
8

En complément des réponses ci-dessus, je me heurte simplement à un problème similaire et je travaille complètement avec le python installé par défaut.

Lorsque j'appelle l'exemple de la bibliothèque d'objets partagés avec laquelle je recherche LD_LIBRARY_PATH, j'obtiens quelque chose comme ceci:

$ LD_LIBRARY_PATH=/path/to/mysodir:$LD_LIBRARY_PATH python example-so-user.py
python: can't open file 'example-so-user.py': [Errno 2] No such file or directory

Notamment, il ne se plaint même pas de l'importation - il se plaint du fichier source!

Mais si je force le chargement de l'objet en utilisant LD_PRELOAD:

$ LD_PRELOAD=/path/to/mysodir/mypyobj.so python example-so-user.py
python: error while loading shared libraries: libtiff.so.5: cannot open shared object file: No such file or directory

... J'obtiens immédiatement un message d'erreur plus significatif - à propos d'une dépendance manquante!

Je pensais juste que je noterais ceci ici - bravo!

sdaau
la source
Êtes-vous sûr que ce n'est pas une nouvelle erreur qui se produit avant l'erreur OP?
David Knipe
1

J'utilise python setup.py build_ext -R/usr/local/lib -I/usr/local/include/libcalg-1.0et le fichier .so compilé se trouve dans le dossier de construction. vous pouvez taper python setup.py --help build_extpour voir les explications de -R et -I

ScutterKey
la source
1

Pour moi, ce qui fonctionne ici est d'utiliser un gestionnaire de versions tel que pyenv , que je recommande fortement pour que vos environnements de projet et vos versions de packages soient bien gérés et séparés de ceux du système d'exploitation.

J'ai eu cette même erreur après une mise à jour du système d'exploitation, mais a été facilement corrigée avec pyenv install 3.7-dev j'ai (la version que j'utilise).

elcortegano
la source