在Windows .dll中使用SWIG包装的函数

5 投票
2 回答
3423 浏览
提问于 2025-04-17 10:56

我在使用一个通过SWIG接口导出的共享库中的函数时遇到了问题。

版本信息

Python: 2.6.4

Swig: 2.0.4

大致情况是这样的:我有一些在Linux下用C++开发的代码,并通过SWIG进行了封装。我把C++源代码编译成了一个在Linux下使用的.so对象,然后在Python中使用这个.so库。

现在,我需要把这些函数迁移到Windows,而在Windows中,.so的对应物是.dll。所以,我打算把所有的C++源代码编译成一个.dll,然后通过Python来访问它们。

正常的流程应该是:先有C++源代码 -> 用SWIG进行封装 -> 编译成.dll -> 通过Python访问。

SWIG生成了一个很大的.cxx源文件,里面包含了我开发的所有函数。现在的任务是把这个SWIG生成的文件编译成一个.dll,这样我就可以在后面使用所有的函数。然而,这个.cxx文件用了一些奇怪的方式来封装我的函数,我完全不知道该怎么用。

这些函数的封装方式是这样的。假设我有一个叫做sdrts_reverse_burst_ff的C++类,经过封装后,这个类在.cxx文件中变成了一个函数,定义如下:

SWIGINTERN PyObject *_wrap_sdrts_reverse_burst_ff_sptr___deref__(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {

PyObject *resultobj = 0;

boost::shared_ptr< sdrts_reverse_burst_ff > *arg1 = (boost::shared_ptr< sdrts_reverse_burst_ff > *) 0 ;

  void *argp1 = 0 ;

  int res1 = 0 ;

  PyObject * obj0 = 0 ;

  sdrts_reverse_burst_ff *result = 0 ;



  if(!PyArg_UnpackTuple(args,(char *)"sdrts_reverse_burst_ff_sptr___deref__",1,1,&obj0)) SWIG_fail;

  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_boost__shared_ptrT_sdrts_reverse_burst_ff_t, 0 |  0 );

  if (!SWIG_IsOK(res1)) {

    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "sdrts_reverse_burst_ff_sptr___deref__" "', argument " "1"" of type '" "boost::shared_ptr< sdrts_reverse_burst_ff > *""'"); 

  }

  arg1 = reinterpret_cast< boost::shared_ptr< sdrts_reverse_burst_ff > * >(argp1);

  result = (sdrts_reverse_burst_ff *)(arg1)->operator ->();

  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_sdrts_reverse_burst_ff, 0 |  0 );

  return resultobj;

fail:

  return NULL;

}

这还不是全部:在这个.cxx文件的末尾,有一个巨大的数组,里面包含了所有类的函数,像这样:

