使用SWIG包装C 类,该类调用另一个对象成员函数

Using SWIG to wrap a C++ class that calls another objects member function

本文关键字:一个对象 成员 函数 调用 SWIG 包装 使用      更新时间:2023-10-16

我正在使用swig将包装器写入C 类,以与Python一起使用。

当我尝试执行from CSMPy import *CSMPy是我的模块)时,我会收到此消息:

ImportError: dlopen(/Users/MUL_mac2/anaconda/lib/python2.7/site-packages/_CSMPy.so, 2): Symbol not found: __ZN4csmp4VSetILm2EE6ResizeERKSt5dequeIiSaIiEERKS2_ImSaImEESA_m
  Referenced from: /Users/MUL_mac2/anaconda/lib/python2.7/site-packages/_CSMPy.so
  Expected in: dynamic lookup

一点点背景:

我有一个接口文件,其中包含一个包含我的包装器类的标头文件:

此类具有私人成员的对象。

i然后要将std::deque<int>类型的许多对象传递给成员函数像这样的对象: this->object.Function(int_deque_a,int_deque_b) object是我使用swig包装的类的成员。

当我评论上面的排队时,一切都像魅力一样工作。我通过的所有容器都是传递到此对象成员函数并包含正确数量条目的有效数据类型。

所有内容都编译了,这仅发生在模块的导入上。

我在这里缺少什么?

我正在使用distutils使用python setup.py install

编译

setup.py:

CSMPy_module = Extension('_CSMPy',
                                  include_dirs = [Bunch of include directories here],
                                  library_dirs = ['MyLibraryPath'],
                                  libraries = ['MyLibrary'],
                                  sources=['CSMPy_wrap.cxx', 'WrapperClass.cpp'],
                                  )
setup (name = 'CSMPy',
   version = '0.1',
   author = "My name",
   description = """Simple Test""",
   ext_modules = [CSMPy_module],
   py_modules = ["CSMPy"],
   )

mylibrary是一个静态库。

编辑1:我正在为您提供可以向所有人展示的代码版本

setup.h

#include <iostream>
#include <vector>
#include <deque>
#include "VSet.h"

class Setup {
public:
  Setup();
  ~Setup();
  void InitializeSetup();
private:
  std::deque<size_t> npes;
  std::deque<size_t> epes;
  std::deque<std::vector<size_t> > eni; //plist
  std::deque<std::vector<csmp::int32> > enb; //pfverts
  std::deque<std::vector<csmp::double64> > ncl; //pelmt
  std::map<size_t, csmp::int32> bnf; //bflags
  std::deque<csmp::int32>   et;
  csmp::VSet<2U> v;
};

setup.cpp

#include "Setup.h"

Setup::Setup() {
  std::cout<<"Setup initialized."<<std::endl;
}
Setup::~Setup() {
}
void Setup::InitializeSetup() {

  for(size_t i = 0; i < this->eni.size(); i++) {
      this->npes.push_back(this->eni[i].size());
  }
  for(size_t i = 0; i < this->enb.size(); i++) {
    this->epes.push_back(this->enb[i].size());
  }
  this->v.Resize(this->et, npes, epes, this->ncl.size()); //This is the line that does not work
}

csmpy.i

