构造Python绑定到C或c++库的最快方法是什么?
(如果这很重要的话,我使用的是Windows。)
构造Python绑定到C或c++库的最快方法是什么?
(如果这很重要的话,我使用的是Windows。)
当前回答
问题是如何从Python中调用C函数,如果我理解正确的话。那么最好的选择是c类型(顺便说一句,可移植到所有Python变体)。
>>> from ctypes import *
>>> libc = cdll.msvcrt
>>> print libc.time(None)
1438069008
>>> printf = libc.printf
>>> printf("Hello, %s\n", "World!")
Hello, World!
14
>>> printf("%d bottles of beer\n", 42)
42 bottles of beer
19
关于详细的指南,你可以参考我的博客文章。
其他回答
Ctypes模块是标准库的一部分,因此比swig更稳定和更广泛可用,而swig总是给我带来问题。
使用ctypes,您需要满足python的任何编译时依赖,并且您的绑定将适用于任何具有ctypes的python,而不仅仅是它编译时针对的python。
假设你有一个简单的c++示例类,你想在一个名为foo.cpp的文件中进行对话:
#include <iostream>
class Foo{
public:
void bar(){
std::cout << "Hello" << std::endl;
}
};
由于ctypes只能与C函数对话,因此需要将它们声明为extern "C"
extern "C" {
Foo* Foo_new(){ return new Foo(); }
void Foo_bar(Foo* foo){ foo->bar(); }
}
接下来,您必须将其编译到共享库
g++ -c -fPIC foo.cpp -o foo.o
g++ -shared -Wl,-soname,libfoo.so -o libfoo.so foo.o
最后,你必须编写python包装器(例如在fooWrapper.py中)。
from ctypes import cdll
lib = cdll.LoadLibrary('./libfoo.so')
class Foo(object):
def __init__(self):
self.obj = lib.Foo_new()
def bar(self):
lib.Foo_bar(self.obj)
一旦你有了它,你就可以叫它
f = Foo()
f.bar() #and you will see "Hello" on the screen
还有pybind11,它类似于Boost的轻量级版本。Python和兼容所有现代c++编译器:
https://pybind11.readthedocs.io/en/latest/
对于现代c++,使用cppyy: http://cppyy.readthedocs.io/en/latest/
它基于Clang/LLVM的c++解释器kling。绑定是在运行时进行的,不需要额外的中间语言。得益于Clang,它支持c++ 17。
使用pip安装:
$ pip install cppyy
对于小型项目,只需加载您感兴趣的相关库和标头。例如,从ctypes例子中获取的代码是这个线程,但是在头和代码部分中被分割:
$ cat foo.h
class Foo {
public:
void bar();
};
$ cat foo.cpp
#include "foo.h"
#include <iostream>
void Foo::bar() { std::cout << "Hello" << std::endl; }
编译:
$ g++ -c -fPIC foo.cpp -o foo.o
$ g++ -shared -Wl,-soname,libfoo.so -o libfoo.so foo.o
并使用它:
$ python
>>> import cppyy
>>> cppyy.include("foo.h")
>>> cppyy.load_library("foo")
>>> from cppyy.gbl import Foo
>>> f = Foo()
>>> f.bar()
Hello
>>>
大型项目支持自动加载准备好的反射信息和cmake片段来创建它们,以便已安装包的用户可以简单地运行:
$ python
>>> import cppyy
>>> f = cppyy.gbl.Foo()
>>> f.bar()
Hello
>>>
多亏了LLVM,高级特性才得以实现,比如自动模板实例化。继续这个例子:
>>> v = cppyy.gbl.std.vector[cppyy.gbl.Foo]()
>>> v.push_back(f)
>>> len(v)
1
>>> v[0].bar()
Hello
>>>
注:我是cppyy的作者。
你应该看看Boost.Python。以下是他们网站上的简短介绍:
The Boost Python Library is a framework for interfacing Python and C++. It allows you to quickly and seamlessly expose C++ classes functions and objects to Python, and vice-versa, using no special tools -- just your C++ compiler. It is designed to wrap C++ interfaces non-intrusively, so that you should not have to change the C++ code at all in order to wrap it, making Boost.Python ideal for exposing 3rd-party libraries to Python. The library's use of advanced metaprogramming techniques simplifies its syntax for users, so that wrapping code takes on the look of a kind of declarative interface definition language (IDL).
Cython绝对是最好的选择,除非您希望编写Java包装器,在这种情况下,SWIG可能更可取。
我建议使用runcython命令行实用工具,它使使用Cython的过程极其简单。如果你需要向c++传递结构化数据,可以看看谷歌的protobuf库,它非常方便。
以下是我使用这两种工具的一个最小示例:
https://github.com/nicodjimenez/python2cpp
希望这能成为一个有用的起点。