Writing extensions for stubs and pre-stubs Tcl

David Gravereaux gave this code on news:[comp.lang.tcl ] for writing code which will compile for both stubs-enabled, and pre-stubs (8.0) Tcl, both using the Tcl_Obj interface (so nothing prior to 8.0). Perhaps people can add extras for different compilers/platforms...

8.0 and 8.1+ have a different interface for extensions. Please pardon the overdose of macros, but this works and is very aggressive:

#include <tcl.h>

// We need at least the Tcl_Obj interface that was started in 8.0
#if TCL_MAJOR_VERSION < 8
#   error "we need Tcl 8.0 or greater to build this"

// Check for Stubs compatibility when asked for it.
#elif defined(USE_TCL_STUBS) && TCL_MAJOR_VERSION == 8 && \
       (TCL_MINOR_VERSION == 0 || \
       (TCL_MINOR_VERSION == 1 && TCL_RELEASE_LEVEL != TCL_FINAL_RELEASE))
#   error "Stubs interface doesn't work in 8.0 and alpha/beta 8.1; only 8.1.0+"
#endif


#ifdef _MSC_VER
   // Only do this when MSVC++ is compiling us.
#   ifdef USE_TCL_STUBS
       // Mark this .obj as needing tcl's Stubs library.
#       pragma comment(lib, "tclstub" \
           STRINGIFY(JOIN(TCL_MAJOR_VERSION,TCL_MINOR_VERSION)) ".lib")
#       if !defined(_MT) || !defined(_DLL) || defined(_DEBUG)
           // This fixes a bug with how the Stubs library was compiled.
           // The requirement for msvcrt.lib from tclstubXX.lib should
           // be removed.
#           pragma comment(linker, "-nodefaultlib:msvcrt.lib")
#       endif
#   else
   // Mark this .obj needing the import library
#   pragma comment(lib, "tcl" \
       STRINGIFY(JOIN(TCL_MAJOR_VERSION,TCL_MINOR_VERSION)) ".lib")
#   endif
#endif


#undef TCL_STORAGE_CLASS
#define TCL_STORAGE_CLASS DLLEXPORT

EXTERN int
Livemsg_Init(Tcl_Interp *interp)
{
 int code;

#ifdef USE_TCL_STUBS
   if (Tcl_InitStubs(interp, "8.1", 0) == NULL) {
       return TCL_ERROR;
   }
#endif

 Tcl_CreateObjCommand(interp,"LiveMsg",LiveMsgObjCmd,
  (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);


 code=Tcl_PkgProvide(interp,"LiveMsg","1.0");
 if (code != TCL_OK) {
  return code;
 }

 // init here
 return TCL_OK;
}

See Also