在 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&lt;EachColumn&gt; 并从 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 调用

如何在C语言中调用shell命令

如何在C语言中调用shell命令

如何在C语言中调用shell命令

我如何制作一个启动Python脚本的linux后台进程(在c中)

Python与C/C++互操作