[pypy-dev] okay to rename cppyy -> _cppyy

wlavrijsen at lbl.gov wlavrijsen at lbl.gov
Thu Jul 20 21:17:47 EDT 2017


Hi,

[replying to self]

> And yes, it is technically possible to write a bindings generator that only
> depends on LLVM during offline bindings generation, not at run-time. But
> then you'd just have SWIG (albeit with a standards-compliant parser).

it hit me yesterday that instead of generating something offline for cppyy
to read, you could also use cppyy_backend directly to generate a pure python
module for use with cffi as it knows about sizes, offsets, name mangling,
class relations etc., etc., etc.

(The point is that cppyy_backend exposes a minimalistic C-API, which itself
can be bound with cffi, as _cppyy in fact does.)

(There are still wrappers needed for inlined functions, overloaded
operator new, virtual inheritance offsets, etc., but those could be stuffed
in a .cxx on the side of the cffi-based Python module. Can't solve automatic
template instantiation this way, though: cppyy will always be superior.)

So, I wrote a quick proof of concept (https://bitbucket.org/wlav/quaff/src):

  $ cat Simple.h
  class Simple {
  public:
      Simple();
      Simple(int);
      virtual ~Simple();

  public:
      int get_data();
      void set_data(int);

  private:
      int m_data;
  };

  $ cat Simple.cxx
  #include "Simple.h"

  Simple::Simple() : m_data(42) { }
  Simple::Simple(int i) : m_data(i) { }
  Simple::~Simple() { }

  int Simple::get_data() { return m_data; }
  void Simple::set_data(int i) { m_data = i; }

  $ g++ -shared -o libsimple.so -fPIC Simple.cxx

  $ python
  >>>> from quaff import generate
  >>>> generate.generate_class('simple', 'Simple', 'libsimple.so')
  >>>> import simple
  >>>> s1 = simple.Simple()
  >>>> s1.get_data()
  42
  >>>> s1.set_data(13)
  >>>> s1.get_data()
  13
  >>>> s2 = simple.Simple(99)
  >>>> s2.get_data()
  99
  >>>>

What quaff generated looks like this:

  $ cat simple.py
  from cffi import FFI

  _ffi = FFI()

  _ffi.cdef("""
  void _ZN6SimpleC1Ev(void*);
  void _ZN6SimpleC1Ei(void*, int);
  int _ZN6Simple8get_dataEv(void*);
  void _ZN6Simple8set_dataEi(void*, int);
  """)

  _dll = _ffi.dlopen('libsimple.so')

  class Simple(object):
    def __init__(self, *args):
      self._cpp_this = _ffi.new('char[]', 16)
      if len(args) == 0:
        _dll._ZN6SimpleC1Ev(self._cpp_this, *args)
      if len(args) == 1:
        _dll._ZN6SimpleC1Ei(self._cpp_this, *args)
    def get_data(self, *args):
      return _dll._ZN6Simple8get_dataEv(self._cpp_this, *args)
    def set_data(self, *args):
      return _dll._ZN6Simple8set_dataEi(self._cpp_this, *args)

which is nicely standalone for distribution (yes, the result is platform
specific, but no more so than a binary .so and way better than a Python
extension module).

Best regards,
            Wim
-- 
WLavrijsen at lbl.gov    --    +1 (510) 486 6411    --    www.lavrijsen.net


More information about the pypy-dev mailing list