我有一个库,最初是作为可加载的Tcl扩展而构建的。我现在正尝试将它用于稍微不同的目的(带有libtecla的交互式shell用于制表符完成和历史记录),目前我无法使Tcl_StaticPackage()
和load {} $lib
组合起作用。奇怪的是,虽然不起作用,但它也不会产生错误。
我已将演示问题所需的代码减少到:
的main.cpp
#include <stdio.h>
#include <tcl.h>
extern "C" {
int Demolib_Init(Tcl_Interp *);
int Demolib_SafeInit(Tcl_Interp *);
}
int main(int argc, char *argv[])
{
Tcl_Interp *interp;
interp = Tcl_CreateInterp();
if (!interp)
{
perror("Couldn't create interpreter");
return 1;
}
if (TCL_OK != Tcl_Init(interp))
{
perror("Couldn't initialize Tcl");
return 2;
}
Tcl_StaticPackage(interp, "Demolib", Demolib_Init, Demolib_SafeInit);
printf("Via 'load'...\n");
if (TCL_OK != Tcl_Eval(interp, "load {} Demolib"))
{
fprintf(stderr, "Err : %s\n", Tcl_GetStringResult(interp));
}
else
{
printf("Ok : %s\n", Tcl_GetStringResult(interp));
}
printf("\nVia 'Demolib_Init()'...\n");
Demolib_Init(interp);
return 0;
}
demolib.cpp
#include <tcl.h>
#include <stdio.h>
#include "demolib.h"
#ifdef __cplusplus
extern "C" {
#endif
int DLLEXPORT Demolib_Init(Tcl_Interp *interp)
{
printf("Pre-stubs\n");
#ifdef USE_TCL_STUBS
if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL)
{
return TCL_ERROR;
}
#endif
printf("Pre-provide\n");
if (Tcl_PkgProvide(interp, "Demolib", "0.0") == TCL_ERROR)
{
return TCL_ERROR;
}
printf("Pre-return\n");
return TCL_OK;
}
int DLLEXPORT Demolib_SafeInit(Tcl_Interp *interp)
{
return Demolib_Init(interp);
}
#ifdef __cplusplus
}
#endif
(虽然演示不需要是.cpp,真正的代码确实如此)
如果以下"Demolib"
与load {} ...
中的库名称不匹配,则会引发错误,因此Tcl_StaticPackage()
具有load
可以看到的效果。
Tcl_StaticPackage(interp, "Demolib", Demolib_Init, Demolib_SafeInit);
...
if (TCL_OK != Tcl_Eval(interp, "load {} Demolib"))
但是,Demolib_Init()
或Demolib_SafeInit()
都没有被调用过。我可以直接调用它,它可以说是更整洁(没有Tcl_Eval(...)
调用),但我想了解发生了什么(没有)。在最终的应用程序中,load {} ...
的时间将由脚本确定,因此需要此功能。
请注意,我故意不调用Tcl_Main()
或进入Tcl事件循环 - libtecla最终将提供提示。
我错过了什么?
答案 0 :(得分:2)
使用MSVC 2013和Tcl 8.6在Windows上使用提供的两个文件尝试此操作:
C:\src\Files\DemoTcl>cl -nologo -I/opt/tcl/include -D_DEBUG -Od -Zi -MDd -c main.cpp
main.cpp
C:\src\Files\DemoTcl>cl -nologo -I/opt/tcl/include -D_DEBUG -Od -Zi -MDd -c demolib.cpp
demolib.cpp
C:\src\Files\DemoTcl>link -nologo -subsystem:console main.obj demolib.obj \opt\tcl\lib\tcl86.lib
Creating library main.lib and object main.exp
C:\src\Files\DemoTcl>main.exe
Via 'load'...
Ok :
Via 'Demolib_Init()'...
Pre-stubs
Pre-provide
Pre-return
如果我们将Tcl_StaticPackage调用更改为以下内容:
Tcl_StaticPackage(NULL, "Demolib", Demolib_Init, Demolib_SafeInit);
然后新的可执行输出是:
Via 'load'...
Pre-stubs
Pre-provide
Pre-return
Ok :
Via 'Demolib_Init()'...
Pre-stubs
Pre-provide
Pre-return
我认为您应该尽早添加Tcl_FindExecutable(argv[0]);
,尽管这并不会影响所提出的问题。
Tcl_StaticPackage的文档巧妙地指出interp参数指向一个解释器,如果它不是NULL,那么它已经被加载了。