在 Python (linux) 中调用复杂的 C++ 函数
Posted
技术标签:
【中文标题】在 Python (linux) 中调用复杂的 C++ 函数【英文标题】:Calling complicated C++ functions in Python (linux) 【发布时间】:2013-09-03 10:54:42 【问题描述】:我在 C++ 源代码中有一些函数,声明如下:
extern "C"
int32_t comp_ip_long(const std::vector<EachColumn>& in, std::vector<EachColumn>& out);
C++ 代码编译成 xxx.so(linux 共享对象),我想在 Python 中调用该函数。请注意,我无法修改 C++ 代码,因此无法访问 boost::python
之类的内容。
我试过ctypes.CDLL,但是不知道怎么把复杂的参数传给xxx.so?
PS:
我给了一个.so,里面有一些函数(参数类型如上,但函数名未知),函数名和参数由用户输入。
【问题讨论】:
【参考方案1】:我相信您需要声明为 extern "C"
的辅助粘合函数来构造(即初始化)并填充您的 std::vector<EachColumn>
并从 Python 调用这些辅助函数。
也许
typedef std::vector<EachColumn> columnvect_t;
extern "C" columnvect_t *new_vect()
return new columnvect_t; ;
extern "C" void del_vect(columnvect_t*vec)
delete vec; ;
extern "C" void pushback_vect(columnvect_t* vec, EachColumn* col)
vec->push_back(*col); ;
同样适用于您的EachColumn
课程。
也许你需要制作一个胶水库链接到C++库和dlopen
-ed by Python
基本上,Python 比 C++ 更友好(因此你需要让 C++ 粘合代码感觉就像 C 对 Python 的感觉)。请注意,不要通过 Python 解释器抛出任何 C++ 异常(因此在胶水函数中捕获所有异常)
如果 C 或 C++ 代码很大,您可能会考虑自定义 GCC 以帮助生成此类胶水代码,使用 MELT 或使用 D.Malcom 的 GCC python Plugin。但这需要时间。
【讨论】:
您仍然需要添加 C++ 代码。其实函数名是别人提供的,我完全不知道..【参考方案2】:使用Boost.Python
来自 boost 文档的示例:
按照 C/C++ 的传统,让我们从“hello, world”开始。一个 C++ 函数:
char const* greet()
return "hello, world";
可以通过编写 Boost.Python 包装器向 Python 公开:
#include <boost/python.hpp>
BOOST_PYTHON_MODULE(hello_ext)
using namespace boost::python;
def("greet", greet);
就是这样。我们完成了。我们现在可以将其构建为共享库。生成的 DLL 现在对 Python 可见。这是一个 Python 会话示例:
>>> import hello_ext
>>> print hello_ext.greet()
hello, world
【讨论】:
【参考方案3】:你不能从 ctypes 调用它,你至少需要在 C 中扭曲函数,以便你可以从 Python 调用它。
我不知道您的函数的详细信息,但例如,如果您有这样的 C++ 代码:
#include <iostream>
class Foo
int bar;
public:
Foo(int bar) : bar(bar)
int getBar() const
return bar;
void setBar(int bar)
this->bar = bar;
void doSomething() const
std::cout << bar << std::endl;
;
你可以这样变形:
// previous code here +
#define CAST_FOO(x) (static_cast<Foo *>(x))
#ifndef FOO_DEBUG
extern "C"
#endif
void* foo_new(int bar)
return static_cast<void*>(new Foo(bar));
int foo_get_bar(void *foo)
return CAST_FOO(foo)->getBar();
void foo_set_bar(void *foo, int bar)
CAST_FOO(foo)->setBar(bar);
void foo_do_something(void* foo)
CAST_FOO(foo)->doSomething();
void foo_destroy(void* foo)
delete CAST_FOO(foo);
#ifndef FOO_DEBUG
;
#endif
#ifdef FOO_DEBUG
int main(int argc, char **argv)
void* foo = foo_new(10);
foo_do_something(foo);
foo_set_bar(foo, 20);
foo_do_something(foo);
foo_destroy(foo);
return 0;
#endif
现在它应该可以从 ctypes 调用,也可以从 C 调用。
$ g++ -Wall foo.cpp -DFOO_DEBUG
$ ./a.out
10
20
$ g++ -Wall foo.cpp -shared -o foo.so
$ python
>>> from ctypes import *
>>>
>>> so = cdll.LoadLibrary('foo.so')
>>> foo = so.foo_new(10)
>>>
>>> so.foo_do_something(foo)
10
>>> so.foo_set_bar(foo, 20)
>>> so.foo_do_something(foo)
20
>>> so.foo_destroy(foo)
>>>
【讨论】:
以上是关于在 Python (linux) 中调用复杂的 C++ 函数的主要内容,如果未能解决你的问题,请参考以下文章
python-daemon 阻止对 ctypes 链接的 C 用户库的 ioctl 调用