Изменение LD_LIBRARY_PATH во время выполнения для ctypes
Вопрос
Как вы обновляете эту переменную среды во время выполнения, чтобы 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")
Решение
К моменту запуска такой программы, как Python, динамический загрузчик (ld.so.1 или что-то подобное) уже прочитал LD_LIBRARY_PATH и после этого не заметит никаких изменений.Итак, если только само программное обеспечение Python не вычисляет LD_LIBRARY_PATH и не использует его для построения возможного имени пути библиотеки для dlopen()
или эквивалентную функцию для использования, установка переменной в скрипте не будет иметь никакого эффекта.
Учитывая, что вы говорите, что это не работает, кажется правдоподобным предположить, что Python не создает и не пробует все возможные имена библиотек;вероятно, он полагается только на LD_LIBRARY_PATH .
Другие советы
Даже если вы укажете полный путь к 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, и нашивка.chrpath доступен из репозиториев Ubuntu.Он не может изменить rpath на .so, у которого его никогда не было.patchelf более гибкий.
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")
Скомпилируйте ваш двоичный файл с 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