%module CSMPy
%{
#define SWIG_FILE_WITH_INIT
#include "stdlib.h"
#include <vector>
#include <deque>
#include <map>
#include "VSet.cpp"
#include "Setup.h"
#include "Number_Types.h"
%}
%include "Number_Types.h"
%include "std_map.i"
%include "std_vector.i"
%include "std_deque.i"
// Instantiate templates used by CSMPy
namespace std {
  %template() pair<size_t, csmp::int32>;
  %template() pair<size_t, csmp::double64>;
  %template() pair<size_t, vector<size_t> >;
  %template() pair<size_t, vector<csmp::int32> >;
  %template() pair<size_t, vector<csmp::double64> >;
  %template(Deque_SizeT) deque<size_t>;
  %template(Deque_Int) deque<csmp::int32>;
  %template(Vector_SizeT) vector<size_t>;
  %template(Vector_Int32) vector<csmp::int32>;
  %template(Vector_Double64) vector<csmp::double64>;
  %template(Deque_Double64) deque<csmp::double64>;
  %template(Deque_Vector_Int) deque<vector<csmp::int32> >;
  %template(Deque_Vector_SizeT) deque<vector<size_t> >;
  %template(Deque_Vector_Double64) deque<vector<csmp::double64> >;
  %template(Map_SizeT_Int) map< size_t, csmp::int32>;
  %template(Map_SizeT_Double64) map< size_t, csmp::double64>;
  %template(Map_SizeT_Vector_SizeT) map< size_t, vector<size_t> >;
  %template(Map_SizeT_Vector_Int) map< size_t, vector<csmp::int32> >;
  %template(Map_SizeT_Vector_Double64) map< size_t, vector<csmp::double64> >;
}
%include "Setup.h"

编辑2:

我做了nm -gc mylib.so

我找到了这个回声

__ZN4csmp4VSetILm2EE6ResizeERKNSt3__15dequeIiNS2_9allocatorIiEEEERKNS3_ImNS4_ImEEEESC_m

c 倾斜告诉我:

csmp::VSet<2ul>::Resize(std::__1::deque<int, std::__1::allocator<int> > const&, std::__1::deque<unsigned long, std::__1::allocator<unsigned long> > const&, std::__1::deque<unsigned long, std::__1::allocator<unsigned long> > const&, unsigned long)

关于此的几个笔记,我切换到使用Clang 作为编译器和手动编译。我还将#include" vset.cpp"放在我的.i文件中。(请参阅上一篇文章中的编辑)

我现在在Python中遇到此错误:

Symbol not found: __ZN4csmp5VData6InTextERSt14basic_ifstreamIcSt11char_traitsIcEE
  Referenced from: ./_CSMPy.so
  Expected in: flat namespace

我还创建了一个主体,该主体将实例化对象和调用initialize()工作。

它找不到符号

__ZN4csmp4VSetILm2EE6ResizeERKSt5dequeIiSaIiEERKS2_ImSaImEESA_m

在.so中。感谢戴夫(Dave)脱离了这个问题,我们现在知道它是指

csmp::VSet<2ul>::Resize(
    const std::deque<int>&, 
    const std::deque<unsigned long> &, 
    const std::deque<unsigned long> &)

因此,根据您的发布,您有两种脱口机有点奇怪。

这里有一些尝试:

  1. 验证您的_CSMP.SO链接到编译器随附的STL库,您可能必须在setup.py中指定额外的开关或字段。您说,当调整大小不存在时,您的代码起作用,所以这不太可能问题。
  2. 打开setup.py中的详细输出,以便您可以看到汇编和链接命令行参数
  3. 确保您%将std_deque.i纳入您的swig .i文件中。您不会遇到编译错误,因此这不太可能。
  4. 验证您是否已在.i中使用%template(IntDeque) std::deque<int>实例化deque<int>,因为Python对C 模板一无所知,并且模板不是类,而是配方,因此编译器可以为您创建类。如果您确实同时使用了INT和未签名的长时间,则必须同时实例化。我只在您的代码中看到int和size_t。您不能假设size_t与unsigned long相同。
  5. 确认您的DLL包含此调整方法的无符号INT的插图。在您的C 代码中。我认为您通过通过size_t版本定义了size_t版本,还是未签名的长期意外?

大约5:

swig生成标头和一个源文件。在标题中,它放大了粘附于Python C API的功能,并将它们注册在Python解释器中,并且在这些功能的正文中,它弄清楚了从库中调用的C/C 功能。在DLL中找不到上述调整大小的事实表明,SWIG认为需要调整大小的超载,因此从其生成的函数中调用,但是您的C LIB并未实例化。

