web-dev-qa-db-fra.com

Définissez LD_LIBRARY_PATH avant d'importer dans python

Python utilise la variable d'environnement PYTHONPATH pour déterminer dans quels dossiers il doit rechercher les modules. Vous pouvez jouer avec lui en modifiant sys.path, Qui fonctionne bien pour les modules Python purs. Mais quand un module utilise des fichiers objets partagés ou des bibliothèques statiques, il recherche ceux dans LD_LIBRARY_PATH (Sous linux), mais cela ne peut pas être changé aussi facilement et dépend de la plate-forme pour autant que je sache.

La solution rapide pour ce problème est bien sûr de définir la variable d'environnement ou d'appeler le script comme LD_LIBRARY_PATH=. ./script.py, Mais vous devrez ensuite le redéfinir pour chaque nouveau Shell que vous ouvrez. De plus, les fichiers .so Dans mon cas seront toujours dans le même répertoire que le fichier .py, Mais peuvent très bien être déplacés vers un autre chemin absolu, donc je voudrais les définir automatiquement chaque fois que j'invoque le script.

Comment puis-je modifier le chemin dans lequel l'interpréteur Python recherche les bibliothèques indépendamment de la plate-forme lors de l'exécution?

MODIFIER:

J'ai déjà essayé os.environ['LD_LIBRARY_PATH'] = os.getcwd(), mais en vain.

34
iFreilicht

J'utiliserais:

import os

os.environ['LD_LIBRARY_PATH'] = os.getcwd()  # or whatever path you want

Cela définit le LD_LIBRARY_PATH variable d'environnement pour la durée/durée de vie de l'exécution du processus en cours uniquement.

EDIT: il semble que cela doit être défini avant de démarrer Python: Modification de LD_LIBRARY_PATH au moment de l'exécution pour les ctypes

Je suggérerais donc d'aller avec un wrapper .sh (ou .py si vous insistez) script. En outre, comme l'a souligné @chepner, vous pouvez envisager d'installer votre .so fichiers dans un emplacement standard (dans virtualenv).

Voir aussi Définition de LD_LIBRARY_PATH depuis Python

20
Erik Allik

Ma solution à ce problème est de mettre cela comme la première ligne d'un script Python (au lieu du Shebang habituel):

exec env LD_LIBRARY_PATH=/some/path/to/lib /path/to/specific/python -x "$0" "$@"

Et voici comment cela fonctionne:

  • sans Shebang, le Shell actuel traite le fichier comme un script Shell,
  • "exec" garantit que cette première ligne est également la dernière commande de ce fichier exécutée par le Shell,
  • "env" est utilisé ici pour définir toutes les variables d'environnement, par exemple LD_LIBRARY_PATH,
  • un chemin exact vers l'interpréteur de Python peut être spécifié ou "env" peut en trouver un dans PATH,
  • "-x" est une option de Python qui fait que la première ligne est ignorée par l'interpréteur Python,
  • "$ 0" est le nom du script, "$ @" est remplacé par des paramètres de position.
7
Jarek

Python, quand obtient les valeurs des variables d'environnement comme dans os.environ[‘LD_LIBRARY_PATH’] ou os.environ[‘PATH’], il copie les valeurs, dans un dictionnaire, à partir de l'environnement de son processus parent, généralement bash (l'environnement du processus bash est transféré au processus enfant, l'instance python en cours d'exécution).

vous pouvez voir cette section de variable d'environnement avec la sortie de commande env de bash.

vous pouvez également voir/lire ces données env à partir de /proc/<pid>/environ, en introduisant une boucle infinie (while 1: pass) après avoir modifié une variable d'environnement.

Si vous voyez/lisez cette valeur de variable/données de /proc/<pid>/environ après l'avoir modifié à l'intérieur du script python, vous pourriez voir que les données de la variable réelle ne sont pas modifiées, bien que le script python montre un valeur de clé de dictionnaire modifiée, mise à jour.

Que se passe-t-il réellement lorsque vous modifiez une variable env à l'intérieur du script python, comme dans os.environ['LD_LIBRARY_PATH']='/<new_location>', c'est qu'il met juste à jour la valeur dans le dictionnaire local, qui n'est pas mappée à la section variable env du processus. Par conséquent, il ne se propagera pas tout le temps pour se refléter dans l'environnement du processus actuel, car NIQUEMENT un dictionnaire local a été modifié/mis à jour/rempli.

Par conséquent, si nous voulons que la nouvelle variable d'environnement soit reflétée, nous devons remplacer l'image mémoire du processus par de nouvelles données de variable d'environnement, en utilisant execv.

Exemple:

new_lib = '/<new_location>'
if not new_lib in os.environ['LD_LIBRARY_PATH']:
    os.environ['LD_LIBRARY_PATH'] += ':'+new_lib
    try:
        os.execv(sys.argv[0], sys.argv)
    except Exception as e:
        sys.exit('EXCEPTION: Failed to Execute under modified environment, '+e)

import xyz
#do something else

Limitation: Idéalement, python ne devrait pas permettre une telle modification de os.environ variables. Mais comme il n'y a pas de type de données de dictionnaire constant, il permet de modifier la variable de données. Il est absolument inutile de modifier les valeurs, car cela n'a rien d'utile à refléter dans l'environnement réel du processus en cours d'exécution, à moins que execv ne soit utilisé.

3
S471