2008-12-11 14 views
13

Ich verwende Ctypes, um eine DLL in Python zu laden. Das funktioniert großartig.Wie kann ich eine DLL mit Ctypes in Python entladen?

Jetzt möchten wir in der Lage sein, diese DLL zur Laufzeit neu zu laden.

Der einfachste Ansatz scheint zu sein: 1. Unload DLL 2. Laden DLL

Leider nicht sicher, ob ich bin, was der richtige Weg, die DLL zu entladen.

_ctypes.FreeLibrary ist verfügbar, aber privat.

Gibt es eine andere Möglichkeit zum Entladen der DLL?

+0

Haben Sie eine bessere Antwort gefunden als meine hässliche Art? Wenn nicht vielleicht, sollten Sie auf ihrer Mailing-Liste fragen, und wenn es nicht vorhanden ist, melden Sie es. 'del' sollte die Funktion aufrufen, um Ressourcen zu releasen! –

Antwort

13

Sie sollten in der Lage sein, es zu tun, indem Sie das Objekt Entsorgung

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

EDIT: Hop Kommentar ist richtig, das den Namen entbindet, aber die Garbage Collection nicht geschieht so schnell, ich in der Tat sogar bezweifle, dass es sogar die geladene Bibliothek freigibt.

Ctypes scheint nicht eine saubere Art und Weise zu schaffen, Ressourcen freizugeben, ist es nur ein _handle Feld zum dlopen Griff bereitstellt ...

So ist die einzige Art, wie ich sehe, ein wirklich, wirklich nicht clean way, ist systemabhängig dlclose das handle, aber es ist sehr sehr unsauber, da außerdem ctypes interne verweise auf dieses handle behält. So nimmt Entladen etwas von der Form:

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

Es ist so unrein, dass ich nur überprüft, es funktioniert mit:

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

Ich weiß es nicht, aber ich bezweifle, dass dies die DLL entlädt. Ich nehme an, es entfernt nur die Bindung aus dem Namen im aktuellen Namespace (nach Sprachreferenz) – hop

+0

Wenn die gemeinsam genutzte Bibliothek nicht refcount dekrementiert werden kann, gibt POSIX 'dclose' ungleich Null zurück und Windows' FreeLibrary' gibt null zurück. '_ctypes.dlclose' und' _ctypes.FreeLibrary' (beachten Sie den Unterstrich) in diesem Fall 'OSError'. – eryksun

+0

Weitere Informationen zu diesem Thema finden Sie unter http: // stackoverflow.com/questions/19547084/can-i-explizit-close-a-ctypes-cdll – Gamrix

3

Es ist hilfreich in der Lage sein, die DLL zu entladen, so dass Sie die DLL neu erstellen können ohne dass Sie die Sitzung neu starten müssen, wenn Sie iPython oder einen ähnlichen Workflow verwenden. In Windows arbeiten Ich habe nur versucht, mit den Windows-DLL-Methoden zu arbeiten.

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) 

Ich weiß nicht viel von den Interna, also bin ich nicht wirklich sicher, wie sauber das ist. Ich denke, dass das Löschen von Mydll die Python-Ressourcen freigibt und der FreeLibrary-Aufruf Fenster dazu veranlasst, es freizugeben. Ich hatte angenommen, dass das Freigeben mit FreeLibary zuerst Probleme verursacht hätte, also speicherte ich eine Kopie des Bibliotheksgriffs und löste sie in der Reihenfolge, die im Beispiel gezeigt wird.

Ich basierte diese Methode auf ctypes unload dll, die das Handle explizit nach vorne geladen. Die Ladekonvention funktioniert jedoch nicht so sauber wie die einfache "ctypes.cdll.LoadLibrary ('test.dll')", also entschied ich mich für die gezeigte Methode.

+1

Das ist falsch. Ein DLL/EXE-Modul-Handle ist ein Zeiger auf die Basisadresse des Moduls, die im Allgemeinen ein 64-Bit-Wert in 64-Bit-Python ist. Aber ctypes übergibt Ganzzahlen als 32-Bit-C int-Werte; wodurch der Wert eines 64-Bit-Zeigers abgeschnitten wird. Sie müssen entweder das Handle als Zeiger umschließen, zB 'ctypes.c_void_p (mydll._handle)', oder 'kernel32.FreeLibrary.argtypes = (ctypes.c_void_p,)' deklarieren, oder stattdessen '_cypypes.FreeLibrary' aufrufen (Anmerkung der anfängliche Unterstrich, es ist das zugrunde liegende '_cypes'-Erweiterungsmodul. – eryksun