在C程序中使用tcl和tk存根

我需要一个简单的C程序,它创建tcl解释器,初始化tcl和tk,然后加载给定的tcl / tk脚本。 我想使用tcl和tk存根(以确保程序将在具有不同版本的tcl / tk的计算机上运行)。 我将使用此程序而不是运行wish(因为我有可移植性问题)。

#include  #include  #include  #include  int AppInit(Tcl_Interp *interp) { if(Tcl_Init(interp) == TCL_ERROR) return TCL_ERROR; if(Tk_Init(interp) == TCL_ERROR) return TCL_ERROR; Tcl_EvalFile(interp,"myscript.tcl"); return TCL_OK; } int main(int argc, char *argv[]) { Tk_Main(argc, argv, AppInit); return 0; } 

我尝试使用以下命令编译(在GNU / Linux上)。 程序编译没有错误,但随后停止分段错误。

 gcc -I/usr/include/tcl8.5 -DUSE_TCL_STUBS -DUSE_TK_STUBS -o main.exe ../main.c /usr/lib/libtclstub.a /usr/lib/libtkstub.a 

TL;博士

使用main编译程序时, 不应使用存根。 相反,没有USE_TCL_STUBSUSE_TK_STUBS定义并链接到libtcl.solibtk.so (好吧,无论附加到它们的版本号是什么)。 由于Unix链接器的特殊性,你应该将Tk库放在Tcl库之前(你可能还需要手动链接其他库,例如X库;链接有时候是一种黑色艺术)。

背景说明

存根机制旨在允许Tcl扩展库使用Tcl(和Tk)的C API,而不必与Tcl库本身链接。 这意味着该库与加载它的过程中存在的确切版本的Tcl无关,而只是依赖于特定版本的Tcl API(Tcl非常擅长管理长期API和ABI兼容性)。 但是,这一切都取决于使用非常特殊的指针调用库初始化函数,该指针允许查找所有其他API函数。 (一旦Tcl以这种方式被引导,就可以更容易地找到所有其他API。)在创建像你正在做的应用程序时,你会遇到一个问题,因为你的代码没有现有的自举Tcl库实例来链接; 它必须直接链接(实际上,由于这个原因, Tcl_MainTk_Main都是非存根函数)。

那些在家里阅读的人可能会认为这是Tcl重复系统动态链接器所做的很多事情。 你是对的。 然而,系统动态链接器有许多方法可以做一些不能正常工作的事情(例如,当有多个版本的库时它会变得非常混乱)并且它在平台之间的能力上有微妙的变化。 Tcl使用自己的机制,因为这使得它在任何地方都能正确地工作(对于Tcl),使我们能够更好地控制长期的ABI兼容性。

关于存根的上述规则有一个例外,那就是tclkit ,它是一个完整的Tcl和Tk运行时(加上一个小的NoSQL DB)在一个文件中。 但是,tclkit的引导代码非常复杂; 你不想要处理那种你没有的东西! 如果你想要一个单文件Tcl运行时,你可以使用tclkit(或其他几个做同样事情的系统之一)。