如何静态链接最初打算用作Tcl扩展的库?

如何静态链接最初打算用作Tcl扩展的库?,tcl,Tcl,我有一个库,最初是作为可加载的Tcl扩展构建的。我现在尝试将它用于一个稍微不同的用途(一个带有libtecla的交互式shell,用于制表符完成和历史记录),但目前无法使Tcl_StaticPackage()和load{}$lib组合起作用。奇怪的是,虽然不工作,但它也不会产生错误 我已将演示问题所需的代码缩减为: main.cpp #include <stdio.h> #include <tcl.h> extern "C" { int Demolib_Init

我有一个库,最初是作为可加载的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;
}
#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
但是,无论是
Demolib\u Init()
还是
Demolib\u SafeInit()
都不会被调用。我可以直接调用它,可以说它更整洁(没有
Tcl_Eval(…)
call),但我想了解(没有)发生了什么。在最后一个应用程序中,
加载{}…
的时间将由脚本确定,因此需要此功能

请注意,我故意不调用
Tcl_Main()
或进入Tcl事件循环-libtecla最终将提供提示


我错过了什么?

在Windows上使用MSVC 2013和Tcl 8.6尝试使用提供的两个文件:

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,则该解释器中的包已经加载。

我认为这与它的构建和链接方式有关,但这是一个我不太了解的领域。真遗憾——我自信地期待着你通常的全面解释。我没有明确说明的是,虽然文件解决方案最好是静态链接到库,但在这种简化的情况下,我只是将两个.o链接到一个可执行文件中。上面的注释应该是“…而最终解决方案…”嗯-似乎应该在“通过‘加载’”之后立即打印出Pre-provide等等。所以not ok then.ok-您需要在Tcl\u StaticPackage调用中使用NULL。请参见编辑。非常好,帕特,谢谢。在这个案例中,我对文档的阅读似乎减少到了略微不充分的“Tcl_Interp*-我有一个这样的文档!”现在这很微妙+1.
Via 'load'...
Pre-stubs
Pre-provide
Pre-return
Ok  :

Via 'Demolib_Init()'...
Pre-stubs
Pre-provide
Pre-return