2011-09-21 251 views
1

我一直在關注使用Swig將C和TCL結合在一起的教程。該教程似乎正常工作,但最終我遇到了一個我無法解決的錯誤。情況如下:使用Swig結合使用C和TCL

我跟着的教程是: http://www.swig.org/tutorial.html

我有一個名爲test.c的文件:

char *HelloWorld() 
{ 
    return "hello world"; 
} 

,另一個名爲test.i:

%module test 
%{ 
/* Put header files here or function declarations like below */ 
extern char *HelloWorld(); 
%} 

extern char *HelloWorld(); 

然後我用下面的命令行參數來準備正確的文件:

gcc -c test.c -o test.o 
swig -tcl test.i 
gcc -c test_wrap.c -o test_wrap.o 
gcc -dynamiclib -framework Tcl test.o test_wrap.o -o test.so 

最後我試着加載它:

tclsh 
% load test.so test 

這是我收到以下錯誤點:

dlsym(0x100600090, Test_Unload): symbol not founddlsym(0x100600090, Test_SafeUnload): symbol not found 

據我所知,我沒有從教程流浪。任何人都可以告訴我這是如何得到這個錯誤,更重要的是如何擺脫它?

在此先感謝!

+0

Tcl有它自己的*優秀的* C接口。我建議只研究它,而不是浪費時間在SWIG上。 – kostix

+0

我會,但我做這個教程的原因是,我可以稍後在我的TCL腳本中使用已提供的SWIG接口和C文件。我擔心它不會在TCL中使用C代碼的其他方式。 – Tom

+0

做'文件test.so'和'nm -AC test.so'並顯示輸出 – vrdhn

回答

1

這些錯誤消息是否阻止load正常工作?他們不應該;他們報告說支持卸載擴展的底層API不存在,但是沒關係(許多擴展不能被卸載;編寫支持它的代碼是很棘手的)。

你並沒有提到你正在使用哪個版本的Tcl - 但它至少要達到8.5,因爲那些符號甚至被首先搜索 - 所以有點難以猜測到底是什麼問題是。 (該消息應該不會被報告。)我建議在此提交bug report; 確保在報告中包含所有確切版本。

0

因爲我使用了SWIG,所以很長一段時間,所以我不確定它是否能夠對您生成的代碼進行充分的控制,以便您能夠應用此修復程序。粉飾這個細節,我可以重現(並修復)問題有以下:

在 'ext.c':

#include <tcl.h> 

int DLLEXPORT Ext_Init(Tcl_Interp *interp) { 


    if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) { 
     return TCL_ERROR; 
    } 
    if (Tcl_PkgProvide(interp, "Ext", "0.0") == TCL_ERROR) { 
     return TCL_ERROR; 
    } 

    return TCL_OK; 
} 

構建,運行tclsh的,負載擴展:

$ gcc -dynamiclib -framework Tcl ext.c -o ext.so 
$ tclsh8.5 
% load ./ext.so 
dlsym(0x400000, Ext_SafeInit): symbol not found 
dlsym(0x400000, Ext_Unload): symbol not found 
dlsym(0x400000, Ext_SafeUnload): symbol not found 

庫加載代碼內部的東西是將該錯誤消息放入解釋器結果中。要停止過堆焊,設置消息或者使得_Init()函數一端或其他的重置結果:

// Set the result to a message of your choosing 
    Tcl_SetObjResult(interp, Tcl_NewStringObj("ok", -1)); 

// Or clear out the result altogether 
    Tcl_ResetResult(interp); 
    return TCL_OK; 
} 

的痛飲威力插入代碼在正確的地方init block功能來實現同樣的事情:

%init %{ 
Tcl_ResetResult(interp); 
%}