PyMethodDef SwigMethods[] = {

  { (char *)"sdrts_reverse_burst_ff_sptr___deref__", _wrap_sdrts_reverse_burst_ff_sptr___deref__, METH_VARARGS, (char *)"sdrts_reverse_burst_ff_sptr___deref__(sdrts_reverse_burst_ff_sptr self)"},

  { (char *)"delete_sdrts_reverse_burst_ff_sptr", _wrap_delete_sdrts_reverse_burst_ff_sptr, METH_VARARGS, (char *)"delete_sdrts_reverse_burst_ff_sptr(sdrts_reverse_burst_ff_sptr self)"},

  { (char *)"sdrts_reverse_burst_ff_sptr_set_reverse_burst", _wrap_sdrts_reverse_burst_ff_sptr_set_reverse_burst, METH_VARARGS, (char *)"sdrts_reverse_burst_ff_sptr_set_reverse_burst(sdrts_reverse_burst_ff_sptr self, int samples) -> int"},

  { (char *)"sdrts_reverse_burst_ff_sptr_enable_reverse_burst", _wrap_sdrts_reverse_burst_ff_sptr_enable_reverse_burst, METH_VARARGS, (char *)"sdrts_reverse_burst_ff_sptr_enable_reverse_burst(sdrts_reverse_burst_ff_sptr self) -> int"},

  { (char *)"sdrts_reverse_burst_ff_sptr_reset", _wrap_sdrts_reverse_burst_ff_sptr_reset, METH_VARARGS, (char *)"sdrts_reverse_burst_ff_sptr_reset(sdrts_reverse_burst_ff_sptr self) -> int"},

  { (char *)"sdrts_reverse_burst_ff_sptr_history", _wrap_sdrts_reverse_burst_ff_sptr_history, METH_VARARGS, (char *)"sdrts_reverse_burst_ff_sptr_history(sdrts_reverse_burst_ff_sptr self) -> unsigned int"},

  { (char *)"sdrts_reverse_burst_ff_sptr_output_multiple", _wrap_sdrts_reverse_burst_ff_sptr_output_multiple, METH_VARARGS, (char *)"sdrts_reverse_burst_ff_sptr_output_multiple(sdrts_reverse_burst_ff_sptr self) -> int"},

  { (char *)"sdrts_reverse_burst_ff_sptr_relative_rate", _wrap_sdrts_reverse_burst_ff_sptr_relative_rate, METH_VARARGS, (char *)"sdrts_reverse_burst_ff_sptr_relative_rate(sdrts_reverse_burst_ff_sptr self) -> double"},

  { (char *)"sdrts_reverse_burst_ff_sptr_start", _wrap_sdrts_reverse_burst_ff_sptr_start, METH_VARARGS, (char *)"sdrts_reverse_burst_ff_sptr_start(sdrts_reverse_burst_ff_sptr self) -> bool"},

  { (char *)"sdrts_reverse_burst_ff_sptr_stop", _wrap_sdrts_reverse_burst_ff_sptr_stop, METH_VARARGS, (char *)"sdrts_reverse_burst_ff_sptr_stop(sdrts_reverse_burst_ff_sptr self) -> bool"},

  { (char *)"sdrts_reverse_burst_ff_sptr_nitems_read", _wrap_sdrts_reverse_burst_ff_sptr_nitems_read, METH_VARARGS, (char *)"sdrts_reverse_burst_ff_sptr_nitems_read(sdrts_reverse_burst_ff_sptr self, unsigned int which_input) -> uint64_t"},

  { (char *)"sdrts_reverse_burst_ff_sptr_nitems_written", _wrap_sdrts_reverse_burst_ff_sptr_nitems_written, METH_VARARGS, (char *)"sdrts_reverse_burst_ff_sptr_nitems_written(sdrts_reverse_burst_ff_sptr self, unsigned int which_output) -> uint64_t"},

  { (char *)"sdrts_reverse_burst_ff_sptr_detail", _wrap_sdrts_reverse_burst_ff_sptr_detail, METH_VARARGS, (char *)"sdrts_reverse_burst_ff_sptr_detail(sdrts_reverse_burst_ff_sptr self) -> gr_block_detail_sptr"},

  { (char *)"sdrts_reverse_burst_ff_sptr_set_detail", _wrap_sdrts_reverse_burst_ff_sptr_set_detail, METH_VARARGS, (char *)"sdrts_reverse_burst_ff_sptr_set_detail(sdrts_reverse_burst_ff_sptr self, gr_block_detail_sptr detail)"},

  { (char *)"sdrts_reverse_burst_ff_sptr_name", _wrap_sdrts_reverse_burst_ff_sptr_name, METH_VARARGS, (char *)"sdrts_reverse_burst_ff_sptr_name(sdrts_reverse_burst_ff_sptr self) -> string"},

  { (char *)"sdrts_reverse_burst_ff_sptr_input_signature", _wrap_sdrts_reverse_burst_ff_sptr_input_signature, METH_VARARGS, (char *)"sdrts_reverse_burst_ff_sptr_input_signature(sdrts_reverse_burst_ff_sptr self) -> gr_io_signature_sptr"},

  { (char *)"sdrts_reverse_burst_ff_sptr_output_signature", _wrap_sdrts_reverse_burst_ff_sptr_output_signature, METH_VARARGS, (char *)"sdrts_reverse_burst_ff_sptr_output_signature(sdrts_reverse_burst_ff_sptr self) -> gr_io_signature_sptr"},

  { (char *)"sdrts_reverse_burst_ff_sptr_unique_id", _wrap_sdrts_reverse_burst_ff_sptr_unique_id, METH_VARARGS, (char *)"sdrts_reverse_burst_ff_sptr_unique_id(sdrts_reverse_burst_ff_sptr self) -> long"},

  { (char *)"sdrts_reverse_burst_ff_sptr_to_basic_block", _wrap_sdrts_reverse_burst_ff_sptr_to_basic_block, METH_VARARGS, (char *)"sdrts_reverse_burst_ff_sptr_to_basic_block(sdrts_reverse_burst_ff_sptr self) -> gr_basic_block_sptr"},

  { (char *)"sdrts_reverse_burst_ff_sptr_check_topology", _wrap_sdrts_reverse_burst_ff_sptr_check_topology, METH_VARARGS, (char *)"sdrts_reverse_burst_ff_sptr_check_topology(sdrts_reverse_burst_ff_sptr self, int ninputs, int noutputs) -> bool"},

  { (char *)"sdrts_reverse_burst_ff_sptr_swigregister", sdrts_reverse_burst_ff_sptr_swigregister, METH_VARARGS, NULL},

  { (char *)"reverse_burst_ff", _wrap_reverse_burst_ff, METH_VARARGS, (char *)"reverse_burst_ff(int max_samples) -> sdrts_reverse_burst_ff_sptr"},

  { NULL, NULL, 0, NULL }

};

