Как я могу выгрузить DLL, используя ctypes в Python? - PullRequest
18 голосов
/ 11 декабря 2008

Я использую ctypes для загрузки DLL в Python. Это прекрасно работает.

Теперь мы хотели бы иметь возможность перезагрузить эту DLL во время выполнения.

Казалось бы, простой подход: 1. Выгрузить DLL 2. Загрузить DLL

К сожалению, я не уверен, как правильно выгружать DLL.

_ctypes.FreeLibrary доступна, но приватная.

Есть ли другой способ выгрузить DLL?

Ответы [ 3 ]

15 голосов
/ 11 декабря 2008

Вы должны быть в состоянии сделать это, выбрасывая объект

mydll = ctypes.CDLL('...')
del mydll
mydll = ctypes.CDLL('...')

РЕДАКТИРОВАТЬ: Комментарий Хопа является правильным, это отменяет привязку имени, но сборка мусора происходит не так быстро, на самом деле я даже сомневаюсь, что она даже освобождает загруженную библиотеку.

Ctypes, похоже, не обеспечивает чистого способа освобождения ресурсов, он только предоставляет поле _handle для дескриптора dlopen ...

Таким образом, единственный способ, по-настоящему, действительно неочищенный способ , состоит в том, чтобы система зависимо закрывала дескриптор, но это очень и очень нечисто, так как, кроме того, ctypes внутренне сохраняет ссылки на этот дескриптор. Таким образом, выгрузка происходит в следующем виде:

mydll = ctypes.CDLL('./mylib.so')
handle = mydll._handle
del mydll
while isLoaded('./mylib.so'):
    dlclose(handle)

Это так нечисто, что я только проверил, что работает, используя:

def isLoaded(lib):
   libp = os.path.abspath(lib)
   ret = os.system("lsof -p %d | grep %s > /dev/null" % (os.getpid(), libp))
   return (ret == 0)

def dlclose(handle)
   libdl = ctypes.CDLL("libdl.so")
   libdl.dlclose(handle)
4 голосов
/ 19 февраля 2015

Полезно иметь возможность выгрузить DLL, чтобы можно было перестроить DLL без перезапуска сеанса, если вы используете iPython или аналогичный рабочий процесс. Работая в Windows, я пытался работать только с методами, связанными с Windows DLL.

REBUILD = True
if REBUILD:
  from subprocess import call
  call('g++ -c -DBUILDING_EXAMPLE_DLL test.cpp')
  call('g++ -shared -o test.dll test.o -Wl,--out-implib,test.a')

import ctypes
import numpy

# Simplest way to load the DLL
mydll = ctypes.cdll.LoadLibrary('test.dll')

# Call a function in the DLL
print mydll.test(10)

# Unload the DLL so that it can be rebuilt
libHandle = mydll._handle
del mydll
ctypes.windll.kernel32.FreeLibrary(libHandle)

Я не знаю много внутренних органов, поэтому я не совсем уверен, насколько это чисто. Я думаю, что удаление mydll высвобождает ресурсы Python, а вызов FreeLibrary говорит Windows освободить его. Я предполагал, что сначала освобождение с помощью FreeLibary вызовет проблемы, поэтому я сохранил копию дескриптора библиотеки и освободил ее в порядке, показанном в примере.

Я основал этот метод на ctypes unload dll , который явно загружал дескриптор. Соглашение о загрузке, однако, не работает так же просто, как простое ctypes.cdll.LoadLibrary ('test.dll') ", поэтому я выбрал показанный метод.

1 голос
/ 22 марта 2018

Если вам нужна эта функциональность, вы можете написать 2 dll, где dll_A загружает / выгружает библиотеку из dll_B. Используйте dll_A как загрузчик интерфейса Python и проход для функций в dll_B.

...