TCL與c c 的互相呼叫

2021-06-21 16:37:24 字數 4092 閱讀 9317

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...