Tcl 作为一种脚本语言,有其优点,因而在C/C++程序中加入执行Tcl脚本的能力,可以提供脚本。
Tcl 作为一种脚本语言,终有其局限性。比如速度和某些功能。在Tcl中调用 C/C++ 使得 Tcl 可以扩展。
Tcl/Tk 和 C/C++ 的关系可以概括为三种情况:
由于Tcl语言是解释器执行语言,可以想象问题的关键是两部分:
具体实现可以参考 Tcl解释器(Tcl Interpreter)的创建和管理
这个常用于扩展包。
在Tcl中读入编译好的C/C++程序模块(.so 文件或者.dll文件)。
load filename.so pkgName # Tcl解释器将会调用C/C++ 模块种特定的函数(Pkgname_Init/Pkgname_SafeInit) 作为程序入口。 # 该入口函数通常用来添加Tcl命令。 # 默认是读入当前的解释器。也可以指定解释器如下 load filename.so pkgName interp
/************************************************ * 以下两者之一是函数原型 * 后者用于safe intepreter *************************************************/ int Pkgname_Init(Tcl_Interp *interp); int Pkgname_SafeInit(Tcl_Interp *interp); //e.g. int Pkgname_Init(Tcl_Interp *interp){ return TCL_OK; }
这种程序的好处是,在拥有C的强大计算能力的同时,提供给用户一个交互式界面。
如果加上Tk,还可以实现GUI。这样的程序有时也被称作 //bigwish//
#include <tk.h> #include <tcl.h> #include <iostream> typedef int Tcl_AppInitProc(Tcl_Interp *interp); int appInitProc(Tcl_Interp *interp){ std::cout << "App Init" << std::endl; Tcl_Init(interp); Tk_Init(interp); Tk_Window topwin = Tk_MainWindow(interp); Tk_SetAppName(topwin,"NOYESNO"); Tcl_Eval(interp,"wm title . NOYESNO"); //Tcl_EvalFile(interp,"debug.tcl"); return 0; } int main(int argc, char** argv){ Tk_Main(argc, argv, appInitProc); //Tk_MainLoop(); return 0; }
实际应用中常主要的问题是初始化。包括下面几项任务
方法一:
const char *argv0 = Tcl_GetNameOfExecutable(); char exec_dir[255]; strcpy(exec_dir,argv0); char *pos = strrchr(exec_dir,'/'); *pos = '\0'; char buf[255]; sprintf(buf,"TCL_LIBRARY=%s/lib/tcl8.5",exec_dir); putenv(buf);
方法二:
const char *argv0 = Tcl_GetNameOfExecutable(); const char *tcl_init = "set t [file dirname [info nameofexecutable]] \n" "set env(TCL_LIBRARY) [file join $t lib tcl8.5] \n" "set env(TK_LIBRARY) [file join $t lib tk8.5] \n" "unset t" ; if (Tcl_Eval(interp,tcl_init) != TCL_OK){ return TCL_ERROR; }
应该说还是第一种方法作为C/C++程序来说更纯粹些。
Tcl_SetSystemEncoding(interp,"utf-8"); Tcl_SetDefaultEncodingDir("/some/path/lib/tcl8.5/encoding");
const char *nyno_init_file = "noyesno.tcl"; if(access(nyno_init_file,R_OK) == 0){ Tcl_EvalFile(interp,nyno_init_file); }