1

我在 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(具有上述参数类型,但函数名称未知),函数名称和参数由用户输入。

4

3 回答 3

1

You can't call it from ctypes, you need at least to warp the function inside C so you could call it from Python.

I don't know the details of your function but for example if you have such this C++ code:

#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:

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

$ 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)
>>>
于 2013-09-03T11:33:01.247 回答
1

更多的工作,但从长远来看可能值得的是使用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
于 2013-09-03T11:35:59.243 回答
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并由 Python -ed的胶水库

基本上,Python 比 C++ 对 C 更友好(所以你需要让 C++ 粘合代码感觉像 C for Python)。请注意,不要通过 Python 解释器抛出任何 C++ 异常(因此在胶水函数中捕获所有异常)

如果 C 或 C++ 代码很大,您可能会考虑自定义 GCC 以帮助生成此类胶水代码,无论是使用MELT还是使用 D.Malcom 的GCC python 插件。但这需要时间。

于 2013-09-03T11:09:06.690 回答