Cython包装使用另一个库的类 [英] Cython wrapping a class that uses another library

查看:49
本文介绍了Cython包装使用另一个库的类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些C ++代码 dbscan.cpp dbscan.h 可以很好地独立运行.现在,我尝试将其包装在Cython中.我不确定如何正确执行此操作,并且我对编译器,链接器以及库和makefile的了解有限.

I've got some C++ code dbscan.cpp and dbscan.h that work great standalone. Now I'm trying to wrap it in Cython. I'm not sure how to do this correctly, and I'm impeded by limited knowledge about compilers and linkers and libraries and makefiles.

这是 PyDBSCAN_lib.pyx :

# distutils: language = c++ 
# distutils: sources = dbscan.cpp

from libcpp.vector cimport vector
from libcpp.string cimport string
from libcpp cimport bool

cdef extern from "dbscan.h":
    cdef cppclass DBSCAN:
        #DBSCAN(int minPts, int eps) except +
        DBSCAN(int minPts) except +
        void start()
        void findNeighbors(int pid, vector[int]& neighbors)
        void readFile(string filename, bool lastColIsTrueCluster)
        void buildDistMatrix()
        void calcEps()
        void calcNumNeighbors()
        void initLabels()
        void writeFile(string filename)

cdef class PyDBSCAN:
    cdef DBSCAN *thisptr
    def __cinit__(self, int minPts):
        self.thisptr = new DBSCAN(minPts)
    def __dealloc__(self):
        del self.thisptr
    def start(self):
        self.thisptr.start()
    def findNeighbors(self, int pid, vector[int]& neighbors):
        self.thisptr.findNeighbors(pid, neighbors)
    def readFile(self, string filename, bool lastColIsTrueCluster):
        self.thisptr.readFile(filename, lastColIsTrueCluster)
    def buildDistMatrix(self):
        self.thisptr.buildDistMatrix()
    def calcEps(self):
        self.thisptr.calcEps()
    def calcNumNeighbors(self):
        self.thisptr.calcNumNeighbors()
    def initLabels(self):
        self.thisptr.initLabels()
    def writeFile(self, string filename):
        self.thisptr.writeFile(filename)

如您所见,上半部分引用了我的c ++代码,而下半部分是包装类.

As you can see the top half makes reference to my c++ code, and the bottom is a wrapper class.

这是 setup.py ,据我了解,它有点像makefile:

And here's the setup.py, which I understand is sort of like a makefile:

from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
#from Cython.Build import cythonize
import os

os.environ['CC'] = '/app/gcc/4.8.2/bin/g++ -std=c++11'
os.environ['CXX'] = '/app/gcc/4.8.2/bin/g++ -std=c++11'
os.environ['CPP'] = '/app/gcc/4.8.2/bin/g++ -std=c++11'
os.environ['CMAKE_CXX_COMPILER'] = '/app/gcc/4.8.2/bin/g++ -std=c++11'

modules = [Extension("PyDBSCAN_lib", 
                sources=["PyDBSCAN_lib.pyx"],
                include_dirs = [".", "/usr/local/elemental/0.81/HybridRelease/include"],
                libraries = ["mpi_cxx", "mpi", "m", "elemental"],
                library_dirs = ["/usr/local/lib", "/usr/lib", "/usr/local/elemental/0.81/HybridRelease/lib"],
                language = "c++")]

setup(ext_modules = modules, cmdclass = {"build_ext" : build_ext})  

我正在尝试生成一个 PyDBSCAN_lib.so ,以便可以将其导入任何常规的python脚本中.

I'm trying to generate a PyDBSCAN_lib.so so that I can import it in any regular python script.

我的问题是 dbscan.cpp 使用了Elemental库中的某些类型,并且在 setup.py 中找不到正确的配置来指定此类型代码>.当前它生成此:

I'm problem is that dbscan.cpp makes use of some types in the Elemental library, and I can't find the right configuration to specify this in setup.py. Currently it generates this:

/usr/bin/ld: /usr/local/elemental/0.81/HybridRelease/lib/libelemental.a(matrix.cpp.o): relocation R_X86_64_32 against `.rodata.str1.1' can not be used when making a shared object; recompile with -fPIC
/usr/local/elemental/0.81/HybridRelease/lib/libelemental.a: could not read symbols: Bad value
collect2: error: ld returned 1 exit status

记录下来,这就是我如何使用g ++进行编译

edit: for the record, here's how I'm compiling it with g++

include /usr/local/elemental/0.81/HybridRelease/conf/elemvariables 

db: dbscan_main.cpp dbscan.cpp 

    ${CXX} ${ELEM_COMPILE_FLAGS} -fopenmp $^ -o $@ ${ELEM_LINK_FLAGS} ${ELEM_LIBS}

其中elemvariables包含各种编译选项,但-fPIC不在其中.

where elemvariables contains various compile options, but -fPIC is not among them.

在此方面的任何帮助,我将不胜感激.谢谢.

I'd appreciate any help on this. Thanks.

推荐答案

您需要使用 -fPIC 编译器标志编译 elemental ,以便从共享库中使用它.对象,例如Python扩展模块.链接一个普通的可执行文件没有这个要求.这是属于共享对象的代码的要求之一.

You need to compile elemental using the -fPIC compiler flag in order to use it from a shared object such as a Python extension module. Linking a normal executable to doesn't have this requirement; this is one of the requirements for code that's part a shared object.

Distutils应该在正在编译的代码上自动使用 -fPIC 标志,因为它知道它正在构建共享对象.

Distutils should automatically use the -fPIC flag on the code that it's compiling, since it knows that it's building a shared object.

这篇关于Cython包装使用另一个库的类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