[bind10-dev] single vs multi module for libdns++ python binding
JINMEI Tatuya / 神明達哉
jinmei at isc.org
Wed Aug 25 19:19:36 UTC 2010
At Wed, 25 Aug 2010 10:06:56 +0200,
Jelte Jansen <jelte at isc.org> wrote:
> > Is there any specific design decision on this point, or is this
> > something worth discussing?
>
> Well, it's certainly worth discussing, so let me give the reasons I
> chose to make one big module; there's no One Big Reason, just a few
> smaller ones; (btw i did intend to make separate modules for other
> wrapped libraries, such as datasrc)
Okay, these generally seem reasonable. I suggest these points be
described in the source file.
Some comments on the specific points follow:
> Most of these classes rely heavily on others, and within the
> bindings it is way easier if we have direct access to the lowlevel
> type descriptions and functions, so we can directly build objects of
> those types, instead of using the python-side interface to make them
> (for instance getting the Name from an RRset, the wrapper can now
> use the name_type PyTypeObject to build the object it returns,
> whereas if these were separate modules, it would have to use the
> python constructor, and that's at least two translation steps more,
> because we need some serialized form to pass to the constructor,
> afaict).
I guess we can workaround this with some common techniques for higher
modularity. For example, we can introduce name_python.h that only
gives a declaration of name_type:
PyTypeObject* name_type_ptr; // defined in name_python.cc
and use name_type_ptr in other .cc than name_python.cc.
We could also either define s_Name in name_python.h or if you don't
like it introduce an opaque type and a wrapper interface:
// in name_python.h
class s_Name;
typedef void* s_NamePtr;
dns::Name* getCPPNameFromPythonName(s_NamePtr p);
// which would be defined in name_python.cc like this:
{ return (&static_cast<s_Name*>(p)->name); }
Then this code in current question_python.cc...
s_Name* name;
try {
if (PyArg_ParseTuple(args, "O!O!O!", &name_type, &name, ...)) {
self->question = QuestionPtr(new Question(*name->name, ...));
...would become:
#include <name_python.h>
s_NamePtr name_ptr;
try {
if (PyArg_ParseTuple(args, "O!O!O!", name_type_ptr,
static_cast<PyObject**>(&name_ptr),...)) {
self->question = QuestionPtr(new Question(
*getCPPNameFromPythonName(name_ptr), ...));
But I admit this is still quite complicated.
> Second reason was that we'd end up with a .so for every class (or cc
> file), and it seems much more common to have one .so for the whole
> library (and you can still use 'from libdns_python import Name' for
> instance)
This seems to be a quite strong reason for the single module
approach. Out of curiosity, isn't it possible for a single .so to
contain multiple python modules? Of course, if we name it
libdns_python.so we can only do
import libdns_python
but (probably) not
import libdns_python.message
etc, but I wonder if we did "import libdns_python" we might be able to
use the libdns_python.message module.
> But yes, adding class methods is harder this way (though i don't think it's
> impossible)
Actually, it's not "hard". For trac #311, I introduced a static method:
{ "create_from_rr",
reinterpret_cast<PyCFunction>(EDNS_createFromRR),
METH_VARARGS | METH_STATIC,
... },
and the corresponding C++ function is just passed NULL for the "self"
argument. It's quite trivial, but just a bit awkward because this
function doesn't have to be a method.
---
JINMEI, Tatuya
More information about the bind10-dev
mailing list