[Cython] bug: constructor declarations not working

Marcus Brinkmann marcus.brinkmann at ruhr-uni-bochum.de
Sun Aug 17 06:07:54 CEST 2014


Hi,

ok, this is not as easy as I originally thought.  I fixed a couple of 
things that prevented the suggested syntax from working, but the linking 
stage has additional challenges, as there is currently no support for 
cimporting a native cppclass from one module to another (akin to the 
"api" feature or the "public" symbol import function feature).  It's 
also not sure how this should work exactly, so I am giving up.

I settled on a work around using "cdef public" C functions and making 
use of cimport and the automatic symbol import feature.  This does not 
give access to the full type, but it's sufficient for my use case.

The following two changes were somewhat useful in my explorations:

1. Fix the "this" pointer misreference.  This is an actual bug, so I 
made a pull request:

https://github.com/cython/cython/pull/316

2. The missing constructor declaration generated when cimporting the pxd 
file is easy to fix by not testing for "defining or name != "<init>") in 
CppClassScope.  However, this breaks a test case, because 
NewExprNode.inferType adds the implicit default constructor under the 
name "<init>" without a proper cname.  So I made a larger change that 
fixes this, too:

https://github.com/lambdafu/cython/tree/lambdafu/cpp_declare_constructor

I didn't make a pull request, because currently cimport'ing an external 
cppclass declaration is not useful without some way to add the runtime 
dependency as well...

Thanks and sorry for the noise.  It wasn't entirely clear to me what the 
state of cppclass support in Cython is until I read the source code.

Marcus


On 08/12/2014 04:57 AM, Marcus Brinkmann wrote:
> Hi,
>
> I want to declare and define C++ classes from Cython.  Sure, I could
> write them in native C++, but it's just small glue code, and I prefer to
> let Cython handle the GIL and all the other good stuff.
>
> First, for reference, the following works (c.f.
> tests/run/cpp_classes_def.pyx):
>
> == cython --cplus example1.pyx ============
> cdef cppclass Foo "Foo":
>    int _foo
>    __init__(int foo) nogil:
>      this._foo = foo
>    __dealloc__() nogil:
>      pass
> ===========================================
>
> This will emit a declaration for Foo and the implementations of the
> constructor and destructor (output is truncated to show relevant parts
> only):
>
> struct Foo {
>    int _foo;
>     Foo(int);
>    virtual  ~Foo(void);
> };
>   Foo::Foo(int __pyx_v_foo) {
>    this->_foo = __pyx_v_foo;
> }
>   Foo::~Foo(void) {
> }
>
> Now, I want to export the class to other cython files.  The following
> does not work, and I think it's a bug:
>
> == example2.pxd ===========================
> cdef extern cppclass Foo:
>    int _foo
>    __init__(int foo)
>    __dealloc__()
> ===========================================
>
> == cython --cplus example2.pyx ============
> cdef cppclass Foo:
>    __init__(int foo) nogil:
>      this._foo = foo
>    __dealloc__() nogil:
>      pass
> ===========================================
>
> == cython --cplus example3.pyx ============
> from example2 cimport Foo
>
> cdef Foo* foo_p = new Foo(2)
> ===========================================
>
> This fails for example2 with an obscure error message:
>
> $ cython --cplus example2.pyx
> example2.pyx:3:8: undeclared name not builtin: this
> ...more spurious errors...
>
> For example3, Cython runs through but trying to compile shows the actual
> problem (which you can also see in example2 if you shift things around a
> bit):
>
> $ g++ -fPIC -shared -o example3.so -I /usr/include/python2.7 example3.cpp
> example3.cpp: In function ‘void initexample3()’:
> example3.cpp:775:38: error: no matching function for call to
> ‘Foo::Foo(int)’
>     __pyx_v_8example3_foo_p = new Foo(2);
>
> This is in the generated code:
>
> /*--- Type declarations ---*/
> struct Foo;
> struct Foo {
>    int _foo;
>    virtual  ~Foo(void);
> };
>
> It's missing the constructor declaration!
>
> I traced this a bit down the Compiler/Symtab.py and found this part in
> CppClassScope::declare_var:
>
> 4e07fc52 (Robert Bradshaw      2012-08-21 00:46:00 -0700 2112) if name
> != "this" and (defining or name != "<init>"):
> 4e07fc52 (Robert Bradshaw      2012-08-21 00:46:00 -0700 2113)
> self.var_entries.append(entry)
>
> Here defining is 0, so the declaration is skipped.  I don't know Cython
> internals, so I am hoping someone who does can fix this easily given the
> above information or point me in the right direction.
>
> Thanks a lot for Cython, it's very useful!
>
> Marcus Brinkmann
> _______________________________________________
> cython-devel mailing list
> cython-devel at python.org
> https://mail.python.org/mailman/listinfo/cython-devel



More information about the cython-devel mailing list