Изменение LD_LIBRARY_PATH во время выполнения для ctypes - PullRequest
35 голосов
/ 13 мая 2009

Как обновить эту переменную среды во время выполнения, чтобы 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")

Ответы [ 4 ]

41 голосов
/ 13 мая 2009

К тому времени, когда запускается такая программа, как Python, динамический загрузчик (ld.so.1 или что-то подобное) уже прочитал LD_LIBRARY_PATH и не заметит каких-либо изменений после этого. Таким образом, если только само программное обеспечение Python не оценит LD_LIBRARY_PATH и не использует его для построения возможного пути к библиотеке для dlopen() или эквивалентной функции для использования, установка переменной в сценарии не будет иметь никакого эффекта.

Учитывая, что вы говорите, что это не работает, кажется правдоподобным предположить, что Python не собирает и не пробует все возможные имена библиотек; вероятно, он опирается только на LD_LIBRARY_PATH.

26 голосов
/ 01 декабря 2010

Даже если вы дадите полный путь к CDLL или cdll.LoadLibrary (), вам все равно может потребоваться установить LD_LIBRARY_PATH перед вызовом Python. Если разделяемая библиотека, которую вы загружаете, явно ссылается на другую разделяемую библиотеку и в .so для этой библиотеки не задан «rpath», то он не будет найден, даже если он уже был загружен. Rpath в библиотеке указывает путь поиска, который будет использоваться для поиска других библиотек, необходимых для этой библиотеки

Например, у меня есть случай с набором взаимозависимых сторонних библиотек, не созданных мной. b.so ссылки a.so. Даже если я загружаю a.so заранее:

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

Я получаю сообщение об ошибке при второй загрузке, поскольку b.so ссылается просто на «a.so», без rpath, и поэтому b.so не знает, что это правильный a.so. Поэтому мне нужно заранее установить LD_LIBRARY_PATH, чтобы включить /abs/path/to'.

Чтобы избежать необходимости устанавливать LD_LIBRARY_PATH, вы изменяете запись rpath в файлах .so. В Linux есть две утилиты, которые делают это: chrpath и patchelf . chrpath доступен в репозиториях Ubuntu. Он не может изменить rpath на .so, который никогда не был. патчелф более гибок.

15 голосов
/ 04 августа 2009

CDLL может быть передан полный путь, поэтому, например, я использую следующее в одном из моих сценариев, где .so находится в том же каталоге, что и сценарий python.

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

В вашем случае должно быть достаточно:

from ctypes import *
lib = CDLL("/home/starlon/Projects/pyCFA635/lib/libevaluator.so")
3 голосов
/ 08 февраля 2016

Скомпилируйте ваш двоичный файл с rpath относительно текущего рабочего каталога, например:

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

Затем вы можете изменить рабочий каталог в Python во время выполнения с помощью:

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

Таким образом, загрузчик также находит другие динамические библиотеки, такие как otherbinary.so

...