Как я могу выгрузить DLL, используя ctypes в Python?

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

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

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

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

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

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

11.12.2008 14:21:06
Вы нашли лучший ответ, что мой уродливый путь? Если не может быть, вы должны спросить в их списке рассылки, и если его нет, сообщите об этом. 'del' должен вызвать функцию для освобождения ресурсов!
Piotr Lesnicki 22.01.2009 15:00:19
3 ОТВЕТА
РЕШЕНИЕ

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

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)
16
15.12.2008 22:15:14
я не знаю, но я сомневаюсь, что это выгружает DLL. я бы предположил, что это только удаляет привязку к имени в текущем пространстве имен (согласно языковой ссылке)
user3850 11.12.2008 16:17:54
Когда разделяемая библиотека не может быть уменьшена с помощью refcount, POSIX dlcloseвозвращает ненулевое значение, а Windows FreeLibraryвозвращает ноль. _ctypes.dlcloseи _ctypes.FreeLibrary(обратите внимание на подчеркивание) повышение OSErrorв этом случае.
Eryk Sun 14.02.2014 11:35:59
Для людей , которые хотят найти способ сделать это на Windows , а также см stackoverflow.com/questions/19547084/...
Gamrix 29.07.2016 18:25:56

Полезно иметь возможность выгрузить 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')», поэтому я выбрал показанный метод.

4
23.05.2017 12:02:36
Это не верно. Дескриптор модуля DLL / EXE - это указатель на базовый адрес модуля, который обычно является 64-битным значением в 64-битном Python. Но ctypes передает целые числа как 32-битные intзначения C ; который будет усекать значение 64-битного указателя. Вы должны либо обернуть дескриптор как указатель, то есть ctypes.c_void_p(mydll._handle), либо объявить kernel32.FreeLibrary.argtypes = (ctypes.c_void_p,), либо вместо вызова _ctypes.FreeLibrary(обратите внимание на начальное подчеркивание; это базовый _ctypesмодуль расширения).
Eryk Sun 23.09.2015 12:37:50

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

2
22.03.2018 03:13:34