Updated 2012-09-12 19:43:07 by dkf

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).


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. Therefor 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.


An example of an application that embeds tcl using this technique follows.
 /* tclembed.c - Copyright (C) 2003 Pat Thoyts <patthoyts@users.sourceforge.net>
  * Sample of an embedded Tcl application linked using the Tcl stubs mechanism
  * as seen at http://wiki.tcl.tk/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
 #include <tcl.h>
 static Tcl_Interp *InitializeTcl(const char *dllname,int argc, char *args[]);
 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]);
     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];
     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);
                 GetModuleFileNameA(hTcl, szLibrary, MAX_PATH);
                 if (lpfnBasekitInit(interp) == TCL_OK) {
                 } else {
                     fprintf(stderr, "TclKit_AppInit: %s\n",
     return interp;