I want to make available one of my c++ classes as Python module. The class is declared in a header Foo.h
and implemented in a .cpp Foo.cpp
.
(g++-4.5, Ubuntu x86_64). It's a very very simple class:
Foo.cpp
:
Foo::Foo() : alfa(1.0), beta(1)
{
}
Foo::~Foo()
{
}
Foo.h
:
class Foo
{
public:
Foo()
Foo(const Foo& orig);
~Foo();
double alfa;
int beta;
};
I created a setup.py
as shown in Cython tutorial:
setup.py
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
setup(
name = 'MyDemo',
ext_modules=[
Extension("Foo"
sources=["Foo.pyx"],
include_dirs=[".","../eigen/"],
language="c++"),
],
cmdclass = {'build_ext': build_ext},
)
and followed the instruction of the cython tutorial to write my Foo.pyx
cython module:
Foo.pyx
cdef extern from "Foo.h":
ctypedef struct c_Foo "Foo":
double alfa
c_Foo *new_Foo "new Foo" ()
void del_Foo "delete" (c_Foo *myfoo)
cdef class Foo:
cdef c_Foo *thisptr # hold a C++ instance which we're wrapping
def __cinit__(self):
self.thisptr = new_Foo()
def __dealloc__(self):
del_Foo(self.thisptr)
I compile it with the following command:
python setup.py build_ext --inplace
running build_ext
skipping 'Foo.cpp' Cython extension (up-to-date)
building 'Foo extension
gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I. -I../eigen/ -I/usr/include/python2.6 -c Foo.cpp -o build/temp.linux-x86_64-2.6/Foo.o
cc1plus: warning: command line option "-Wstrict-prototypes" is valid for Ada/C/ObjC but not for C++
g++ -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions build/temp.linux-x86_64-2.6/Foo.o -o /home/linello/prova/Foo.so
Now the Foo.so
shared library object is created but when I want to import it from python, I get:
>>> import Foo
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: ./Foo.so: undefined symbol: _ZN4FooD1Ev
>>>
I think that _ZN4FooD1Ev is the mangled name of the constructor of Foo
but don't understand how is missing the symbol.
I really can't understand what symbol is missing from the shared object file.
And as second point, after the python setup.py build_ext --inplace
command, my Foo.cpp
file is messed up and contains the cythonized version.
How is possible to rename the cythonized file in another format (for example .cxx
) and avoid that linker error?
I then modified the Foo.pyx
in pFoo.pyx
and consequently modified the setup.py
, now after the setup command I have the cythonized version of pFoo.pyx
in Foo.cxx
but when I try to import I get the
ImportError: dynamic module does not define init function (initpyFoo)
What is wrong with my setup and how is possible to solve my problems?
I suggest you use a different name for your cython module, e.g. cFoo, to avoid the name collision issue:
from distutils.core import setup
from Cython.Build import cythonize
setup(ext_modules = cythonize(
"cFoo.pyx", # our Cython source
sources=["Foo.cpp"], # additional source file(s)
language="c++", # generate C++ code
))
To define a C++ class, use the 'cppclass' keyword, as below:
cdef extern from "Foo.h":
cdef cppclass Foo:
Foo()
double alfa
int beta
You should then be able to access your class like so:
cdef Foo *foo = new Foo()
foo.beta = 42
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With