用Cython封装C++库
我刚接触Cython,想用它来包装一个C/C++的静态库。我做了一个简单的例子,如下所示。
Test.h:
#ifndef TEST_H
#define TEST_H
int add(int a, int b);
int multipy(int a, int b);
#endif
Test.cpp:
#include "test.h"
int add(int a, int b)
{
return a+b;
}
int multipy(int a, int b)
{
return a*b;
}
然后我用g++来编译和构建它。
g++ -c test.cpp -o libtest.o
ar rcs libtest.a libtest.o
现在我得到了一个叫做 libtest.a
的静态库。
Test.pyx:
cdef extern from "test.h":
int add(int a,int b)
int multipy(int a,int b)
print add(2,3)
Setup.py:
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
ext_modules = [Extension("test",
["test.pyx"],
language='c++',
include_dirs=[r'.'],
library_dirs=[r'.'],
libraries=['libtest']
)]
setup(
name = 'test',
cmdclass = {'build_ext': build_ext},
ext_modules = ext_modules
)
然后我调用了:
python setup.py build_ext --compiler=mingw32 --inplace
输出结果是:
running build_ext
cythoning test.pyx to test.cpp
building 'test' extension
creating build
creating build\temp.win32-2.6
creating build\temp.win32-2.6\Release
C:\Program Files\pythonxy\mingw\bin\gcc.exe -mno-cygwin -mdll -O -Wall -I. -IC:\
Python26\include -IC:\Python26\PC -c test.cpp -o build\temp.win32-2.6\Release\test.o
writing build\temp.win32-2.6\Release\test.def
C:\Program Files\pythonxy\mingw\bin\g++.exe -mno-cygwin -mdll -static --entry _D
llMain@12 --output-lib build\temp.win32-2.6\Release\libtest.a --def build\temp.w
in32-2.6\Release\test.def -s build\temp.win32-2.6\Release\test.o -L. -LC:\Python
26\libs -LC:\Python26\PCbuild -ltest -lpython26 -lmsvcr90 -o test.pyd
g++: build\temp.win32-2.6\Release\libtest.a: No such file or directory
error: command 'g++' failed with exit status 1
我还尝试用 libraries=['test']
来代替 libraries=['libtest']
,但得到了同样的错误。
有没有什么线索可以帮助我解决这个问题?
3 个回答
2
我觉得你可以通过指定正确的 library_dirs
来解决这个具体的问题(也就是你放置 libtest.a 的地方——显然它没有被找到),但是我觉得你会遇到另一个问题——你的入口点没有正确声明为 extern "C"
,所以函数的名字会被 C++ 编译器“搞乱”(你可以看看从 libtest.a 导出的名字,你会发现的!),这样除了 C++ 以外的其他语言(包括 C、Cython 等)就会很难调用这些函数。解决办法就是把它们声明为 extern "C"
。
5
你的 Test.pyx
文件没有按照你预期的那样工作。print add(2,3)
这一行 不会 调用 add()
这个 C++ 函数;你需要明确地创建一个包装函数来实现这一点。Cython 不会自动为你创建包装函数。
像下面这样的代码可能是你想要的:
cdef extern from "test.h":
int _add "add"(int a,int b)
int _multiply "multiply"(int a,int b)
def add(a, b):
return _add(a, b)
def multiply(a, b):
return _multiply(a, b)
print add(2, 3)
你可以查看 Cython 的 文档,获取更多详细信息。
29
如果你的C++代码只是被包装器使用,另一种选择是让设置程序编译你的.cpp文件,像这样:
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
ext_modules = [Extension("test",
["test.pyx", "test.cpp"],
language='c++',
)]
setup(
name = 'test',
cmdclass = {'build_ext': build_ext},
ext_modules = ext_modules
)
要链接到一个静态库,你需要在你的Extension
中使用extra_objects这个参数:
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
ext_modules = [Extension("test",
["test.pyx"],
language='c++',
extra_objects=["libtest.a"],
)]
setup(
name = 'test',
cmdclass = {'build_ext': build_ext},
ext_modules = ext_modules
)