这怎么可能?在您的C LIB中,您有一个带有调整大小方法的类模板。类模板的诀窍是编译器只会为DLL中使用的方法生成代码(因此,如果您的类定义了5种方法,但您的DLL仅使用1个方法,则不会为其他4种方法生成代码),除非如果您明确实例化库中的模板。您将通过提出语句来做到这一点

template class VSet<2ul>; 

(无论2英寸代表)在您的C dll中,或通过.i文件中的%模板指令包装DLL。这将实例化VSet<2ul>的所有方法,因此调整大小也将在那里。如果 因此生成的调整大小具有参数deque<int>deque<unsigned long>。您的代码表明您假设size_t是unsigned int。如果size_t被打字到未签名的int,则SWIG应该能够处理它,但也许有一个错误。最好不要假设。您可以为未签名的INT添加调整大小过载。或者,您可以在设置中创建一个内联扩展方法,以获取两个Unsigneld Long Deques并调用size_t版本。像

%template DequeULong std::deque<unsigned long>
%extend Setup {
   void Resize(const DequeInt& a, const DequeULong& b) 
   {
       DequeSizet c;
       ... copy b into a DequeSizet
       Resize(a, c);
   }
}

这个问题很可能不是汇编问题。您的标题文件和实现文件之间的可能性不匹配。标头承诺您未实现的接口。您不会在独立的C 中看到未定义的参考 - 仅当您从未在C 代码中调用该成员函数的应用程序。

当您告诉Swig包装C 标头时,标题和实现之间的不匹配成为一个真正的问题。生成的SWIG代码包含对该尚未完成功能的引用。动态链接失败,因为该功能从未定义。

那是什么功能?查看错误消息:

Symbol not found: __ZN4csmp4VSetILm2EE6ResizeERKSt5dequeIiSaIiEERKS2_ImSaImEESA_m

这告诉您完全缺少的东西,但以一种非常令人费解的(名称)方式。复制该符号,打开终端窗口,然后发出命令echo <paste mangled name here> | c++filt

echo __ZN4csmp4VSetILm2EE6ResizeERKSt5dequeIiSaIiEERKS2_ImSaImEESA_m | c++filt

c++filt实用程序是Mac和Linux框上非常有用的功能。在这种情况下,它为您提供了丢失符号的未直角名称。请参阅我对Schollii答案的评论。

我正在开始一个新答案,因为vset&lt; 2u>未包装的事实使我的大多数其他答案都使与此问题无关(尽管那里的所有内容仍然正确)。并且设置具有VSET类型的数据成员2U>的数据成员与SWIG无关,因为您无法直接从Python访问SETUP :: V。

验证设置在没有python或swig的情况下工作:创建一个void main(),您可以在其中实例化设置并调用其onitializeSetup()方法,构建和运行。由于找不到符号,很可能会遇到相同的运行时错误。

设置对象代码正在寻找

csmp::VSet<2ul>::Resize(
    const std::deque<int>&, 
    const std::deque<unsigned long> &, 
    const std::deque<unsigned long> &,
    unsigned long)

如此验证您的DLL具有此符号:

~> nm -gC yourLib.so

可能没有。是否还有其他调整大小过载可以实例化?这可以给出线索。

编译器无法实例化调整大小的VSET&lt; 2u>可能存在多种原因。例如,模板类的方法定义必须出现在.h中,否则编译器将如何知道要生成什么代码?如果您告诉编译器编译vset.cpp,除非您明确实例化特定类型的模板,否则不会在.o中生成任何内容。然后,.o将包含该类型该特定模板类的类别的对象代码。我喜欢将我的方法定义单独使用类定义,但是然后将.cpp包含在.h中,因为.H的任何用户都需要nclude .cpp,以便编译器可以生成正确的代码。对于您来说,这意味着您将在VSET的底部。h #include "VSet.cpp" // templated code

相关文章: