#define _USECASE 2 /* ===================================================== Pick an exit handling case by setting the _USECASE value above. The 4 choices are 1 - using function __attribute__((destructor)) 2 - using stdlib function atexit 3 - using Py_AtExit looked up with dlsym 4 - using Py_AtExit and __attribute__((weak)) Build this file into a shared library. On Linux use gcc -o dlibtest4.os -m32 -Wall -Werror -fPIC -c dlibtest4.c gcc -o dlibtest4.so -m32 -ldl -shared dlibtest4.os or MacOS X with gcc -o dlibtest4.os -Wall -Werror -march=i686 -c -fPIC dlibtest4.c gcc -o dlibtest4.dylib -undefined dynamic_lookup -dynamiclib dlibtest4.os Then pre-load that library with the Python binary on Linux env LD_PRELOAD=./dlibtest4.so .../python an on MacOS X env DYLD_INSERT_LIBRARIES=./dlibtest4.dylib .../python.exe Type Ctrl-D or exit() to quit python. In total, three messages should have been printed. But 3.0a1 prints only the first two *** ctor called in python... *** and never the last one *** dtor called in python... An exit status is 9 or 011 indicates that a printf error occurred on exit. /Jean Brouwers PS) To preload the library within gdb (on Linux) use gdb .../python (gdb) set environment LD_PRELOAD ./dlibtest4.so (gdb) run ..... or use setenv LD_PRELOAD ./dlibtest4.so gdb .../python (gdb) run ..... PPS) For more details on the con/destructor attributes, see the GNU gcc documentation at See also Apple's documentation DynamicLibrary.pdf which contains some excellent examples plus special MacOS X features. E.g. c/dtor must be ZPRIVATE and a static ctor can have main-like argc, argv and envp arguments! ===================================================== */ #ifndef __GNUC__ # error requires the GNU compiler #endif #include "stdio.h" #include "string.h" #include "unistd.h" extern const char* __progname; /* call printf() only if inside python[.exe] binary */ static void _print2 (const char* a1, const char* a2) { if (!strncmp("python", __progname, 6)) { if (printf("*** %s %s in %s ...\n", a1, a2, __progname) < 0) { /* printf failed, try perror but that message does not show up on 3.0a1 either */ perror("stdout closed?"); /* last resort */ _exit(9); /* note, _exit! */ } } } #if _USECASE == 1 /* con-/destructor functions */ static void __attribute__((constructor)) /* called on main() */ _ctor (void) { _print2("ctor", "called"); _print2("using", "__attribute__"); } static void __attribute__((destructor)) /* called on exit() */ _dtor (void) { _print2("dtor", "called"); } #elif _USECASE == 2 /* atexit */ #include static void _dtor (void) { _print2("dtor", "called"); } static void __attribute__((constructor)) _ctor (void) { _print2("ctor", "called"); _print2("atexit", (atexit(_dtor) ? "failed!" : "OK")); } #elif _USECASE == 3 /* dlsym Py_AtExit */ #define __USE_GNU /* for RTLD_DEFAULT */ #include static void _dtor (void) { _print2("dtor", "called"); } typedef int _AtExit_t (void(*func)(void)); /* Py_AtExit() signature */ static void __attribute__((constructor)) _ctor (void) { _AtExit_t* _AtExit; _print2("ctor", "called"); _AtExit = dlsym(RTLD_DEFAULT, "Py_AtExit"); if (_AtExit) { _print2("dlsym Py_AtExit", ((*_AtExit)(_dtor) < 0 ? "failed!" : "OK")); } else { _print2("dlsym(Py_AtExit)", "failed!"); } } #elif _USECASE == 4 /* weak Py_AtExit */ static void _dtor (void) { _print2("dtor", "called"); } extern int Py_AtExit (void(*func)(void)) __attribute__((weak)); static void __attribute__((constructor)) _ctor (void) { _print2("ctor", "called"); if (Py_AtExit) { _print2("weak Py_AtExit", (Py_AtExit(_dtor) < 0 ? "failed!" : "OK")); } else { _print2("weak Py_AtExit", "unresolved!"); } } #else # error #define _USECASE 1, 2, 3, or 4 #endif