2009-05-13 10 views
29

Comment mettre à jour cette variable d'environnement lors de l'exécution pour que ctypes puisse charger une bibliothèque où que ce soit? J'ai essayé ce qui suit et aucun ne semble fonctionner.Modification de LD_LIBRARY_PATH au moment de l'exécution pour ctypes

from ctypes import * 
os.environ['LD_LIBRARY_PATH'] = "/home/starlon/Projects/pyCFA635/lib" 
os.putenv('LD_LIBRARY_PATH', "/home/starlon/Projects/pyCFA635/lib") 
lib = CDLL("libevaluator.so") 

Répondre

35

Au moment où un programme tel que Python est en cours d'exécution, le chargeur dynamique (ld.so.1 ou quelque chose de similaire) a déjà lu LD_LIBRARY_PATH et ne remarqueront aucun changement par la suite. Ainsi, à moins que le logiciel Python évalue lui-même LD_LIBRARY_PATH et l'utilise pour construire le nom de chemin possible de la bibliothèque pour dlopen() ou une fonction équivalente à utiliser, la définition de la variable dans le script n'aura aucun effet. Etant donné que vous dites que cela ne fonctionne pas, il semble plausible de supposer que Python ne construit pas et n'essaye pas tous les noms de bibliothèques possibles; il repose probablement sur LD_LIBRARY_PATH seul.

+5

ceci diagnostique le problème mais ne le résout pas. – dbliss

13

CDLL peut recevoir un nom de chemin qualifié complet. Par exemple, j'utilise ce qui suit dans l'un de mes scripts, où .so se trouve dans le même répertoire que le script python.

import os 
path = os.path.dirname(os.path.realpath(__file__)) 
dll = CDLL("%s/iface.so"%path) 

Dans votre cas, les éléments suivants devraient suffire.

from ctypes import * 
lib = CDLL("/home/starlon/Projects/pyCFA635/lib/libevaluator.so") 
21

Même si vous donnez un chemin complet CDLL ou cdll.LoadLibrary(), vous pouvez toujours besoin de mettre LD_LIBRARY_PATH avant d'appeler Python. Si la bibliothèque partagée que vous chargez fait explicitement référence à une autre bibliothèque partagée et qu'aucun "rpath" n'est défini dans le fichier .so pour cette bibliothèque, alors elle ne sera pas trouvée, même si elle a déjà été chargée. Un rpath dans une bibliothèque spécifie un chemin de recherche à utiliser pour rechercher les autres bibliothèques nécessaires à cette bibliothèque

Par exemple, j'ai un cas d'un ensemble de bibliothèques tierces interdépendantes que je n'ai pas produites. b.so références a.so. Même si je charge a.so à l'avance:

ctypes.cdll.LoadLibrary('/abs/path/to/a.so') 
ctypes.cdll.LoadLibrary('/abs/path/to/b.so') 

Je reçois une erreur sur la deuxième charge, car b.so se réfère simplement « a.so », sans rpath, et ainsi b.so n » Je sais que c'est le bon a.so. Donc, je dois définir LD_LIBRARY_PATH à l'avance pour inclure '/ abs/path/to'. Pour éviter d'avoir à définir LD_LIBRARY_PATH, vous modifiez l'entrée rpath dans les fichiers .so

Sous Linux, il y a deux utilitaires que j'ai trouvés: chrpath, et patchelf. chrpath est disponible depuis les dépôts Ubuntu. Il ne peut pas changer rpath sur .so qui n'en a jamais eu un. patchelf est plus flexible.

1

compiler votre binaire avec un rpath par rapport au répertoire de travail courant comme:

gcc -shared -o yourbinary.so yoursource.c otherbinary.so \ 
    -Wl,-rpath='.',-rpath='./another/relative/rpath' -fpic 

Ensuite, vous êtes en mesure de changer le répertoire de travail en python à l'exécution avec:

import os 
os.chdir('/path/to/your/binaries') 

Vous aimez cette , le chargeur trouve également d'autres bibliothèques dynamiques comme otherbinary.so

+0

Cela ne fonctionne que lorsque le répertoire de travail du processus chargeant la bibliothèque est le répertoire de la bibliothèque. Sinon, le chemin d'exécution relatif n'est pas capable de trouver la dépendance, dont le répertoire est relatif à la bibliothèque. – danny

Questions connexes