Изменение 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")
Ответы
Ответ 1
К моменту запуска программы, такой как Python, динамический загрузчик (ld.so.1 или что-то подобное) уже прочитал LD_LIBRARY_PATH и после этого не будет замечен никаких изменений. Таким образом, если только программное обеспечение Python не оценивает LD_LIBRARY_PATH и использует его для создания возможного имени пути библиотеки для dlopen()
или эквивалентной функции для использования, установка переменной в script не будет иметь никакого эффекта.
Учитывая, что вы говорите, что это не работает, кажется правдоподобным предположить, что Python не создает и не пытается использовать все возможные имена библиотек; он, вероятно, полагается только на LD_LIBRARY_PATH.
Ответ 2
Даже если вы даете полный путь к CDLL или cdll.LoadLibrary(), вам все равно нужно установить LD_LIBRARY_PATH перед вызовом Python. Если явная ссылка на общую библиотеку ссылается на другую разделяемую библиотеку, а в этой библиотеке не устанавливается "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, у которого его никогда не было. patchelf более гибкий.
Ответ 3
CDLL может быть передано полное имя пути, поэтому, например, я использую следующее в одном из моих сценариев, где .so находится в том же каталоге, что и python script.
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")
Ответ 4
Скомпилируйте свой двоичный файл с помощью 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