From: Ben W. <be...@sa...> - 2008-09-28 09:02:26
|
I have run into a problem wrapping two C++ dynamic libraries for Python with SWIG. Not sure this is a SWIG-specific problem, but it seems likely that others have encountered something similar: I have a dynamic library, libbase.so, which declares and throws a custom exception. A second library, libmodule.so, calls into libbase and catches that exception. This works just fine if I link libmodule and libbase into a C++ program, or if I wrap just libmodule with SWIG. But if I also wrap libbase, and "import base" before "import module" then the C++ function in libmodule fails to catch the exception from libbase. I think this is a problem with typeinfo information not being shared (see also http://wiki.python.org/moin/boost.python/CrossExtensionModuleDependencies) and I can "fix" the problem by setting RTLD_GLOBAL with sys.setdlopenflags, but this seems a) inelegant and b) like it should be unnecessary since my custom exception is declared in a shared base library. Any better ideas what is going on? Defining a virtual destructor for the exception class seems to fix things, but then I have to be very careful to do this for each exception I define. More specifically, all of the files can be found in the attachment; the mk.sh script builds everything (at least on 32-bit Linux with Python 2.5) and demonstrates the problem. libbase simply looks like: base.h: class Exception {}; void basefunc(); base.cpp: #include <base.h> void basefunc() { throw Exception(); } base.i (notice that I don't actually wrap anything in base): %module base; %{ #include "base.h" %} libmodule looks like: module.h: void modulefunc(); module.cpp: #include <base.h> #include <module.h> #include <iostream> void modulefunc() { try { basefunc(); } catch (Exception &e) { std::cerr << "exception caught" << std::endl; } } module.i: %module module; %{ #include <iostream> #include "base.h" #include "module.h" %} %exception { try { $action; } catch(Exception &e) { std::cerr << "SWIG module caught an exception" << std::endl; } } %include "module.h" Everything can be compiled with: g++ -Wall -shared base.cpp -I. -o libbase.so g++ -Wall -shared module.cpp -I. -o libmodule.so swig -c++ -python -I. base.i swig -c++ -python -I. module.i g++ -shared -o _base.so base_wrap.cxx -I/usr/include/python2.5 -lbase -L. g++ -shared -o _module.so module_wrap.cxx -I/usr/include/python2.5 -lbase -lmodule -L. Then a simple Python script that works (i.e. it prints "exception caught"): import module module.modulefunc() ...and one that fails (the exception is not caught within libmodule *or* in the %exception handler, but terminates the interpreter): import base import module module.modulefunc() Ben -- be...@sa... http://salilab.org/~ben/ "It is a capital mistake to theorize before one has data." - Sir Arthur Conan Doyle |