Version 10 of Building Tcl DLL's for Windows

Updated 2002-05-02 13:52:56

Using Microsoft Visual C++ 6

  • Create a new win32 dynamic link library project and call it something nice, like tcldemo. This is going to be our package name too.
  • Select an 'Empty DLL' on the next dialog.
  • Before you get going, make sure you have told Visual Studio about the Tcl headers and libraries. To do this, open Tools->Options->Directories and give the Tcl include directory in the includes box and the libraries in the libraries box.
  • Open up the Project settings menu item for your new project and go to the C++ tab. Add USE_TCL_STUBS to the list of defined symbols and in the Link tab prepend tclstub83.lib to the list of libraries. (Adust the numerical suffix for your version of tcl).
  • Now we can write some code. Create a new C++ source file, called tcldemo.cpp and paste in the code below.
  • Build it. Ignore the whining about MSCVRT conflicts. You now have a DLL in either Debug/Release.
  • Fire up tclsh or better tkcon from the Debug or Release subdirectory under your project and issue
  load tcldemo.dll Tcldemo
  set tcldemo_version
  package require Tcldemo
  • You should get 0.1 printed twice!

Using mingw32 GNU C / C++

If you don't happen to have a copy of Microsoft's compiler then you can get a copy of GNU C compiled for the win32 platform. The mingw32 project is the minimal approach which uses only the native libraries and so doesn't support unix porting much - see http://sourceforge.net/projects/mingw for the releases.

  • Create a .cpp or .cc file with the code below using your favourite editor. (eg: emacs)
  • Create a tcldemo.def file with the following lines:
 EXPORTS
 Tcldemo_Init
 Tcldemo_SafeInit
  • Compile the code:
 g++ -Wall -g -Ii:/opt/Tcl/include -c tcldemo.cpp -o tcldemo.o
 dllwrap --driver-name g++ -def tcldemo.def -o tcldemo.dll tcldemo.o -Li:/opt/Tcl/lib -ltcl83 -lm
  • Voila: you now have a tcldemo.dll. Test as above.

I've included a suitable Makefile below.


The code:

 #include <windows.h>
 #include <tcl.h>

 #ifndef DECLSPEC_EXPORT
 #define DECLSPEC_EXPORT __declspec(dllexport)
 #endif // DECLSPEC_EXPORT

 BOOL APIENTRY
 DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
 {
     return TRUE;
 }

 EXTERN_C int DECLSPEC_EXPORT
 Tcldemo_Init(Tcl_Interp* interp)
 {
 #ifdef USE_TCL_STUBS
     Tcl_InitStubs(interp, "8.3", 0);
 #endif
     Tcl_Obj *version = Tcl_SetVar2Ex(interp, "tcldemo_version", NULL,
                                      Tcl_NewDoubleObj(0.1), TCL_LEAVE_ERR_MSG);
     if (version == NULL)
         return TCL_ERROR;
     int r = Tcl_PkgProvide(interp, "Tcldemo", Tcl_GetString(version));

     // Call Tcl_CreateObjCommand etc.

     return r;
 }

 EXTERN_C int DECLSPEC_EXPORT
 Tcldemo_SafeInit(Tcl_Interp* interp)
 {
     // We don't need to be specially safe so...
     return Tcldemo_Init(interp);
 }

 # -*- Makefile -*- for Tcl Demo
 #
 # @(#)$Id: 2419,v 1.11 2002-06-21 04:00:38 jcw Exp $

 CC      =g++
 DLLWRAP =dllwrap
 DLLTOOL =dlltool
 RM      =rm -f
 CFLAGS  =-Wall -Ii:/opt/tcl/include -DUSE_TCL_STUBS
 LDFLAGS =-Li:/opt/tcl/lib
 LIBS    =-ltclstub83

 DLL     =tcldemo.dll
 DEFFILE =tcldemo.def

 WRAPFLAGS =--driver-name $(CC) --def $(DEFFILE)

 CSRCS   =tcldemo.cpp
 OBJS    =$(CSRCS:.cpp=.o)

 $(DLL): $(OBJS)
  $(DLLWRAP) $(WRAPFLAGS) -o [email protected] $^ $(LDFLAGS) $(LIBS)

 clean:
  $(RM) *.o core *~

 %.o: %.cpp
  $(CC) $(CFLAGS) -c $< -o [email protected]

 .PHONY: clean

 #
 # Local variables:
 #   mode: makefile
 # End:
 #

This excellent piece of work was created and put here by Pat Thoyts. Thanks Pat!


Thanks indeed for making things so simple -jcw

The above brings up a question regarding the Tcl core's naming conventions: why is the stub interface lib called "-ltclstub83" and not "-ltclstub8" or even "-ltclstub"?

It might seem inconsequential, but the "83" in the above is the only version dependency w.r.t. Tcl, and given that stubs are intended to maintain backward compatibility, I wonder why we can't just get rid of this and do all extension builders a big favor. On several occasions I had to "fix" extensions when building with the 8.4 core, doing nothing but edit 8.x into 8.4...

One could imagine that the mythical Tcl 9 will break things, so -ltclstub8 seems like a proper choice to me.

(As critcl illustrates, one could dispense with -ltclstub* altogether in fact - but that's a different discussion).


Anyone want to discuss how to buil Tcl code using the UWIN software?

UWIN is software that enables UNIX software to be recompiled and run on WIN32systems such as Windows 95, Windows 98, Windows ME, Windows NT, Windows 2000,and Windows XP http://www.research.att.com/sw/tools/uwin/ mentions Tcl and several extensions built with it.


RS is also very thankful - my first working DLL ;-)! For completeness, how should the source look so it could be compiled both on Windows (making a DLL) and Unix (making a .so shared object)?