使用gcc编译时,Tcl解释器未定义引用错误

时间:2014-07-26 16:49:08

标签: c mingw tcl embed

我是Tcl脚本的新手,并希望使用C来嵌入Tcl代码。 这是我从网站上复制的代码,用于测试Tcl-C的工作情况。

test.c的

#include <stdio.h>
#include <tcl.h>
void main ()
{
   Tcl_Interp *myinterp;
   char *action = "set a [expr 5 * 8]; puts $a";
   int status;
   printf ("Your Program will run ... \n");
   myinterp = Tcl_CreateInterp();
   status = Tcl_Eval(myinterp,action);
   printf ("Your Program has completed\n");
   getch();
}

我正在使用MinGW来编译这个文件。

我已将 C:\ Tcl \ include 文件夹的内容复制到 C:\ MinGW \ include 文件夹中。

我的gcc命令用于编译:

gcc -o test.exe test.c

显示错误消息:

C:\Users\user\AppData\Local\Temp\ccEHJKCb.o:tcl_connection_test.c:(.text+0x23): undefined reference to `_imp__Tcl_CreateInterp'
C:\Users\user\AppData\Local\Temp\ccEHJKCb.o:tcl_connection_test.c:(.text+0x3d): undefined reference to `_imp__Tcl_Eval'
c:/mingw/bin/../lib/gcc/mingw32/4.8.1/../../../../mingw32/bin/ld.exe: C:\Users\user\AppData\Local\Temp\ccEHJKCb.o: bad reloc address 0x20 in section `.eh_frame'
c:/mingw/bin/../lib/gcc/mingw32/4.8.1/../../../../mingw32/bin/ld.exe: final link failed: Invalid operation
collect2.exe: error: ld returned 1 exit status

我似乎在Tcl文件夹中没有任何libtcl文件。

Tcl版本是ActiveTcl 8.5.15.0.297577。

任何帮助都会非常感激。

2 个答案:

答案 0 :(得分:1)

您的示例如何嵌入Tcl已过时,并且您在链接行(例如-ltcl85)中缺少某些内容。如果您只是将-ltcl85添加到链接行,它就应该开始工作了。

它不适用于您的情况,因为您安装了ActiveTcl的x64(64位版本),它提供x64 dll而不是32位dll。但标准mingw gcc仅适用于32位库。

所以要让它发挥作用:

  1. 下载32位ActiveTcl发行版
  2. 使用gcc -o test.exe test.c -Lc:/tcl/lib -Ic:/tcl/include -ltcl86
  3. 编译代码
  4. 调整路径以便在PATH中找到c:\ tcl \ bin \ tcl86.dll,同时确保Tcl找到其libdir(set TCL_LIBRARY=c:\tcl\lib\tcl8.6
  5. 运行您的程序
  6. 但是对于更复杂的示例,您仍然需要初始化库并执行一些样板代码,因此请在调用Tcl_FindExecutable(argv[0]);之前调用Tcl_CreateInterp(),否则请调用一些命令(例如clock可能只是没有按预期工作。)

    有关详细信息,请查看http://www.tcl.tk/cgi-bin/tct/tip/66.html。另请参阅Tcl源代码分发和tclsh shell的源代码。

答案 1 :(得分:0)

你非常接近正确。

Tcler的Wiki有一些例子,其中一些非常令人困惑坦率,但这一个from this page是我最近发现的最好的。 (评论是我的。)

#include <stdlib.h>
#include <tcl.h>

int main (int argc, char *argv[]) {
    Tcl_Interp *interp;
    const char *script = "proc p1 a { puts $a }";

    // Initialize the Tcl library; ***STRONGLY RECOMMENDED***
    Tcl_FindExecutable(argv[0]);

    // Create the interpreter, the execution context
    interp = Tcl_CreateInterp();

    // Initialise the interpreter
    if (TCL_OK != Tcl_Init(interp)) {
        fprintf(stderr, "Tcl_Init error: %s\n", Tcl_GetStringResult(interp));
        exit(EXIT_FAILURE);
    }

    // Define a procedure
    Tcl_Eval(interp, script);
    fprintf(stderr, "res 1: %s\n", Tcl_GetStringResult(interp));

    // Check if the procedure exists
    Tcl_Eval(interp, "puts [info commands p*]");
    fprintf(stderr, "res 2: %s\n", Tcl_GetStringResult(interp));

    // Call the procedure
    Tcl_Eval(interp, "p1 abc");
    fprintf(stderr, "res 3: %s\n", Tcl_GetStringResult(interp));

    // We could use Tcl_DeleteInterpreter to clean up here, but why bother?  
    return EXIT_SUCCESS;
}

你还缺少什么?简单。在构建可执行文件时,您忘了告诉C编译器使用Tcl库;编译器(或者更严格地说,链接器)是一段愚蠢的代码。用于使链接器添加库的确切选项取决于您的系统配置,但可能是-ltcl-ltcl8.5-ltcl8.6;这取决于文件名和所有我们无法在您的系统上无法准确检查的事情。这些名称确实符合一个简单的模式。

您可能还需要传递-L选项以告知链接器有关其他库位置的信息。 (有一个等价的-I用于告诉编译器在哪里找到包含文件,因此您不必将所有内容复制到一个巨大的无法管理的目录中。)

论证的顺序很重要。应在源文件后列出库:

gcc -o test.exe test.c -L/mingw/path/to/library/directory -ltcl86

(如果您使用旧的,不受支持的Tcl版本 - 为什么要这样做?! - 那么上面的代码将无效,因为Tcl_Eval然后使用可写字符串但是很多年前这个问题已得到解决,升级到当前版本就是修复。)