Cython包裝一個使用另一個庫的類。

[英]Cython wrapping a class that uses another library


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.

我有一些c++代碼dbscan。cpp和dbscan。這是一個非常獨立的工作。現在我要把它包起來。我不知道如何正確地做到這一點,而且我對編譯器、鏈接器、庫和makefile的有限知識也有阻礙。

Here's PyDBSCAN_lib.pyx:

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)

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

正如您看到的,上半部分引用了我的c++代碼,下面是一個包裝類。

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

這是設置。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})  

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

我正在嘗試生成PyDBSCAN_lib。這樣我就可以將它導入到任何常規的python腳本中。

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:

我的問題是dbscan。cpp在元素庫中使用了一些類型,我找不到合適的配置來在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

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

編輯:為了記錄,這里是我如何用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}

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

其中元素包含各種編譯選項,但是-fPIC不在其中。

I'd appreciate any help on this. Thanks.

對此我很感激。謝謝。

2 个解决方案

#1


1  

Have you tried doing what the linker ld error is recommending? You can pass the -fPIC flag to the compiler in the Extension objection construction in setup.py:

你是否嘗試過linker ld的錯誤建議?您可以將-fPIC標志傳遞到setup.py的擴展反對結構中的編譯器:

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

Not sure if this should be a compiler or linker flag; I am mentioning both possibilities so that you are aware of both.

不確定這是否應該是編譯器或鏈接器標志;我提到了兩種可能性,讓你們都知道。

#2


1  

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.

您需要使用-fPIC編譯器標記來編譯元素,以便從共享對象(比如Python擴展模塊)中使用它。將一個普通的可執行文件鏈接到沒有這個要求;這是代碼的需求之一,它是共享對象的一部分。

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

Distutils應該在編譯的代碼上自動使用-fPIC標志,因為它知道它正在構建一個共享對象。


注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2014/04/09/72ffc3d4f5a08f31fdf2344bb51a997.html



 
粤ICP备14056181号  © 2014-2021 ITdaan.com