I'm taking my first steps in Cython to write a Python extension of some C++ code. Also, I have only superficial knowledge of C++. Now I face an error which I do not understand, when cythonizing my .pyx file. The C++11 code is generated successfully, but that code does not compile. The first lines of the compiler error message are:
$ python setup.py build_ext --inplace
Compiling py_foo.pyx because it changed.
[1/1] Cythonizing py_foo.pyx
running build_ext
building 'pyfoo' extension
creating build
creating build/temp.linux-x86_64-3.9
gcc -pthread -B /home/…/compiler_compat -Wno-unused-result -Wsign-compare -DNDEBUG -O2 -Wall -fPIC -O2 -isystem /home/…/include -I/home/…/include -fPIC -O2 -isystem /home/…/include -fPIC -I. -I./ -I/home/…/include/python3.9 -c ./example.cpp -o build/temp.linux-x86_64-3.9/./example.o -std=c++11
gcc -pthread -B /home/…/compiler_compat -Wno-unused-result -Wsign-compare -DNDEBUG -O2 -Wall -fPIC -O2 -isystem /home/…/include -I/home/…/include -fPIC -O2 -isystem /home/…/include -fPIC -I. -I./ -I/home/…/include/python3.9 -c ./foo.cpp -o build/temp.linux-x86_64-3.9/./foo.o -std=c++11
gcc -pthread -B /home/…/compiler_compat -Wno-unused-result -Wsign-compare -DNDEBUG -O2 -Wall -fPIC -O2 -isystem /home/…/include -I/home/…/include -fPIC -O2 -isystem /home/…/include -fPIC -I. -I./ -I/home/…/include/python3.9 -c py_foo.cpp -o build/temp.linux-x86_64-3.9/py_foo.o -std=c++11
py_foo.cpp: In function ‘void __pyx_pf_5pyfoo_9PyDerived_2__dealloc__(__pyx_obj_5pyfoo_PyDerived*)’:
py_foo.cpp:1913:24: warning: deleting object of polymorphic class type ‘nspace::Derived’ which has non-virtual destructor might cause undefined behavior [-Wdelete-non-virtual-dtor]
 1913 |   delete __pyx_v_self->c_derived;
      |                        ^~~~~~~~~
py_foo.cpp: In function ‘int __pyx_pf_5pyfoo_5PyFoo___cinit__(__pyx_obj_5pyfoo_PyFoo*, __pyx_obj_5pyfoo_PyBase*)’:
py_foo.cpp:2134:66: error: no matching function for call to ‘std::unique_ptr<nspace::Base>::unique_ptr(PyObject*&)’
 2134 |     __pyx_t_2 = new nspace::Foo(((std::unique_ptr<nspace::Base> )__pyx_t_1));
      |                                                                  ^~~~~~~~~
In file included from /usr/include/c++/9/memory:80,
                 from py_foo.cpp:729:
/usr/include/c++/9/bits/unique_ptr.h:281:2: note: candidate: ‘template<class _Up, class> std::unique_ptr<_Tp, _Dp>::unique_ptr(std::auto_ptr<_Up>&&)’
  281 |  unique_ptr(auto_ptr<_Up>&& __u) noexcept;
      |  ^~~~~~~~~~
/usr/include/c++/9/bits/unique_ptr.h:281:2: note:   template argument deduction/substitution failed:
py_foo.cpp:2134:66: note:   mismatched types ‘std::auto_ptr<_Up>’ and ‘PyObject*’ {aka ‘_object*’}
 2134 |     __pyx_t_2 = new nspace::Foo(((std::unique_ptr<nspace::Base> )__pyx_t_1));
      |
...
These are the relevant files of my MWE:
example.h:
#ifndef EXAMPLE_H
#define EXAMPLE_H
namespace nspace
{
    class Base
    {
    public:
        virtual void print_() const = 0;
    };
    class Derived : public Base
    {
    private:
        int i;
    public:
        Derived(int i);
        void print_() const;
    };
}
#endif /* EXAMPLE_H */
example.cpp:
#include <iostream>
#include "example.h"
namespace nspace
{
    Derived::Derived(int i)
    {
        this->i = i;
    }
    void Derived::print_() const
    {
        std::cout << this->i << std::endl;
    }
}
foo.h:
#ifndef FOO_H
#define FOO_H
#include <memory>
#include "example.h"
namespace nspace
{
    class Foo
    {
    public:
        Foo();
        Foo(std::unique_ptr<Base> base);
        void print_();
    private:
        std::unique_ptr<Base> base;
    };
}
#endif // FOO_H
foo.cpp:
#include "foo.h"
#include "example.h"
namespace nspace
{
    Foo::Foo()
    {
        this->base = std::unique_ptr<Base>(new Derived(0));
    }
    Foo::Foo(std::unique_ptr<Base> base)
    {
        this->base = std::move(base);
    }
    void Foo::print_()
    {
        this->base->print_();
    }
}
cpp_foo.pxd:
from libcpp.memory cimport unique_ptr
cdef extern from "foo.h" namespace "nspace":
    cdef cppclass Foo:
        Foo() except +
        Foo(unique_ptr[Base] cpp_base) except +
        print_()
cdef extern from "example.h" namespace "nspace":
    cdef cppclass Base:
        pass
    cdef cppclass Derived(Base):
        Derived(int i) except +
py_foo.pyx:
# distutils: language = c++
# distutils: extra_compile_args = -std=c++11
cimport cython
from cpp_foo cimport Foo, Base, Derived
from libcpp.memory cimport unique_ptr
cdef class PyBase:
    pass
cdef class PyDerived(PyBase):
    cdef Derived* c_derived
    def __cinit__(self, int i):
        self.c_derived = new Derived(i)
    def __dealloc__(self):
        del self.c_derived
cdef class PyFoo:
    cdef Foo* foo
    def __cinit__(self, PyBase py_base):
        self.foo = new Foo(
            cpp_base=<unique_ptr[Base]>(py_base.c_derived)
        )
    def __dealloc__(self):
        del self.foo
    def print_(self):
        self.foo.print_()
setup.py:
from distutils.core import setup, Extension
from Cython.Build import cythonize
extensions = [
    Extension("pyfoo",
        sources=[
            "py_foo.pyx",
            "./foo.cpp",
            "./example.cpp",
        ],
        include_dirs=["./"]
    )
]
setup(
    ext_modules=cythonize(
        extensions,
        language_level=3,
    ),
)
I'm very sure my error comes from a misconception I have regarding Cython (and maybe C++ too). Any help or tip is appreciated.
Aucun commentaire:
Enregistrer un commentaire