2014-01-18 61 views
0

我正在使用swig將包裝器寫入C++類以便與python一起使用。使用SWIG來包裝調用另一個對象成員函數的C++類

當我嘗試做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是我使用痛飲包裹類的成員。

當我評論上面的一行時,一切都像魅力一樣。 我傳遞的所有容器都是傳遞給此對象成員函數的有效數據類型,並且包含正確數量的條目。

所有內容都會編譯並且僅在導入模塊時纔會發生。

我在這裏錯過了什麼?

我使用的distutils使用Python的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是一個靜態庫。

編輯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:

我做納米-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 

我還創建了一個主,將實例化對象,並調用初始化()的作品。

+0

背景部分太難理解了,你能發表一些代碼嗎(只是相關部分)? – Schollii

+0

我不能發佈任何代碼,因爲它是專有的。我已經爲你編碼了代碼。 –

+0

這可能與您使用gcc編譯和鏈接'CSMPy'的方式有很大關係。請提供用於構建模塊的命令行。 – mockinterface

回答

3

它沒有找到符號

__ZN4csmp4VSetILm2EE6ResizeERKSt5dequeIiSaIiEERKS2_ImSaImEESA_m 
的。所以

。感謝戴夫demangling這一點,我們現在知道,它指的是

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

所以這是一個有點古怪,你有兩種類型的雙端的基礎上,您發佈的內容。

這裏有一些事情要嘗試:

  1. 確認您_CSMP.so鏈接隨附你的編譯器的STL庫,你可能必須指定在setup.py一個額外的開關或領域。你的代碼在Resize不存在的時候起作用,你說,所以這可能不是問題。
  2. 在您的setup.py中打開詳細輸出,以便您可以看到編譯和鏈接命令行參數
  3. 確保您在swIG .i文件中包含std_deque.i。你沒有收到編譯錯誤,所以這可能不是問題。
  4. 驗證您是否在.i中使用%template(IntDeque) std::deque<int>實例化了deque<int>,因爲Python對C++模板一無所知,並且模板不是類,但編譯器可以爲您創建一個類。如果你真的使用int和unsigned long,你必須實例化兩者。我只在你的代碼中看到int和size_t。你不能認爲size_t和unsigned long是一樣的。
  5. 確認您的DLL包含此Resize方法的unsigned int的intantiation。在你的C++代碼中。我認爲你通過定義size_t版本,或者是無符號的長意外?

關於#5:

SWIG產生一個頭和一個源文件。在頭文件中,它提供了遵循Python C API的函數,並將它們註冊到Python解釋器中,並在這些函數的主體中找出了從庫中調用哪些C/C++函數。在DLL中沒有找到上述Resize的事實表明SWIG認爲Resize的這種重載是需要的,所以它從它生成的函數調用,但是您的C++ lib沒有實例化它。

這怎麼可能?在你的C++庫中,你有一個帶有Resize方法的類模板。類模板的技巧是編譯器只會生成DLL中使用的方法的代碼(所以如果你的類定義了5個方法,但你的DLL只使用1,它不會爲其他4個方法生成代碼), ,除了,如果您明確實例化庫中的模板。你會放一個聲明

template class VSet<2ul>; 

(無論2UL代表)無論是在你的C++ DLL,或包裝DLL通過模板%指令在.i文件做到這一點。這將實例化VSet<2ul>的所有方法,因此Resize也將存在。 如果由此生成的調整大小具有參數deque<int>deque<unsigned long>。你的代碼表明你假設size_t是unsigned int。如果size_t是unsigned int的typedefd,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); 
    } 
} 
+0

Demangling'__ZN4csmp4VSetILm2EE6ResizeERKSt5dequeIiSaIiEERKS2_ImSaIEE SA_m'產生'csmp :: VSet <2ul> ::調整大小(std :: deque > const&,std :: deque > const&,std :: deque > const&,unsigned long)'。 –

+0

@DavidHammen謝謝,我已經更新了該信息的答案 – Schollii

+0

+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的回答的評論。

0

我開始一個新的答案,因爲VSet < 2U>沒有被包裝的事實使得我的其他答案大部分與這個問題無關(儘管那裏的所有內容仍然是正確的)。而且安裝程序具有類型VSet < 2U>的數據成員的事實與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的大小< 2U>。例如,模板類的方法定義必須出現在.h中,否則編譯器將如何知道要生成的代碼?如果你告訴編譯器編譯VSet.cpp,它不會在.o中產生任何東西,除非你明確地實例化一個特定類型的模板。然後,.o將包含具有該類型的特定模板類的類的對象代碼。我喜歡讓我的方法定義分開類定義,但是隨後將.cpp包含在.h中,因爲.h的任何用戶都需要包含.cpp,因此編譯器可以生成正確的代碼。對你而言,這意味着你將在VSet.h的底部有一個#include "VSet.cpp" // templated code

+0

我已經更新了我的帖子,並提供了關於您的建議的結果。 –

+0

我誠實地想着改用boost.python代替swig,看起來這是一個永無止境的故事。 –

相關問題