简体   繁体   English

在Python(Linux)中调用复杂的C ++函数

[英]Calling complicated C++ functions in Python (linux)

I have some functions in C++ source, declared like this: 我在C ++源代码中有一些函数,声明如下:

extern "C" {
    int32_t comp_ip_long(const std::vector<EachColumn>& in, std::vector<EachColumn>& out);
}

The C++ code is compiled into xxx.so (linux shared object) and I want to call the function in Python. C ++代码被编译为xxx.so(Linux共享对象),我想在Python中调用该函数。 notice that I cannot modify the C++ code, so something like boost::python is not accessable. 请注意,我无法修改C ++代码,因此无法访问boost::python类的东西。

I've tried ctypes.CDLL, but I don't know how to pass the complicated argument to xxx.so? 我已经尝试过ctypes.CDLL,但是我不知道如何将复杂的参数传递给xxx.so?

PS: PS:

I've given a .so with some functions (with the above parameter type, but function names are unknown), the function name and parameters are input by user. 我给了.so一些函数(具有上述参数类型,但函数名称未知),函数名称和参数由用户输入。

I believe that you need helper glue functions declared as extern "C" to construct (ie initialize) and fill your std::vector<EachColumn> and have these helper functions called from Python. 我相信您需要使用声明为extern "C"帮助程序粘合函数来构造(即初始化)并填充std::vector<EachColumn>并从Python中调用这些帮助程序函数。

Perhaps 也许

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); };

and likewise for your EachColumn class. 同样适用于EachColumn类。

Maybe you need to make a glue library linked to the C++ library and dlopen -ed by Python 也许您需要制作一个链接到C ++库并由python dlopen绑定的胶水库

Basically, Python is more C friendly than C++ friendly (so you need to make C++ glue code feeling like C for Python). 基本上,Python比C ++更友好C(因此,您需要使C ++粘合代码感觉像C for Python)。 Be careful that no C++ exception throwing crosses the Python interpreter (so catch all of them inside your glue functions) 请注意,没有C ++异常抛出会越过Python解释器(因此请在您的粘合函数中捕获所有异常)

If the C or C++ code is huge, you might consider customizing GCC to perhaps help in generating such glue code, either with MELT or with D.Malcom's GCC python Plugin . 如果C或C ++代码庞大,则可以考虑使用MELT或D.Malcom的GCC python插件自定义GCC,以帮助生成此类粘合代码。 But this takes time. 但这需要时间。

You can't call it from ctypes, you need at least to warp the function inside C so you could call it from Python. 您不能从ctypes调用它,至少需要在C内部扭曲函数,以便可以从Python调用它。

I don't know the details of your function but for example if you have such this C++ code: 我不知道您的函数的详细信息,但是例如,如果您具有以下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;
  }
};

you can warp int this way: 你可以这样扭曲int:

// 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

now it should be callable from ctypes, and from C also. 现在应该可以从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)
>>>

A bit more work but maybe worth it in the long run is to use Boost.Python 需要做更多的工作,但从长远来看,值得使用Boost.Python

Example taken from the boost documentation: 从boost文档中获取的示例:

Following C/C++ tradition, let's start with the "hello, world". 遵循C / C ++的传统,让我们从“你好,世界”开始。 A C++ Function: C ++函数:

char const* greet()
{
    return "hello, world";
}

can be exposed to Python by writing a Boost.Python wrapper: 可以通过编写Boost.Python包装器暴露给Python:

#include <boost/python.hpp>

BOOST_PYTHON_MODULE(hello_ext)
{
    using namespace boost::python;
    def("greet", greet);
}

That's it. 而已。 We're done. 大功告成 We can now build this as a shared library. 现在,我们可以将其构建为共享库。 The resulting DLL is now visible to Python. 现在,生成的DLL对Python可见。 Here's a sample Python session: 这是一个示例Python会话:

>>> import hello_ext
>>> print hello_ext.greet()
hello, world

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM