Изменение 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