Free the opened ctypes library in Python

ctypes, dll, python

Solution

Generally you shouldn't have to free a shared library. Consider that CPython doesn't provide a means to unload a regular extension module from memory. For example, importing sqlite3 will load the _sqlite3 extension and sqlite3 shared library for the life of the process. Unloading extensions is incompatible with the way CPython uses pointers as object IDs. Accessing a deallocated (and possibly reused) address would be undefined behavior.

If you need to unload or reload a shared library, and are confident that it's safe, the _ctypes extension module has POSIX `dlclose` and Windows `FreeLibrary`, which call the system functions of the same name. Both take the library handle as the single argument. This is the `_handle` attribute of a `CDLL` instance. If unloading the library fails, `OSError` is raised.

Both `dlclose` and `FreeLibrary` work by decrementing the handle's reference count. The library is unloaded when the count is decremented to 0. The count is initially 1 and gets incremented each time POSIX `dlopen` or Windows `LoadLibrary` is called for an already loaded library.

POSIX Example

#include <stdio.h>

void __attribute__((constructor)) initialize()
{
    printf("initialize\n");
}

void __attribute__((destructor)) finalize()
{
    printf("finalize\n");
}

POSIX Python

>>> import ctypes
>>> lib1 = ctypes.CDLL('./lib.so')
initialize
>>> lib2 = ctypes.CDLL('./lib.so')
>>> lib1._handle == lib2._handle
True

>>> import _ctypes
>>> _ctypes.dlclose(lib1._handle)
>>> _ctypes.dlclose(lib1._handle)
finalize

>>> lib1 = ctypes.CDLL('./lib.so')
initialize
>>> _ctypes.dlclose(lib1._handle)
finalize

Windows Example

#include <stdio.h>
#include <windows.h>

void initialize()
{
    printf("initialize\n");
}

void finalize()
{
    printf("finalize\n");
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL,
                    DWORD fdwReason,
                    LPVOID lpReserved)
{
    switch(fdwReason) 
    { 
        case DLL_PROCESS_ATTACH:
            initialize();
            break;

        case DLL_PROCESS_DETACH:
            finalize();
    }
    return TRUE;
}

Windows Python

>>> import ctypes
>>> lib1 = ctypes.CDLL('./lib.dll')
initialize
>>> lib2 = ctypes.CDLL('./lib.dll')
>>> lib1._handle == lib2._handle
True

>>> import _ctypes
>>> _ctypes.FreeLibrary(lib1._handle)
>>> _ctypes.FreeLibrary(lib1._handle)
finalize

>>> lib1 = ctypes.CDLL('./lib.dll')  
initialize
>>> _ctypes.FreeLibrary(lib1._handle)
finalize

Problem

I was wondering that, if I opened my own dll library compiled from custom c code, like this: ``` import ctypes my_lib = ctypes.cdll.LoadLibrary('./my_dll.dll') my_func = my_lib.my_func # Stuff I want to do with func() ``` Do I need to close the my_lib object after use, like a file object? Will doing this make the code cleaner, more efficient, and more "pythonic"? Thanks!

Original source