[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