python 用 Cython 包装 C++ lib

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2105508/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 23:47:52  来源:igfitidea点击:

Wrap C++ lib with Cython

pythoncython

提问by YuQing Zhang

I'm new to Cython and I'm trying to use Cython to wrap a C/C++ static library. I made a simple example as follow.

我是 Cython 的新手,我正在尝试使用 Cython 来包装 C/C++ 静态库。我做了一个简单的例子如下。

Test.h:

测试.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;
} 

Then I used g++ to compile and build it.

然后我用 g++ 来编译和构建它。

g++ -c test.cpp -o libtest.o
ar rcs libtest.a libtest.o

So now I got a static library called libtest.a.

所以现在我得到了一个名为libtest.a.

Test.pyx:

测试.pyx:

cdef extern from "test.h":
        int add(int a,int b)
        int multipy(int a,int b)

print add(2,3)

Setup.py:

安装程序.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
)

The I called:

我打电话给:

python setup.py build_ext --compiler=mingw32 --inplace

The output was:

输出是:

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

I also tried to use libraries=['test']instead of libraries=['libtest']. It gave me the same errors.

我也尝试使用libraries=['test']代替libraries=['libtest']. 它给了我同样的错误。

Any clue about this?

关于这个的任何线索?

回答by Luper Rouch

If your C++ code is only used by the wrapper, another option is to let the setup compile your .cpp file, like this:

如果您的 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
)

For linking to a static library you have to use the extra_objectsargument in your Extension:

要链接到静态库,您必须在以下文件中使用extra_objects参数Extension

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
)

回答by lothario

Your Test.pyxfile isn't doing what you expect. The print add(2,3)line will notcall the add()C++ function; you have to explicitly create a wrapper function to do that. Cython doesn't create wrappers for you automatically.

您的Test.pyx文件没有按照您的预期运行。该print add(2,3)不会调用add()C++ 函数;你必须显式地创建一个包装函数来做到这一点。Cython 不会自动为您创建包装器。

Something like this is probably what you want:

这样的事情可能是你想要的:

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)

You can look at Cython's documentationfor more details.

您可以查看 Cython 的文档以获取更多详细信息。

回答by Alex Martelli

I think you can fix this specific problem by specifying the right library_dirs(where you actually putlibtest.a -- apparently it's not getting found), but I think then you'll have another problem -- your entry points are not properly declared as extern "C", so the function's names will have been "mangled" by the C++ compiler (look at the names exported from your libtest.a and you'll see!), so any other language except C++ (including C, Cython, etc) will have problems getting at them. The fix is to declare them as extern "C".

我认为您可以通过指定正确的library_dirs(您实际放置libtest.a 的位置 - 显然没有找到)来解决这个特定问题,但我认为您会遇到另一个问题 - 您的入口点没有正确声明为extern "C",因此函数的名称将被 C++ 编译器“修改”(查看从 libtest.a 导出的名称,您会看到!),因此除 C++ 之外的任何其他语言(包括 C、Cython 等)都会出现问题接近他们。解决方法是将它们声明为extern "C".