2008-12-11 25 views
13

Estoy usando ctypes para cargar una DLL en Python. Esto funciona genial¿Cómo puedo descargar una DLL usando ctypes en Python?

Ahora nos gustaría poder volver a cargar esa DLL en tiempo de ejecución.

El enfoque directo parecería ser: 1. Descargar DLL 2. Cargar DLL

Desafortunadamente no estoy seguro de cuál es la forma correcta para descargar el archivo DLL es.

_ctypes.FreeLibrary está disponible, pero es privado.

¿Hay alguna otra forma de descargar la DLL?

+0

¿Has encontrado una mejor respuesta que mi fea manera? Si no es así, debe preguntar en su lista de correo y, si no está presente, repórtelo. 'del' debería llamar a la función para realease recursos! –

Respuesta

13

usted debería ser capaz de hacerlo disponiendo el objeto

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

EDIT: comentario Hop es correcto, esto desata el nombre, pero la recolección de basura no sucede tan rápido, de hecho, incluso duda que incluso libera la biblioteca cargada.

ctypes no parece proporcionar una forma limpia para liberar recursos, no sólo proporcionan un campo _handle al mango dlopen ...

Así que la única forma en que veo, realmente, realmente no La forma limpia, es para el sistema de forma dependiente de cerrar el controlador, pero está muy, muy sucio, ya que además ctypes mantiene referencias internas a este identificador. Por lo tanto la descarga toma algo de la forma:

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

Es tan sucio que yo sólo comprobado que funciona usando:

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) 
+0

no lo sé, pero dudo que esto descargue el dll. supongo que solo elimina el enlace del nombre en el espacio de nombre actual (según la referencia del idioma) – hop

+0

Cuando la biblioteca compartida no puede volver a calcularse como recuento, POSIX 'dlclose' devuelve un valor distinto de cero y Windows' FreeLibrary' devuelve cero. '_ctypes.dlclose' y' _ctypes.FreeLibrary' (observe el guión bajo) levanta 'OSError' en este caso. – eryksun

+0

Para las personas que buscan encontrar la manera de hacerlo en Windows, consulte http: // stackoverflow.com/questions/19547084/can-i-explicitly-close-a-ctypes-cdll – Gamrix

3

Es útil para poder descargar el archivo DLL para que pueda reconstruir el archivo DLL sin tener que reiniciar la sesión si está usando iPython o flujo de trabajo similar. Trabajando en Windows, solo intenté trabajar con los métodos relacionados con 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) 

No sé mucho de las partes internas, así que no estoy muy seguro de lo limpio que es esto. Creo que al eliminar mydll se liberan los recursos de Python y la llamada de FreeLibrary le dice a Windows que lo libere. Había asumido que la liberación con FreeLibary primero habría producido problemas, así que guardé una copia del identificador de la biblioteca y lo liberé en el orden que se muestra en el ejemplo.

Basé este método en ctypes unload dll que cargó el identificador explícitamente por adelantado. Sin embargo, la convención de carga no funciona tan limpiamente como la simple "ctypes.cdll.LoadLibrary ('test.dll')", por lo que opté por el método que se muestra.

+1

Esto está mal. Un controlador de módulo DLL/EXE es un puntero a la dirección base del módulo, que en general es un valor de 64 bits en Python de 64 bits. Pero ctypes pasa enteros como valores C 'int' de 32 bits; que truncará el valor de un puntero de 64 bits. O bien tiene que envolver el controlador como un puntero, es decir, 'ctypes.c_void_p (mydll._handle)', o declarar 'kernel32.FreeLibrary.argtypes = (ctypes.c_void_p,)', o bien llamar a '_ctypes.FreeLibrary' (nota el guión bajo inicial; es el módulo de extensión '_ctypes' subyacente). – eryksun

Cuestiones relacionadas