经过许多尝试、试错、尖叫和拔光头发,我终于搞定了这个问题。但首先,我不得不将我的C++代码重写成C语言,这对我来说实际上只是将所有的 std::string
变量转换为 char*
,并跟踪一些长度。
完成后,我有了.h和.c文件。我想将C代码中的一个函数作为Python中的单个函数使用。事实证明,Cython可以将您的C文件编译成扩展,并在一次链接中链接任何库,因此从我的setup.py开始,它最终看起来像这样:
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
ext_modules=[
Extension("myext",
["myext.pyx", "../stuff.c"],
libraries=["ssl", "crypto"]
)
]
setup(
name = "myext",
cmdclass = {"build_ext": build_ext},
ext_modules = ext_modules
)
如您所见,Extension的第二个参数仅列出需要编译的所有文件,据我所知,Cython会根据它们的文件扩展名来确定如何编译它们。libraries数组告诉Cython编译器需要链接什么(在这种情况下,我正在封装一些加密内容,我似乎无法直接通过现有的Python库进行模拟)。
要在.pyx文件中使我的C函数可用,您需要在.pxd中编写一个小包装器。我的myext.pxd如下所示:
cdef extern from "../stuff.h":
char* myfunc(char* arg1, char* arg2, char* arg3)
在.pyx文件中,您可以使用cimport声明导入此函数,然后可以像任何其他Python函数一样使用它:
cimport myext
def my_python_func(arg1, arg2, arg3):
result = myext.myfunc(arg1, arg2, arg3)
return result
当您在Mac上构建此项目时,会得到一个 .so 文件,您可以将其导入Python并从 .pyx 运行函数。可能有更好、更正确的方法来实现所有这些工作,但这需要经验,并且这是我第一次尝试,我设法把它搞定了。如果我有做错的地方,非常希望得到指点。
更新:
在进一步使用Cython后,我发现将其与C++集成也非常简单,只要你知道你在做什么。将C++的
string
简单地声明为
from libcpp.string cimport string
可以使其在您的 pyx/pyd 中可用。声明C++类也同样容易:
cdef extern from "MyCPPClass.h":
cdef cppclass MyCPPClass:
int foo;
string bar;
当然,你需要以Pythonic的格式重新声明你的类的.h定义,但这是为了获得对已经编写的C++函数的访问而付出的小代价。