简体   繁体   English

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

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

I am using swig to write a wrapper to a c++ class for use with python. 我正在用swig将包装器写入c ++类,以便与python一起使用。

When I try to do from CSMPy import * ( CSMPy is my module) I get this message: 当我尝试from CSMPy import *CSMPy是我的模块)执行操作时from CSMPy import *以下消息:

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

A little bit of background: 一点背景:

I have one interface file that has an include to one header file containing my wrapper class: 我有一个接口文件,该文件包含一个包含我的包装器类的头文件:

This class has an object as a private member. 此类有一个对象作为私有成员。

I then want to pass a number of objects of type std::deque<int> to a member function of this object like so: this->object.Function(int_deque_a,int_deque_b) where object is a member of the class I am wrapping using swig. 然后,我想将多个std::deque<int>类型的对象传递给该对象的成员函数,如下所示: this->object.Function(int_deque_a,int_deque_b)其中object是我正在包装的类的成员用swig。

When I comment the above line out everything works like a charm. 当我评论以上内容时,所有内容都像一个魅力。 All the containers I am passing are valid datatypes to pass to this objects member function and contain the correct number of entries. 我要传递的所有容器都是有效的数据类型,可传递给此对象成员函数并包含正确数量的条目。

Everything compiles and this occurs only on import of the module. 一切都会编译,并且这仅在模块导入时发生。

What am I missing here? 我在这里想念什么?

I am using distutils to compile using python setup.py install 我正在使用distutils使用python setup.py install进行编译

setup.py: 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 is a static library. MyLibrary是静态库。

Edit 1: I am providing you with a version of the code I can show to everyone 编辑1:我为您提供了可以向大家展示的代码版本

Setup.h 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 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 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"

Edit 2: 编辑2:

I did nm -gC myLib.so 我做了nm -gC myLib.so

I found this echo 我发现了这个回声

__ZN4csmp4VSetILm2EE6ResizeERKNSt3__15dequeIiNS2_9allocatorIiEEEERKNS3_ImNS4_ImEEEESC_m

which on c++ tilt tells me: 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)

couple of notes on this, I have switched to using clang++ as my compiler and manually compiling. 关于这两个注意事项,我已改用clang ++作为编译器并手动进行编译。 I have also put #include "VSet.cpp" in my .i file. 我也将#include“ VSet.cpp”放在了我的.i文件中。 (See edit in previous post) (请参阅上一篇文章中的编辑)

I am now getting this error on import in python: 我现在在python中导入时遇到此错误:

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

I have also created a main that will instantiate the object and the call to Initialize() works. 我还创建了一个将实例化该对象的主体,并且对Initialize()的调用起作用。

It's not finding the symbol 没有找到符号

__ZN4csmp4VSetILm2EE6ResizeERKSt5dequeIiSaIiEERKS2_ImSaImEESA_m

in the .so. 在.so中。 Thanks to Dave for demangling this, we now know that it refers to 感谢Dave取消了此操作,我们现在知道它指的是

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

So it is a little odd that you have two types of deques, based on what you posted. 因此,根据您发布的内容,您有两种类型的双端队列很奇怪。

Here are some things to try: 这里有一些尝试:

  1. Verify that your _CSMP.so links to the STL library that comes with your compiler, you may have to specify an extra switch or field in your setup.py. 验证_CSMP.so链接到编译器随附的STL库,您可能必须在setup.py中指定一个额外的开关或字段。 Your code works when Resize is not there, you say, so that's not likely the problem. 您说,当没有“调整大小”时,您的代码可以工作,所以这可能不是问题。
  2. turn on verbose output in your setup.py so that you can see the compilation and link command line parameters 在setup.py中打开详细输出,以便可以看到编译和链接命令行参数
  3. make sure you %include std_deque.i in your SWIG .i file. 确保在SWIG .i文件中%stst_deque.i。 You're not getting compile error so this is not likely the issue. 您不会遇到编译错误,因此这可能不是问题。
  4. verify that you have instantiated your deque<int> with a %template(IntDeque) std::deque<int> in your .i, since Python knows nothing about C++ templates, and a template is not a class, but a recipe so compiler can create a class for you. 验证您是否已在.i中使用%template(IntDeque) std::deque<int>实例化了deque<int> ,因为Python对C ++模板一无所知,并且模板不是类,而是配方,因此编译器可以为您创建一个类。 If you really do use both int and unsigned long, you have to instantiate both. 如果确实使用int和unsigned long,则必须实例化这两个实例。 I'm only seeing int and size_t in your code. 我只在您的代码中看到int和size_t。 You can't assume that size_t is same as unsigned long. 您不能假定size_t与unsigned long相同。
  5. Confirm that your DLL contains an intantiation of this Resize method for unsigned int. 确认您的DLL包含针对未签名int的此Resize方法的实例化。 in your C++ code. 在您的C ++代码中。 I think you defined the size_t version via, or are the unsigned long unexpected? 我认为您是通过size_t版本定义的,还是unsigned long很意外?

