tcl是乙個解釋型的語言,但是功能相當強大,乙個重要原因就在於它的擴充套件性,現有的諸如http,socket,xml,oratcl等等,使得tcl可以輕鬆處理字串、檔案、通訊以及資料庫等等多方面的工作,甚至支援多執行緒。
tcl的擴充套件可以通過呼叫tcl library來完成,具體的開發語言可能有多種,本文第一部分將以c/c++為例討論。
此外,緣於客戶化的需要,也有可能在c/c++**中呼叫tcl的咚咚,例如執行指令碼啊,配置檔案什麼的,具體可見第二部分。
一.tcl中呼叫c/c++
主要是利用c/c++處理複雜邏輯的能力,對於tcl來說,實際上就是乙個擴充套件,因為你可以通過tcl_createcommand函式,建立出乙個新的tcl命令。
具體操作方法需要分情況:
1.如果當前tcl版本支援load命令
語法:load libpackage.so
意義:在tcl中,當乙個動態庫libpackage.so被裝載時,tcl會呼叫其中名為package_init的函式,記住,名字一定不能錯,包括大小寫。這樣,你就獲得了乙個入口,可以進入c/c++啦,你可以幹任何事,當然,最重要的還是tcl_createcommand了。
函式原型:tcl_command tcl_createcommand(interp, cmdname, proc, clientdata, deleteproc)
意義:建立乙個新的tcl命令cmdname,對應的操作函式指標為proc。
這裡以乙個階乘演算法為例:目的是提供乙個名為myfract的tcl命令,只接收乙個引數,例如:
myfract 10
表示計算10的階乘。
【fract.c】:
#include "tcl.h"
int tcl_myfract(clientdata notused, tcl_interp *interp, int argc, char **argv)
if (tcl_getint(interp, argv[1], &i) != tcl_ok)
for (j=1;j<=i;j++)
res *= j;
sprintf(re,"%le",res);
tcl_setresult(interp, re, tcl_volatile);
return tcl_ok; }
int fract_init(tcl_interp *interp)
【makefile】:
t = libfract.so
all: $t
clean:
rm -f $t core
libfract.so: fract.c
gcc -i. -shared -o $@ fract.c
【test.tcl】:
#!/usr/bin/tclsh
load ./libfract.so
set tcl_flag
[catch return_str]
if else
執行:linux:~/test/tcl # ./test.tcl
2.000000e+00
【小結】:這裡有兩點需要注意,第一,fract_init是由tcl到c/c++的入口,而tcl_createcommand則是由c/c++到tcl的入口;第二,編譯動態庫時不必鏈結tcl的開發庫,因為這裡僅僅需要引用。
還有swig可以使用
【fract.i】:
%module fract
extern double myfract(int);
swig的語法這裡就不詳述了,具體可參見
www.swig.org。
第一行表示模組名稱叫做fract,對應前面的c/c++**,就是說要建立的動態庫叫做libfract.so;
第二行表示將要匯出的函式,這個函式是需要你自己定義的。
【fract.c】:
double myfract(int n)
return(res); }
【makefile】:
t = fract_wrap.c libfract.so
all: $t
clean:
rm -f $t core *.doc *.o
fract_wrap.c: fract.i
swig -tcl fract.i
libfract.so:fract_wrap.c
gcc -c fract.c fract_wrap.c
執行:linux:~/test/tcl/swig # ./test.tcl
2.02.如果當前tcl版本不支援load命令
【main.c】:
int main(int argc, char *argv)
/* initialize tcl */
if (tcl_init(interp) == tcl_error)
/* initialize our extension */
if (fract_init(interp) == tcl_error)
return tcl_ok; }
【makefile】:
t = main
tcl_libs = -l/usr/lib -ltcl8.4
all: $t
clean:
rm -f $t core
main:main.c fract.c
gcc -i. $ -o $@ main.c fract.c
執行:linux:~/test/tcl # ./main
% myfract 8
4.032000e+04
% exit
linux:~/test/tcl # ldd main
linux-gate.so.1 =>
(0xffffe000)
libtcl8.4.so => /usr/lib/libtcl8.4.so (0x40030000)
libc.so.6 => /lib/tls/libc.so.6 (0x400d8000)
libdl.so.2 => /lib/libdl.so.2 (0x401f1000)
libm.so.6 => /lib/tls/libm.so.6 (0x401f5000)
/lib/ld-linux.so.2 (0x40000000)
因為最後會建立乙個類似tclsh的執行檔案,所以,tcl開發庫必須鏈結上。
二.c/c++中呼叫tcl
之所以會有這樣的做法,主要是想利用tcl的客戶化能力。
例如把流程寫在tcl指令碼中,c/c++**中僅僅執行tcl_evalfile就可以了,對於不同的服務,我們可以借助某種手段,繫結乙個流程指令碼,這樣,當增加新的服務時或者服務流程需要變更時,不必修改原始碼,只要增加或修改配置檔案/指令碼檔案即可,這也就實現了我們所說的客戶化。
我們只討論幾個常用的函式:
tcl_createinterp
- 建立乙個tcl直譯器
tcl_eval
- 執行乙個tcl命令
tcl_vareval
- 類似tcl_eval,只不過這個命令是被引數串起來的
tcl_evalfile
- 執行乙個tcl指令碼
tcl_setvar
- 設定tcl變數
tcl_getvar
- 獲取tcl變數的值
下面是乙個用法測試:
【test.c】:
#include
#include
#include
#include
int main()
【makefile】:
t = test
tcl_libs = -l/usr/lib -ltcl8.4
all: $t
clean:
rm -f $t core
test: test.c
gcc -i. $ -o $@ test.c
linux:~/test/tcl/test # ./test ok
三.後記
在實踐中,以上二者往往是聯絡在一起的,例如c/c++中呼叫的tcl指令碼,也可以執行擴充套件命令(該命令完全可能是用c/c++**實現的)。沒有必要刻意去區分它們,正確的時候做正確的事,這就是原則。
四.參考
python與C 的互相呼叫
python與c 的互相呼叫 一 c 呼叫python 新建乙個專案,新增引用 ironpython.dll,microsoft.scripting.dll 在ironpython的安裝目錄中 建立乙個文字檔案命名為hello.py,把該檔案新增的當前的專案中,並設定為總是輸出。hello.py d...
python與c 的互相呼叫
這個很簡單 標頭檔案,引用的方式是 ifdef debug undef debug include define debug else include endif 因為不這樣的話會報python38 d.lib缺少的錯誤。網上沒有什麼好的辦法。1,修改配置檔案 2,自己重新編譯python,我這邊稍...
go與c互相呼叫
此例子來自於go原始碼中,藉此來和大家分享一下兩者如何呼叫,網上很多文章語言不詳,也沒有乙個完整的測試例子 首先src 目錄下有 testcgowin目錄下 這裡的 obj目錄是cgo生成的 這裡需要展示的是go中如何呼叫c語言匯出函式,以及在c語言中如何呼叫go的匯出函式.關鍵是cthread.g...