3
votes

I am trying to call a c++ code from a python script using cython. I already managed to work with an example from here but the thing is: my c++ code includes non-standard libraries from opencv. I believe I am not linking them correctly so I need someone to have a look on my setup.py and my cpp_rect.h and cpp_rect.cpp files.

The error I am getting is regarding to the bold line yn the *.cpp file: cv::Mat img1(7,7,CV_32FC2,Scalar(1,3)); When I try to test the library, I receive an include error when I execute $ python userect.py:

Traceback (most recent call last):
  File "userect.py", line 2, in <module>
    from rectangle import Rectangle
ImportError: dlopen(/Users/marcelosalloum/Desktop/python_cpp_interface/rectangle.so, 2): Symbol not found: __ZN2cv3Mat10deallocateEv
  Referenced from: /Users/marcelosalloum/Desktop/python_cpp_interface/rectangle.so
  Expected in: flat namespace
 in /Users/marcelosalloum/Desktop/python_cpp_interface/rectangle.so

The symbol not found (__ZN2cv3Mat10deallocateEv) has something to do with the cv::Mat::deallocate() function, what indicates that my imports are not working properly.

Any ideas?


My other classes are the following:

This is my setup.py file. Note taht I already included 2 directories although not sure if I did correctly:

from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext

setup(
  name = 'Demos',
  ext_modules=[
    Extension("rectangle",
              sources=["rectangle.pyx", "cpp_rect.cpp"], # Note, you can link against a c++ library instead of including the source
              include_dirs=[".", "/usr/local/include/opencv/", "/usr/local/include/"],
              language="c++"),
    ],
  cmdclass = {'build_ext': build_ext},

)

My cpp_rect.h file includes a cv.h and a namespace cv, as shown bellow:

#include "source/AntiShake.h"
#include <iostream>
#include "cv.h"
using namespace cv;

class Rectangle {
public:
    int x0, y0, x1, y1;
    Rectangle();
    Rectangle(int x0, int y0, int x1, int y1);
    ~Rectangle();
    int getLength();
    int getHeight();
    int getArea();
    void move(int dx, int dy);
    **void openCV();**
    Rectangle operator+(const Rectangle& other);
};

and my openCV() function simply instantiates an cv::Mat from opencv (file cpp_rect.cpp):

#include "cpp_rect.h"

Rectangle::Rectangle() {
    x0 = y0 = x1 = y1 = 0;
}

Rectangle::Rectangle(int a, int b, int c, int d) {
    x0 = a;
    y0 = b;
    x1 = c;
    y1 = d;  
}

Rectangle::~Rectangle() {
}

void Rectangle::openCV(){
    **cv::Mat img1(7,7,CV_32FC2,Scalar(1,3));**
}
...

I can compile the file with the following command: $ python setup.py build_ext --inplace, which provides me the *.so file. But when I run my userect.py script, I get that include error described firstly in this question.

Any Ideas?

1
The symbol __ZN2cv3Mat10deallocateEv) mentioned above is cv::Mat::deallocate(): you can use echo __ZN2cv3Mat10deallocateEv) | c++filt to find out. If that function is from an external library, I would expect that you need to specify the libraries you need to be linked in your setup.py but I'm not a cython/python user so I don't know the details.Dietmar Kühl
Right, the echo __ZN2cv3Mat10deallocateEv | c++filt command worked and showed that it is indeed the cv::Mat::deallocare() function. But I thought the field include_dirs would be enough to link to de libraries. But I still have no idea how to link them properlymarcelosalloum
Well, the include_dirs is normally what become argument to the -I compiler options. You probably want to also specify lib_dirs for the location of the compiled library code and libraries (or whatever) to list the required libraries. How these are to be configured exactly, I don't know. In Makefiles these would be part of the LDFLAGS (e.g. -L<directory-where-the-libraries-are-located>) and the LDLIBS (e.g. -l<library-to-be-linked-to>).Dietmar Kühl

1 Answers

3
votes

Resolved, thanks to Dietmar Kühl's comments and this video from youtube!

What was wrong? I found out that my setup.py was misconfigured. It should be like:

from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext

setup(
    name = 'DyCppInterface',
    version = '1.0',
    author = 'Marcelo Salloum dos Santos',
    # The ext modules interface the cpp code with the python one:
    ext_modules=[
        Extension("rectangle",
            sources=["rectangle.pyx", "cpp_rect.cpp"], # Note, you can link against a c++ library instead of including the source
            include_dirs=[".","source" , "/opt/local/include/opencv", "/opt/local/include"],
            language="c++",
            library_dirs=['/opt/local/lib', 'source'],
            libraries=['opencv_core', 'LibCppOpenCV'])
    ],
    cmdclass = {'build_ext': build_ext},
)

The three things to pay attention in order to correctly configure it are:

  • include_dirs: each referenced file in the setup.py or the .h and .cpp shall have its container folder in the include_dirs;
  • library_dirs: each referenced library shall have its container folder written here;
  • libraries: one MUST put the library's name here

Further questions on how to configure a library for cython can be answered by watching this video on how to use and configure a dynamic library (using Eclipse CDT).