About #5: 关于#5:

SWIG generates a header and a source file. SWIG生成头文件和源文件。 In the header it puts functions that adhere to the Python C API and registers them in the Python interpreter, and in the body of those functions it figures out what C/C++ functions to call from your library. 在标头中,它将遵循Python C API的功能放入Python解释器中,并在这些功能的主体中指出从库中调用哪些C / C ++函数。 The fact that the above Resize is not found in DLL is an indication that SWIG thinks this overload of Resize is needed, so it is called from the function it generated, but your C++ lib did not instantiate it. 在DLL中找不到上述Resize的事实表明SWIG认为需要Resize的这种重载,因此从它生成的函数中调用它,但是C ++库没有实例化它。

How is this possible? 这怎么可能? In your C++ lib, you have a class template with a Resize method. 在C ++库中,您有一个带有Resize方法的类模板。 The trick with class templates is that the compiler will only generate code for the methods that are used in the DLL (so if your class defines 5 methods but your DLL only uses 1, it won't generate code for the other 4 methods), except if you explicitly instantiate the template in your library. 使用类模板的诀窍是,编译器将只为DLL中使用的方法生成代码(因此,如果您的类定义了5种方法,但您的DLL仅使用1种,则它不会为其他4种方法生成代码), 除非您在库中显式实例化模板, 否则除外 You would do this by putting a statement 您可以通过声明来做到这一点

template class VSet<2ul>; 

(whatever 2ul stands for) either in your C++ DLL, or the wrapper DLL via the %template directive in your .i file. (无论2ul代表什么)都可以在C ++ DLL中,也可以通过.i文件中的%template指令访问包装DLL。 This will instantiate all methods of VSet<2ul> , so Resize will be there too. 这将实例化VSet<2ul>所有方法,因此Resize也将存在。 IF the Resize thus generated has parameters deque<int> and deque<unsigned long> . 如果这样生成的Resize具有参数deque<int>deque<unsigned long> Your code indicates that you are assuming that size_t is unsigned int. 您的代码表明您假设size_t是unsigned int。 If size_t is typedefd to unsigned int, SWIG should be able to handle it, but maybe there is a bug. 如果将size_t类型定义为unsigned int,SWIG应该能够处理它,但是可能存在错误。 Better not assume. 最好不要假设。 You could add a Resize overload for unsigned int. 您可以为unsigned int添加Resize重载。 Or you could create an inline extension method in Setup taking two unsigneld long deques and calling the size_t version. 或者,您可以在安装程序中创建一个内联扩展方法,采用两个无符号长双端队列并调用size_t版本。 Something like 就像是

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

The problem most likely isn't a compilation issue. 问题很可能不是编译问题。 It's much more likely that there's a mismatch between your header file and implementation files. 头文件和实现文件之间很可能不匹配。 The header promises an interface that you aren't implementing. 标头承诺您未实现的接口。 You won't see the undefined reference in a standalone, C++-only application if you never call that member function in your C++ code. 如果您从未在C ++代码中调用该成员函数,则在独立的仅C ++应用程序中将看不到未定义的引用。

The mismatch between header and implementation becomes a real problem when you tell SWIG to wrap that C++ header. 当您告诉SWIG包装该C ++标头时,标头与实现之间的不匹配成为一个实际问题。 The generated SWIG code contains a reference to that unimplemented function. 生成的SWIG代码包含对该未实现函数的引用。 The dynamic linking fails because that function is never defined. 动态链接失败,因为从未定义该功能。

So what function is it? 那是什么功能呢? Look at the error message: 查看错误消息:

Symbol not found: __ZN4csmp4VSetILm2EE6ResizeERKSt5dequeIiSaIiEERKS2_ImSaImEESA_m

This tells you exactly what's missing, but in a very convoluted (name mangled) way. 这可以准确地告诉您所缺少的内容,但是以非常复杂的方式(名称混乱)。 Copy that symbol, open a terminal window, and issue the command echo <paste mangled name here> | c++filt 复制该符号,打开一个终端窗口,然后发出命令echo <paste mangled name here> | c++filt echo <paste mangled name here> | c++filt : echo <paste mangled name here> | c++filt

echo __ZN4csmp4VSetILm2EE6ResizeERKSt5dequeIiSaIiEERKS2_ImSaImEESA_m | c++filt

The c++filt utility is a very useful capability on Macs and Linux boxes. c++filt实用程序在Mac和Linux机器上非常有用。 In this case it gives you the unmangled name of the missing symbol. 在这种情况下,它为您提供了丢失符号的完整名称。 See my comment to Schollii's answer. 请参阅我对Schollii答案的评论。

I'm starting a new answer because the fact that VSet<2U> is not wrapped makes most of my other answer not relevant to this problem (although everything in there is still correct). 我开始一个新的答案,因为没有包装VSet <2U>的事实使我的大多数其他答案与该问题无关(尽管其中的所有内容仍然正确)。 And the fact that Setup has a data member of type VSet<2U> is not relevant to SWIG since you aren't accessing Setup::v directly from Python. 而且,安装程序具有VSet <2U>类型的数据成员这一事实与SWIG无关,因为您不是直接从Python访问Setup :: v。

Verify that Setup works without Python or SWIG: create a void main() where you instantiate a Setup and call its InitializeSetup() method, build and run. 验证安装程序是否可以在没有Python或SWIG的情况下运行:创建一个无效的main(),在其中实例化安装程序并调用其InitializeSetup()方法,进行构建并运行。 Most likely yo will get same runtime error due to symbol not found. 由于找不到符号,您很可能会获得相同的运行时错误。

The Setup object code is looking for 安装程序对象代码正在寻找

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

So verify that your DLL has this symbol: 因此,请验证您的DLL具有以下符号:

~> nm -gC yourLib.so

It probably doesn't. 可能不是。 Are there other Resize overloads that were instantiated? 是否还有其他实例化的Resize重载? This can give a clue. 这可以提供一个线索。

There could be a variety of reasons why the compiler failed to instantiate the Resize for VSet<2U>. 编译器无法实例化VSet <2U>的Resize可能有多种原因。 For example, a template class's method definitions must appear in the .h otherwise how it the compiler going to know what code to generate? 例如,模板类的方法定义必须出现在.h中,否则编译器将如何知道要生成什么代码? If you tell the compiler to compile VSet.cpp it won't generate anything in the .o unless you explicitly instantiate the template for a specific type. 如果告诉编译器编译VSet.cpp,则除非您为特定类型显式实例化模板,否则它不会在.o中生成任何内容。 Then the .o will contain object code for class of that specific templated class with that type. 然后,.o将包含该类型的特定模板化类的类的目标代码。 I like to have my method definitions separate class definition, but then I include the .cpp in the .h since any user of the .h would need to also nclude the .cpp so compiler can generate the right code. 我喜欢将我的方法定义与单独的类定义分开,但是随后我将.cpp包含在.h中,因为.h的任何用户都需要同时包含.cpp以便编译器可以生成正确的代码。 For you this would mean you would have at the bottom of VSet.h an #include "VSet.cpp" // templated code . 对您来说,这意味着您将在VSet.h的底部拥有#include "VSet.cpp" // templated code

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

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