Building stardll (aka: basekit) with kitgen

9 April 2008

I decided it was time to work out how to build a stardll using kitgen. A stardll or basekit dll is a shared library version of tclkit. That is it is a single library containing tcl and the necessary vfs code plus a virtual filesystem that contains the script files and dynamically loadable extensions (eg: thread) that are required for a complete installation. This is important for embedded application use where currently an application like python or git needs to carry a tcl tree around. If they instead link to a stardll then that is the only file needed for tcl support. The Tcl browser plugin uses this design to keep all the necessary files bound up in a single file.

Using a stardll/basekit

So how would we use one of these compound shared libraries? To make sure I build it correctly it will help to have a test program. ActiveTcl include what they term a basekit. In my installation I have a file called base-tcl-thread-win32-ix86.dll that is a stardll. There are a couple of things that we must do. Firstly the tclkit virtual filesystem is going to be in the shared library and not in the application executable. So the tclkit startup code cannot mount [info nameofexecutable] as we normally do. Instead there is an exposed API char * TclKit_SetKitPath(const char *) which we must use to set the location of the vfs containing file before we call int TclKit_AppInit(Tcl_Interp *). I've chosen to make the whole thing dynamic and use the tclstubs linking mechanism as well. This is an unusual step for embedding tcl as the stubs mechanism is really for use with Tcl extensions. However it permits us the same kind of version independence that we achive with extensions and we only need to find three functions from the shared library to make it work. By doing it this way I can test using the Tcl 8.4 basekit provided with ActiveTcl and then move on to test my 8.6 basekit using the same executable. The code is tclembed.c

The sample needs compiling with something like
cl -W3 -MD -I/opt/tcl/include -DUSE_TCL_STUBS -o tclembed.exe tclembed.c /opt/tcl/lib/tclstub84.lib
Note that we do not link to tcl84.dll or the basekit -- only to the stubs library. It is going to look for a file called basekit.dll in the current directory (or in fact in any of the usual dll loading locations). If you run this and provide a file with some simple script (eg: puts [info patchlevel]) then it should work fine.

Building the dll

Usually tclkit executables build tcl and various extensions as static libraries and then link the whole thing into an executable with kitInit.c providing the Tcl_AppInit code required to initialize the Tcl runtime. On windows a dll is really the same thing as an executable but linked slightly differently. When we build the tcl dll normally then exported symbols are defined from the sourcecode using the __declspec(dllexport) MSVC extension. Because we are building a static library this isn't defined so we cannot identify the symbols in this manner. I spent a while poking at the makefiles to see if I could get this to work before I decided on a simpler approach. Read the symbols from a dll and generate a .def file and add that to the dll link step. You can read the symbols from a dll using dumpbin /exports with a bit of editing just append this to a text file. Personally I used
echo EXPORTS > basekit.def
echo TclKit_SetKitPath >> basekit.def
echo TclKit_AppInit >> basekit.def
dumpbin /exports tcl86t.dll | awk "NR>19 {print $4}" >> basekit.def

There are a few more symbols that might be useful so in the future we need a makefile target to do the work. This will give us a basekit.def file that is sufficient for the task.

The modified Makefile can now build kit-lite.dll and kitsh.dll targets. These are respectively a stardll that uses vlerq and one that uses Mk4tcl for the vfs access. Copying either of these to basekit.dll in the test folder means we can test out our new basekit with the test app provided earlier.

Viewable with any browser