'''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. ''(Note: Creating an MFC DLL project may cause problems, as the MFC framework infrastructure can conflict with the declarations in example code. You'll know you've got a _declspec() problem if you get unresolved symbols like __imp_TclCreateObjCommand() -RWT)'' * 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 * Link the code. If you are using a standard distribution such as ActiveTcl then see [How to create mingw32 libraries from DLLs]: 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. [[ ''Q:'' isn't it possible to do this without a .def file? I thought the __declspec(dllexport) was supposed to make it unnecessary ]] ---- Dana Robinson: You can use either. You can even have some functions declared as __declspec(dllexport) and other ones specified in a .def file and it'll all work out. Personally, I like to use .def files with platform-independent code. They aren't that hard to maintain and you don't have to mess up your pretty ANSI C/C++ code with a bunch of #ifdefs and MS-specific code. ---- '''The code:''' #include #include #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.31 2004-12-16 07:00:13 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 $@ $^ $(LDFLAGS) $(LIBS) clean: $(RM) *.o core *~ %.o: %.cpp $(CC) $(CFLAGS) -c $< -o $@ .PHONY: clean # # Local variables: # mode: makefile # End: # ---- This excellent piece of work was created and put here by [Pat Thoyts]. Thanks Pat! ---- Paul Kienzle: With recent versions of mingw you can dispense with .def files, DECLSPEC_EXPORT, #include , DllMain, and dllwrap, and just use: g++ -Wall -g -Ii:/opt/Tcl/include -DUSE_TCL_STUBS -c tcldemo.cpp -o tcldemo.o g++ -shared -o tcldemo.dll tcldemo.o -Li:/opt/Tcl/lib -ltclstub83 After correcting the paths in my Makefile, my tcl extension from unix built and worked fine with ActiveState's binary distribution for windows. ---- I was unable to produce functional DLL with Paul Kienzles advice, but found another easy way to compile shared library with MinGW for MinGW-compiled Tcl: gcc -I C:\Tcl\include -s -shared -o test.dll test.c C:\Tcl\bin\tcl84.dll Apparently newer versions of gcc can extract all required names from the DLL by itself, without using libtclXX.a or libtclstubXX.a. --[mjk] ( g++.exe can do that, too. But then use a extern "C" block for init and wrapper functions. You can then still call your other C++ functions and create objects, use new and delete etc. and pass the result back to the wrapper function in the extern "C" block. [Samuel_J] ) ---- See also '''[Building Extensions on Windows]'''. ---- Question: Once you have built the extensions, where should they be installed, and what gets installed? ---- [Category Porting]