我按照以前处理.dll的经验,简单地用__declspec(dllexport)导出了所有函数。在Python中,我也可以调用我导出的_wrap_sdrts_reverse_burst_ff_sptr___deref__

import ctypes

_dll_func_list = ctypes.WinDLL("func.dll")

_reverse_burst_ref = _dll_func_list._wrap_sdrts_reverse_burst_ff_sptr___deref__

然而,这就是我能做到的极限。当我尝试访问那个类中的子函数时,比如:

_class_ref._wrap_sdrts_reverse_burst_ff_sptr_set_reverse_burst(0)

机器却告诉我:

'_wrap_sdrts_reverse_burst_ff_sptr_set_reverse_burst' 找不到。

当我尝试直接调用这个函数并传入一个参数时,像这样:

_dll_func_list ._wrap_sdrts_reverse_burst_ff_sptr_set_reverse_burst(0)

机器说:

WindowsError: exception: access violation reading 0x00000004

有没有人知道如何使用Python访问导出的SWIG封装函数?

2 个回答

2

所以最终的简短回答是,C++编译出来的文件应该是 _my_dll.pyd(而不是 _my_dll.dll),这样才能在Windows上用Python导入 my_dll。这和Linux的情况不同,在Linux上你会编译出 _my_dll.so

把 .dll 文件直接改名为 .pyd 是可以的,但如上面的评论所说,最好还是通过编译来生成这个文件。

2

SWIG除了生成一个.cxx文件外,还会生成一个.py文件。一旦你在自己的平台上构建了一个DLL(或者共享对象),要在Python中使用它,你只需要这样做:

import ModuleName

这里的ModuleName是你告诉SWIG给模块起的名字,可以通过在.i文件中使用%module或者在命令行调用时指定。

在SWIG生成的Python代码中,有处理DLL加载的代码,所以你不需要使用ctypes或其他类似的东西。生成的代码会尽量匹配你要求SWIG封装的接口,并且神奇地将调用转发到C++那边。

因此,如果sdrts_reverse_burst_ff是一个自由函数,你可以这样做:

import ModuleName

ModuleName.sdrts_reverse_burst_ff()

你需要确保构建的DLL名称是SWIG所期望的,如果不是,Python会抛出异常,这样你就能很明显地看出来。你可能还想将它链接到包含sdrts_reverse_burst_ff()的实现上,除非这个函数只是一个头文件中的函数。

撰写回答