It is possible to link a tclkit as a shared library or DLL. This is useful for use in applications that embed Tcl as the shared library contains a virtual filesystem containing the necessary script files. This means that the embedding of Tcl now only requires a single file to be distributed.
Notes on building a stardll are at http://www.patthoyts.tk/tclkit/building-basekits.html
ActiveState refer to tclkit and stardll as basekit and there is such a DLL included with ActiveTcl (base-tcl-thread-win32-ix86.dll on Windows).
TclKit_SetKitPath
The tclkit initialization code expects to mount the executable to access the tclkit virtual filesystem. When you use tclkit as a shared library you must inform the initialization code that it must mount a different file. Therefore the very first call you make must be to TclKit_SetKitPath(const char *path) giving the filename and path of the shared library. Second must be a call to TclKit_AppInit(Tcl_Interp *interp) to initialize the runtime.
Example
An example of an application that embeds tcl using this technique follows.
/* tclembed.c - Copyright (C) 2003 Pat Thoyts <[email protected]> * * Sample of an embedded Tcl application linked using the Tcl stubs mechanism * as seen at https://wiki.tcl-lang.org/2074. * * This version demonstrates linking to the stardll (ActiveTcl calls it a * basekit DLL) which is a TclKit presented as a DLL. * * ---------------------------------------------------------------------- * This source code is public domain. * ---------------------------------------------------------------------- * * $Id$ */ #define STRICT #define WIN32_LEAN_AND_MEAN #include <windows.h> #ifndef USE_TCL_STUBS #define USE_TCL_STUBS #endif #include <tcl.h> static Tcl_Interp *InitializeTcl(const char *dllname,int argc, char *args[]); int main(int argc, char *argv[]) { Tcl_Interp *interp; int r = TCL_OK; interp = InitializeTcl("basekit.dll", argc, argv); if (interp == NULL) { fprintf(stderr, "error: failed to initialize Tcl runtime\n"); } else { if (argc > 1) { r = Tcl_EvalFile(interp, argv[1]); printf(Tcl_GetStringResult(interp)); } Tcl_DeleteInterp(interp); } return r; } typedef Tcl_Interp * (*LPFNCREATEINTERP) (); typedef int (*LPFNBASEKITINIT) (Tcl_Interp *); typedef char * (*LPFNSETKITPATH) (char *); Tcl_Interp * InitializeTcl(const char *dllname, int argc, char *argv[]) { TCHAR szLibrary[MAX_PATH]; HINSTANCE hTcl = NULL; Tcl_Interp *interp = NULL; hTcl = LoadLibraryA(dllname); if (hTcl != NULL) { LPFNCREATEINTERP lpfnCreateInterp = (LPFNCREATEINTERP)GetProcAddress(hTcl, "Tcl_CreateInterp"); LPFNBASEKITINIT lpfnBasekitInit = (LPFNBASEKITINIT)GetProcAddress(hTcl, "TclKit_AppInit"); LPFNSETKITPATH lpfnSetKitPath = (LPFNSETKITPATH)GetProcAddress(hTcl, "TclKit_SetKitPath"); if (lpfnCreateInterp != NULL && lpfnBasekitInit != NULL && lpfnSetKitPath != NULL) { interp = lpfnCreateInterp(); if (interp != NULL) { Tcl_InitStubs(interp, "8.4", 0); Tcl_FindExecutable(argv[0]); GetModuleFileNameA(hTcl, szLibrary, MAX_PATH); lpfnSetKitPath(szLibrary); if (lpfnBasekitInit(interp) == TCL_OK) { Tcl_InitMemory(interp); } else { fprintf(stderr, "TclKit_AppInit: %s\n", Tcl_GetStringResult(interp)); } } } } return interp; }