使用SWIG包装C 类,该类调用另一个对象成员函数
Using SWIG to wrap a C++ class that calls another objects member function
我正在使用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> &)
因此,根据您的发布,您有两种脱口机有点奇怪。
这里有一些尝试:
- 验证您的_CSMP.SO链接到编译器随附的STL库,您可能必须在setup.py中指定额外的开关或字段。您说,当调整大小不存在时,您的代码起作用,所以这不太可能问题。
- 打开setup.py中的详细输出,以便您可以看到汇编和链接命令行参数
- 确保您%将std_deque.i纳入您的swig .i文件中。您不会遇到编译错误,因此这不太可能。
- 验证您是否已在.i中使用
%template(IntDeque) std::deque<int>
实例化deque<int>
,因为Python对C 模板一无所知,并且模板不是类,而是配方,因此编译器可以为您创建类。如果您确实同时使用了INT和未签名的长时间,则必须同时实例化。我只在您的代码中看到int和size_t。您不能假设size_t与unsigned long相同。 - 确认您的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
。
- 我有一个对象,它将在整个程序的持续时间内实例化,但一个类成员不会,我应该动态分配它吗?
- 在 C++ 中声明 const 对象需要用户定义的默认构造函数.如果我有一个可变成员变量,为什么不呢?
- 复制赋值函数如何访问另一个对象的私有成员(Stroustroup 原则和实践书)?
- 我们可以有一个 setter 成员函数作为从 const 对象引用的 const 吗?
- 在C++中,是否可以"overload"作为另一个类成员的对象?
- 如何将 c++ 类包装到 python 中,以便我可以使用 pybind11 访问其成员的公共方法(成员是一个对象指针)
- 复制一个对象并使两者共享一个成员变量 (C++)
- 编译问题 C++ 同时,尝试通过调用另一个对象中的成员函数来创建 std:: 线程
- 有没有办法为静态对象成员定义一个符合开关标准的常量?
- 我如何访问一个对象的向量的成员变量,该对象是从类中的成员变量
- C++ Qt4.8 :: 将对象传递给另一个类 - 成员访问不完整类型错误
- 只有当声明一个对象时,内存空间才会分配给类的数据成员,那么为什么 Sizeof(class_name) 给我结果
- 如何在C 中的另一个对象的同一数据成员中输入另一个字符串
- 使用SWIG包装C 类,该类调用另一个对象成员函数
- 从另一个对象调用成员函数时出现问题
- 在另一个 QThread 中访问对象成员
- 当一个没有参数的成员函数被c++中的一个对象调用时会发生什么
- 我可以使用另一个类成员初始化初始化列表中的对象吗?
- 成员函数指针指向另一个对象的方法
- 另一个对象所包含的一个对象如何可以更改容器对象的私有数据成员