我编译的TCL库(Tcl8.6.7,win7)没有导出tclOODecls.h中的函数。我通过在自动生成的部分之前将t if
放在tclOODecls.h中来导出函数。
我想知道默认情况下导出函数的原因以及启用导出的首选方法。
答案 0 :(得分:1)
已将符号定义为使用MODULE_SCOPE。请参阅前面提到过的问题3010352。我们的想法是,如果您想使用这些符号,您应该使用Tcl存根链接机制并定义USE_TCLOO_STUBS宏并链接到存根库(tclstub86)。函数在那里 - 只是没有导出DLL导出。
来自tcl.h:
/*
* Include platform specific public function declarations that are accessible
* via the stubs table. Make all TclOO symbols MODULE_SCOPE (which only
* has effect on building it as a shared library). See ticket [3010352].
*/
以下代码将构建一个可执行文件,其作用类似于标准Tcl shell,但包含一个额外的命令,可以作为演示访问TclOO API。
/* Demonstrate embedding Tcl and using the TclOO API.
*
* Build with MSVC (adjust paths for local setup):
*
* cl -nologo -W3 -MT -Zi -GL -DSTATIC_BUILD -Ic:\opt\tcl\include test_embed_oo.c \
* -Fe:test_embed_oo.exe -link -debug -subsystem:console -ltcg -libpath:C:\src\tcl\kitgen\8.6\tcl\win\Release_VC13 \
* tcl86ts.lib user32.lib ws2_32.lib netapi32.lib
*
* Requires a static libary if Tcl (tcl86ts.lib on windows)
*/
#include <tcl.h>
#include <tclOO.h>
#include <locale.h>
static int
GetObjectNameCmd(ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *const objv[])
{
int r = TCL_ERROR;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "object");
return r;
}
Tcl_Object object = Tcl_GetObjectFromObj(interp, objv[1]);
if (object != NULL) {
Tcl_Obj *resultObj = Tcl_GetObjectName(interp, object);
if (resultObj != NULL) {
Tcl_SetObjResult(interp, resultObj);
r = TCL_OK;
}
}
return r;
}
#define TCL_LOCAL_APPINIT Custom_AppInit
int
Custom_AppInit(Tcl_Interp *interp)
{
Tcl_CreateObjCommand(interp, "getobjectname", GetObjectNameCmd, NULL, NULL);
return Tcl_Eval(interp, "source test_embed_oo.tcl");
}
#include "c:/src/tcl/kitgen/8.6/tcl/win/tclAppInit.c"
可以使用Tcl存根链接机制动态地将Tcl链接到应用程序。这需要从DLL加载两个函数,然后初始化存根表。以下显示启用了TclOO访问权限。
/* Demonstrate embedding Tcl and using the TclOO API via stubs
*
* Build with MSVC (adjust paths for local setup):
*
* cl -nologo -W3 -MD -Zi -GL -Ic:\opt\tcl\include test_embed_oo_ex.c \
* -Fe:test_embed_oo_ex.exe -link -debug -ltcg -subsystem:console \
* -libpath:C:\opt\tcl\lib tclstub86.lib user32.lib
*
* Dynamically loads Tcl and then uses stubs for API access.
*/
#define WIN32_LEAN_AND_MEAN
#define STRICT
#include <windows.h>
#include <locale.h>
#define USE_TCL_STUBS
#define USE_TCLOO_STUBS
#include <tcl.h>
#include <tclOO.h>
static int
GetObjectNameCmd(ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *const objv[])
{
int r = TCL_ERROR;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "object");
return r;
}
Tcl_Object object = Tcl_GetObjectFromObj(interp, objv[1]);
if (object != NULL) {
Tcl_Obj *resultObj = Tcl_GetObjectName(interp, object);
if (resultObj != NULL) {
Tcl_SetObjResult(interp, resultObj);
r = TCL_OK;
}
}
return r;
}
typedef Tcl_Interp *(*LPFNTCLCREATEINTERP)();
typedef void *(*LPFNTCLFINDEXECUTABLE)(const char *);
static Tcl_Interp *
InitializeTcl(int argc, char *argv[])
{
Tcl_Interp *interp = NULL;
//Tcl_DString dString;
char szLibrary[16];
int nMinor;
HINSTANCE hTcl = NULL;
for (nMinor = 6; hTcl == NULL && nMinor > 4; nMinor--) {
wsprintfA(szLibrary, "tcl8%d.dll", nMinor);
hTcl = LoadLibraryA(szLibrary);
}
if (hTcl != NULL) {
LPFNTCLCREATEINTERP lpfnTcl_CreateInterp;
LPFNTCLFINDEXECUTABLE lpfnTcl_FindExecutable;
lpfnTcl_CreateInterp = (LPFNTCLCREATEINTERP)
GetProcAddress(hTcl, "Tcl_CreateInterp");
lpfnTcl_FindExecutable = (LPFNTCLFINDEXECUTABLE)
GetProcAddress(hTcl, "Tcl_FindExecutable");
if (lpfnTcl_CreateInterp != NULL) {
interp = lpfnTcl_CreateInterp();
if (interp != NULL) {
Tcl_InitStubs(interp, "8.6", 0);
#ifdef USE_TCLOO_STUBS
Tcl_OOInitStubs(interp);
#endif
lpfnTcl_FindExecutable(argv[0]);
Tcl_InitMemory(interp);
Tcl_Init(interp);
}
}
}
return interp;
}
/*
* Embed tcl interpreter into a C program.
*/
int
main(int argc, char *argv[])
{
Tcl_Interp *interp = NULL;
int r = TCL_ERROR;
setlocale(LC_ALL, "C");
interp = InitializeTcl(argc, argv);
if (interp == NULL) {
fprintf(stderr, "error: failed to initialize Tcl runtime\n");
} else {
Tcl_CreateObjCommand(interp, "getobjectname", GetObjectNameCmd, NULL, NULL);
if (argc > 1) {
r = Tcl_EvalFile(interp, argv[1]);
printf(Tcl_GetStringResult(interp));
}
Tcl_DeleteInterp(interp);
}
return r;
}
要对此进行测试,您需要一个包含一些tcl代码的文件,这些代码可以调用getobjectname
并以此文件的路径作为唯一参数运行可执行文件。