编写Tcl C扩展共享库[链接错误]

时间:2015-12-03 18:14:32

标签: c visual-c++ tcl

我正在按照this指南在C中编写一个简单的Tcl扩展。我已经在文章中提供了源代码,并且我正在使用MSVC的命令行编译器编译(cl.exe )。我的目标是将此源代码转换为共享库(DLL)并允许我的Tcl脚本访问此共享库以使用我实现的Tcl扩展。

我在以下目录中安装了Tcl:

C:\Tcl

以下是源代码:

TclExample.h

#include <tcl.h>

/* <package_name>_Init is called when a package is loaded. In this case,
   since our package is named "Random", we call the function Random_Init()
*/
#ifdef __cplusplus
extern "C" {
#endif

__declspec(dllexport) int Random_Init(Tcl_Interp* interp);
//EXTERN int Random_Init(Tcl_Interp* interp);

__declspec(dllexport) int RandomCmd(ClientData cd, Tcl_Interp* interp, int argc, char* CONST argv[]);
//EXTERN int RandomCmd(ClientData cd, Tcl_Interp* interp, int argc, char* CONST argv[]);

__declspec(dllexport) int RandomObjCmd(ClientData cd, Tcl_Interp* interp, int objc, Tcl_Obj *CONST objv[]);
//EXTERN int RandomObjCmd(ClientData cd, Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]);

#ifdef __cplusplus
}
#endif

TclExample.c

#include "TclExample.h"

/* <package_name>_Init is called when a package is loaded. In this case,
   since our package is named "Random", we call the function Random_Init()
*/
int Random_Init(Tcl_Interp* interp)
{
   /* Initialize the stub table interface */
   if (Tcl_InitStubs(interp, "8.1", 0) == NULL){
        return TCL_ERROR;
   }

   /* Create two varations of the "random" procedure.
      The orandom command uses the object interface
   */
   Tcl_CreateCommand(interp, "random", RandomCmd, NULL, NULL);
   Tcl_CreateObjCommand(interp, "orandom", RandomObjCmd, NULL, NULL);

   /* Declare that we implement the random package so scripts that do "package require random"
      load the library right away
   */
   Tcl_PkgProvide(interp, "random", "1.0");
   return TCL_OK;
}

/* Defined procedures implementation */

int RandomCmd(ClientData cd, Tcl_Interp* interp, int argc, char* CONST argv[])
{
    int rand = 0, error = 0, range = 0;
    if (argc > 2){
        interp->result = "Incorrect number of args. Usage: random ?range?";
        return TCL_ERROR;
    }
    if (argc == 2){
        if (Tcl_GetInt(interp, argv[1], &range) != TCL_OK){
            return TCL_ERROR;
        }
    }

    //rand = random();
    if (range != 0){
        rand %= range;
    }

    sprintf(interp->result, "%d", rand);
    return TCL_OK;
}

int RandomObjCmd(ClientData cd, Tcl_Interp* interp, int objc, Tcl_Obj *CONST objv[])
{
    int rand = 0, error = 0, range = 0;
    if (objc > 2){
        Tcl_WrongNumArgs(interp, 1, objv, "?range?");
        return TCL_ERROR;
    }
    if (objc == 2){
        if (Tcl_GetIntFromObj(interp, objv[1], &range) != TCL_OK){
            return TCL_ERROR;
        }
    }

    //rand = random();
    if (range != 0){
        rand %= range;
    }

    Tcl_Obj* resultPtr = Tcl_GetObjResult(interp);
    Tcl_SetIntObj(resultPtr, rand);
    return TCL_OK;
}

以下是我在MSVC命令行中使用的命令:

cl /I C:\Tcl\include\tcl8.5 /DUSE_TCL_STUBS /DBUILD_tcl /Ox TclExample.c
 /link /DLL /LIBPATH C:\Tcl\lib\tclstub85.lib /LIBPATH C:\Tcl\lib\tkstub85.lib
 /LIBPATH C:\Tcl\lib\ttkstub.lib /OUT:TclExample.dll

如您所见,我已将include路径包含在C:\Tcl\include\tcl8.5中的Tcl标头中,并包含位于C:\Tcl\lib中的存根库。

运行上述命令时出现以下错误:

/out:TclExample.exe
/DLL
/LIBPATH
C:\Tcl\lib\tclstub85.lib
/LIBPATH
C:\Tcl\lib\tkstub85.lib
/LIBPATH
C:\Tcl\lib\ttkstub.lib
/OUT:TclExample.dll
TclExample.obj
   Creating library TclExample.lib and object TclExample.exp
TclExample.obj : error LNK2019: unresolved external symbol _Tcl_InitStubs referenced in function _Random_Init
TclExample.obj : error LNK2019: unresolved external symbol _tclStubsPtr referenced in function _Random_Init
TclExample.dll : fatal error LNK1120: 2 unresolved externals

我尝试过在线挖掘,但是我已经陷入困境了。我查看了Tcl.h标题,我确实看到了那里声明的Tcl_InitStubs函数。此外,我不知道tclStubsPtr错误来自何处,因为我在源代码中没有使用该名称的函数。有谁知道这里的问题是什么?

另外,我现在仅限于使用命令行,所以我需要一个命令行解决方案(如果可能的话)。我还从ActiveTcl发行版获得了我的Tcl文件。

1 个答案:

答案 0 :(得分:0)

我首先看到了相同的链接错误。它只是通过将我的配置从Win32更改为x64来解决。