我正在使用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
一点背景知识:
我有一个接口文件,其中包含一个包含我的包装类的头文件:
此类将对象作为私有成员。
然后我想将一些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 ++作为我的编译器并手动编译。我还在我的.i文件中放了#include“VSet.cpp”。 (参见上一篇文章中的编辑)
我现在在python中导入时出现此错误:
Symbol not found: __ZN4csmp5VData6InTextERSt14basic_ifstreamIcSt11char_traitsIcEE
Referenced from: ./_CSMPy.so
Expected in: flat namespace
我还创建了一个main来实例化该对象,并且对Initialize()的调用也有效。
答案 0 :(得分:3)
找不到符号
__ZN4csmp4VSetILm2EE6ResizeERKSt5dequeIiSaIiEERKS2_ImSaImEESA_m
在.so。感谢Dave对此进行解组,我们现在知道它指的是
csmp::VSet<2ul>::Resize(
const std::deque<int>&,
const std::deque<unsigned long> &,
const std::deque<unsigned long> &)
根据您发布的内容,您有两种类型的deques,这有点奇怪。
以下是一些尝试:
deque<int>
实例化%template(IntDeque) std::deque<int>
,因为Python对C ++模板一无所知,模板不是类,而是一个配方,因此编译器可以创建一个上课。如果你真的使用int和unsigned long,你必须实例化它们。我只在你的代码中看到int和size_t。您不能假设size_t与unsigned long相同。 关于#5:
SWIG生成标头和源文件。在头文件中,它放置了与Python C API相关的函数,并将它们注册到Python解释器中,在这些函数的主体中,它确定了从库中调用的C / C ++函数。在DLL中找不到上面的Resize的事实表明SWIG认为需要Resize的这个重载,所以它是从它生成的函数中调用的,但你的C ++ lib没有实例化它。
这怎么可能?在C ++ lib中,您有一个带有Resize方法的类模板。类模板的技巧是编译器只会为DLL中使用的方法生成代码(因此,如果您的类定义了5个方法,但是您的DLL只使用1,则不会为其他4个方法生成代码),如果您在库中显式实例化模板,则除外。你可以通过声明
来做到这一点template class VSet<2ul>;
(无论2ul代表什么)在您的C ++ DLL中,或者通过.i文件中的%template指令包装DLL。这将实例化VSet<2ul>
的所有方法,因此Resize也将存在。 IF 由此生成的Resize具有参数deque<int>
和deque<unsigned long>
。您的代码表明您假设size_t是unsigned int。如果size_t的typedefd为unsigned int,SWIG应该能够处理它,但可能存在错误。最好不要假设。您可以为unsigned int添加Resize重载。或者您可以在安装程序中创建一个内联扩展方法,获取两个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);
}
}
答案 1 :(得分:1)
问题很可能不是编译问题。您的头文件和实现文件之间的不匹配更有可能。标头承诺您没有实现的接口。如果您从未在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的回答的评论。
答案 2 :(得分:0)
我正在开始一个新的答案,因为VSet&lt; 2U&gt;的事实没有包裹使我的大部分其他答案与这个问题无关(虽然那里的一切都还是正确的)。并且Setup具有VSet&lt; 2U&gt;类型的数据成员的事实。与SWIG无关,因为您没有直接从Python访问Setup :: v。
验证安装程序在没有Python或SWIG的情况下工作:创建一个void main(),在其中实例化一个Setup并调用其InitializeSetup()方法,构建并运行。由于找不到符号,很可能会得到相同的运行时错误。
安装对象代码正在寻找
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
可能没有。是否有其他已实例化的Resize重载?这可以给出一个线索。
编译器无法为VSet&lt; 2U&gt;实例化Resize可能有多种原因。例如,模板类的方法定义必须出现在.h中,否则编译器将如何知道要生成哪些代码?如果您告诉编译器编译VSet.cpp,除非您为特定类型显式实例化模板,否则它不会在.o中生成任何内容。然后.o将包含具有该类型的特定模板化类的类的对象代码。我喜欢让我的方法定义分开类定义,但之后我在.h中包含.cpp,因为.h的任何用户都需要包含.cpp,因此编译器可以生成正确的代码。对你而言,这意味着你将在VSet.h的底部有一个#include "VSet.cpp" // templated code
。