Undefined symbol error importing Cython module
Asked Answered
W

1

10

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?

Wallasey answered 23/10, 2012 at 8:40 Comment(2)
Does the Foo class has its copy constructor defined in the cpp file?Mccrary
No, it actually has no copy constructor defined, when defined and renamed the name of Foo.pyx in pyFoo.pyx I solved the problem.Wallasey
B
2

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
Balsamiferous answered 20/12, 2012 at 17:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.