【问题标题】:Using SWIG wrapped functions from Windows .dll使用来自 Windows .dll 的 SWIG 包装函数
【发布时间】:2012-02-17 06:55:40
【问题描述】:

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

版本信息

Python:2.6.4

痛饮:2.0.4

总体情况是:我有一些在 Linux 下使用 C++ 开发并使用 SWIG 包装的代码。我在Linux下将C++源码编译成.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 }

};

我遵循了我对.dlls 的旧经验,并用一个简单的__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:异常:访问冲突读取 0x00000004

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

【问题讨论】:

    标签: c++ python dll shared-libraries swig


    【解决方案1】:

    除了 .cxx 文件之外,SWIG 还会生成一个 .py 文件。在平台上构建 DLL(或共享对象)后,在 Python 本身中使用它所需要做的就是

    import ModuleName
    

    ModuleName 是你告诉 SWIG 调用模块的地方,或者在调用它时通过 .i 文件中的 %module 从命令行调用它。

    在 SWIG 生成的 Python 中,有代码可以为您处理 DLL 的加载 - 无需使用 ctypes 或类似的东西。生成的代码与您要求 SWIG 在 Python 中尽可能紧密地包装的接口相匹配,并神奇地将调用交给 C++ 端。

    因此,如果sdrts_reverse_burst_ff 是您可以执行的免费功能:

    import ModuleName
    
    ModuleName.sdrts_reverse_burst_ff()
    

    您需要确保使用 SWIG 期望的名称构建 DLL - 如果不是这种情况,Python 引发的异常会很明显。您可能还想将它与包含 sdrts_reverse_burst_ff() 的实现链接起来,除非那是一个仅限标头的函数。

    【讨论】:

    • 我确实使用了生成的 python 文件,它有一个导入助手。但导入 _my_dll 时失败,并显示: ImportError: No module named _my_dll。我将 _my_dll 的绝对路径添加到 PYTHONPATH 和 LD_LIBRARY_PATH 中,它应该能够找到它。
    • @user1165959 - 你需要确保它被称为 exactly "_my_dll.dll" 如果那是 Python 抱怨的。在 Windows 系统上,我倾向于在调用 Python 时将其放在当前目录中。无论哪种方式,ctypes 都不是修复它的方法 - 你需要修复路径+加载问题,它会再次工作。
    • 是的,它的名字就是_my_dll.dll,我也试过把它放在c:\Python27下,还是找不到。只有在使用 ctypes.WinDLL("_my_dll.dll") 时才能找到 dll。但既然你提到这不是这样做的方法,我觉得我制作的这个 dll 没有编译成 SWIG 可识别的格式。我使用 swig 的方式是: swig -module _my_dll -fvirtual -python -modern -c++ -outdir 。 -o _my_dll.cxx _my_dll.i 然后我将 _my_dll.cxx 与我使用 VC++ 2008 express edition 生成 _my_dll.i 的 src 一起编译成一个 dll。我做错什么了吗?
    • @user1165959 - 我认为在 Windows 上,您需要将 .dll 重命名为 .pyd 以便 python 通过导入来获取它。 (docs.python.org/faq/…)
    • 是的,但不是通过重命名,而是通过重建完成。我打开了一个 swig 附带的示例构建,并插入了我的源代码和 .i 文件并从那里构建。一个 .pyd 文件已经构建并且现在可以运行了。感谢您的帮助
    【解决方案2】:

    所以最后的简短回答似乎是 C++ 构建应该生成 _my_dll.pyd(而不是 _my_dll.dll),以便能够在 Windows 上的 Python 中导入 my_dll。这与 Linux 构建形成对比,后者将构建 _my_dll.so

    只需将 .dll 文件重命名为 .pyd 即可,但最好构建它,正如上面 cmets 中所指出的那样。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-10
      • 1970-01-01
      • 2021-11-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-05
      相关资源
      最近更新 更多