我已经获得了一些独立的C ++代码dbscan.cpp
和dbscan.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
在元素库中使用了某些类型,而我无法在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不在其中。
我很感激任何帮助。感谢。
答案 0 :(得分:1)
您是否尝试过执行链接器ld
错误建议的操作?您可以在setup.py中的Extension对象构造中将-fPIC
标志传递给编译器:
Extension("PyDBSCAN_lib",
# ...
extra_compile_args=['-fPIC'],
extra_link_args=['-fPIC']
# ...
)
不确定这应该是编译器还是链接器标志;我提到了两种可能性,以便你了解这两种可能性。
答案 1 :(得分:1)
您需要使用-fPIC
编译器标志编译 elemental ,以便从共享对象(如Python扩展模块)中使用它。将正常的可执行文件链接到没有此要求;这是代码共享对象的代码之一。
Distutils应该自动在它编译的代码上使用-fPIC
标志,因为它知道它正在构建一个共享对象。