Ok so you want to embed a scripting language in your application. For some strange reason, you do not want to use Lua. So, you figure out Tcl is the way to go, but sadly the online documentation is full of holy wars and pretty hard to read overall. Here’s some directions to get you started on Windows 7 using Microsoft Visual Studio 2010.
First you need to fetch the source files, in this case the latest stable version is tcl861-src.zip
. Extract the zip contents to a neat place, because we will instruct MSVC to load some libraries from there later on.
Fire up Visual Studio 2010, and open the command prompt (Tools > Visual Studio Command Prompt). Navigate to the tcl\win
directory you extracted earlier. Now you can build Tcl with nmake
.
For example, to build the debug DLL (tcl86g.dll
) with no threading support type
c:\cdev\sdk\tcl\win>nmake -f makefile.vc core MACHINE=IX86 OPTS=msvcrt,nothreads,symbols
See makefile.vc
for configuration options.
From the project properties under the VC++ Directories-section add the Tcl build directory to your library paths. In my case I added tcl\win\Debug_VC10
to the list. Note that the library path will be different in Debug and Release builds.
After that add tcl\generic
to your Include Directories so you can include tcl.h
in your source files.
In order for the compiler to automatically use your new compiled DLL you need to link against tcl86g.lib
. Add tcl86g.lib
(or just tcl86.dll
in Release-mode) to Linker > Input > Additional Dependencies
When running the executable you of course need to have the tcl86g.dll
in the same place with the executable. During the development phase it’s enough to drop the dll to the project directory though.
You can try your project with the following code adapted from StackOverflow
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <tcl.h>
int main(int argc, char**argv)
{
printf("Running script...\n");
Tcl_Interp *interp;
int code;
char *result;
Tcl_FindExecutable(argv[0]);
interp = Tcl_CreateInterp();
code = Tcl_Eval(interp, "source myscript.tcl; init");
/* Retrieve the result... */
result = Tcl_GetString(Tcl_GetObjResult(interp));
/* Check for error! If an error, message is result. */
if (code == TCL_ERROR) {
fprintf(stderr, "ERROR in script: %s\n", result);
exit(1);
}
/* Print (normal) result if non-empty; we'll skip handling encodings for now */
if (strlen(result)) {
printf("%s\n", result);
}
/* Clean up */
Tcl_DeleteInterp(interp);
exit(0);
}
The code calls init
-proc defined in myscript.tcl