【问题标题】:Cython wrapping a class that uses another libraryCython 包装一个使用另一个库的类
【发布时间】:2014-04-09 19:10:35
【问题描述】:

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

这里是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++ 代码,而下半部分是一个包装类。

这是setup.py,我理解它有点像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 脚本中。

我的问题是 dbscan.cpp 使用了 Elemental 库中的某些类型,而我在 setup.py 中找不到正确的配置来指定它。目前它会生成这个:

/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++ 编译它的方式

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 不在其中。

如果能提供任何帮助,我将不胜感激。谢谢。

【问题讨论】:

    标签: python c++ cython


    【解决方案1】:

    您是否尝试过链接器ld 错误所建议的操作?您可以在 setup.py 中的 Extension 反对构造中将 -fPIC 标志传递给编译器:

    Extension("PyDBSCAN_lib",
              # ...
              extra_compile_args=['-fPIC'],
              extra_link_args=['-fPIC']
              # ...
              )
    

    不确定这应该是编译器还是链接器标志;我提到了这两种可能性,以便您了解这两种可能性。

    【讨论】:

    • 是的,我试过添加它 - 它没有解决它。我查了一下,不知道有什么作用?此外,我可以在没有该选项的情况下编译可执行文件。例如,这是我在做 cython 之前使用的 Makefile: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 不在其中
    • @Ben:这是有用的信息。也许您应该将其作为问题的一部分发布?
    【解决方案2】:

    您需要使用-fPIC 编译器标志编译elemental,以便从共享对象(例如Python 扩展模块)中使用它。将普通可执行文件链接到没有此要求;这是作为共享对象一部分的代码的要求之一。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-14
      • 1970-01-01
      相关资源
      最近更新 更多