如何编译C函数使用LAPACK库的C扩展?
我为Python编写了一个C extesion,并且该模块在.so文件中成功编译。 但是,当我尝试在Python端使用包装的C函数(python中的一个测试代码调用包装的C函数)时,我得到以下ImportError
ImportError: /home/username/newModule.cpython-36m-x86_64-linux-gnu.so: undefined symbol: dgetri_
我很确定导入错误中的undefined symbol: dgetri_
是因为生成的.so
文件找不到LAPACK
库的链接。 所以我的问题如下,
当包装的C函数依赖于LAPACK库来生成.so
格式的模块时,如何为python编译c扩展代码?
目前我正在使用python的utils.core
模块编译C代码。 我想我需要从命令行编译C代码来链接LAPACK
但是不知道哪些是适当的命令?
任何帮助表示赞赏。
您可能对使用scipy.linalg.cython_lapack感兴趣。 它提供了对LAPACK函数dgetri
访问。 好消息是:
这使得可以从任何第三方Cython模块使用SciPy的BLAS和LAPACK,而无需明确地链接到库。 这意味着像scikit-learn和statsmodels这样的项目不需要在BLAS和LAPACK上维护单独的构建依赖。
使用dger
可以直接使用SciPy接口和Cython在Calling BLAS / LAPACK中获得 。 另请参阅使用内部数组定义改善Cython Lapack性能? 我详细介绍了如何在我对MPI python-Open-MPI的回答中使用cython_blas,所以这里是如何适应dgetri:
-
代码的关键部分是用
Cython
编写的,专用文件myinverse.pyx
。 -
该文件由Cython转换为
myinverse.c
文件 -
这个c文件由你最喜欢的c编译器
gcc
编译,以构建一个共享库myinverse.so
-
import myinverse
后,可以在程序中使用优化函数。
这是一个cython模块,放在.pyx文件中:
import numpy cimport numpy cimport scipy.linalg.cython_lapack ctypedef numpy.float64_t DTYPE_t cimport cython from libc.stdlib cimport malloc, free @cython.boundscheck(False) @cython.wraparound(False) @cython.nonecheck(False) def invert(numpy.ndarray[DTYPE_t, ndim=2] array): cdef int rows = array.shape[0] cdef int cols = array.shape[1] cdef int info = 0 if cols !=rows: return array,1,"not a square matrix" cdef int* ipiv = malloc(rows * sizeof(int)) if not ipiv: raise MemoryError() scipy.linalg.cython_lapack.dgetrf(&cols,&rows,&array[0,0],&rows,ipiv,&info) if info !=0: free(ipiv) return array,info,"dgetrf failed, INFO="+str(info) #workspace query cdef double workl cdef int lwork=-1 scipy.linalg.cython_lapack.dgetri(&cols,&array[0,0],&rows,ipiv,&workl,&lwork,&info) if info !=0: free(ipiv) return array,info,"dgetri failed, workspace query, INFO="+str(info) #allocation workspace lwork= int(workl) cdef double* work = malloc(lwork * sizeof(double)) if not work: raise MemoryError() scipy.linalg.cython_lapack.dgetri(&cols,&array[0,0],&rows,ipiv,work,&lwork,&info) if info !=0: free(ipiv) free(work) return array,info,"dgetri failed, INFO="+str(info) free(ipiv) free(work) return array,info,""
要进行cythonize并编译.pyx文件,可以使用以下makefile(我希望你使用Linux …)
all: myinverse myinverseb myinverse: myinverse.pyx cython -a myinverse.pyx myinverseb: myinverse.c gcc -shared -pthread -fPIC -fwrapv -O2 -Wall -fno-strict-aliasing -I/usr/include/python2.7 -o myinverse.so myinverse.c
新的python myinverse函数,chainng LAPACK的dgetrf()
和dgetri()
,在主python文件中调用:
import numpy as np import myinverse n=42 #A=np.zeros((n,n)) #for i in range(n): # A[i,i]=10 A=np.random.rand(n,n) #A=np.zeros((n,n)) Am,info,string=myinverse.invert(A.copy()) if info==0: print np.linalg.norm(A.dot(Am)-np.identity(n), np.inf) else : print "inversion failed, info=",info, string
或者,我在linux中编译时使用以下两行来完成我的代码
$gcc -DNDEBUG -Wall -Wstrict-prototypes -fPIC -I/home/username/anaconda3/include/python3.6m -c stackDoc.cpp -o mydemo.o $gcc -shared mydemo.o -o mydemo.so
我发现以下链接很有用, https://docs.python.org/2/extending/building.html