item2
Next»

contents

 

Introduction - 1

History - 2

Overview - 3

Advanced features - 4

Work in progress - 5

One possibility - 6

Conclusion - 7

 

References

Appendix 1 - blowfish

Appendix 2 - tkspline

3.5 - A Tk Package

Building a Tk extension using Critcl is slightly more complex.

Consider the Tkspline package by John Ellson - part of the Graphviz software [9] . Tkspline provides an additional line smoothing method for the Tk canvas widget, and is typically used in conjunction with Tcldot - the graphviz package for drawing directed graphs on a canvas .  As distributed, Tkspline is built as part of the Graphviz build system, which is large and complex.  By extracting Tkspline and building it using Critcl it becomes feasible to move it to platforms not supported by Graphviz (Windows, for example) and makes support much easier.

So, we'll start constructing Tkspline.tcl (the capitalisation was necessary to force the Critcl generated package to have the same name as the original Tkspline package). Here some of the details will be omitted, but the full text of the script is shown in Appendix 2:

   package require critcl
   package provide Tkspline 0.4.1

   critcl::tk

   set tcl_prefix [file normalize ~/src/tcl]  
   set tk_prefix  [file normalize ~/src/tk]  

   critcl::cheaders \
      -I$tk_prefix/generic -I$tk_prefix \
      -I$tcl_prefix/generic -I$tcl_prefix

The critcl::tk procedure tells Critcl to include the Tk stubs table setup in any generated code, plus add tk.h to the list of C headers files.

But Tkspline also requires some of the internal Tcl and Tk header files (tclInt.h and tkInt.h) - so the next lines specify the location of the Tcl and Tk source trees (it would be preferably for Critcl to have a means for these to be specified on the command line, or even default to a location like /usr/local/src/tcl):

   set tcl_prefix [file normalize ~/src/tcl]  
   set tk_prefix  [file normalize ~/src/tk]  

   critcl::cheaders \
      -I$tk_prefix/generic -I$tk_prefix \
      -I$tcl_prefix/generic -I$tcl_prefix

The last three lines add the specified Tcl and Tk directories to the list of directories searched for included header files (note that this is different from the use of critcl::cheaders shown in the earlier examples). Whilst the use of internal Tcl/Tk header files makes the building of Tkspline potentially Tcl/Tk version specific - it is nevertheless much simpler to deal with than the autoconf, makefiles and other complexities of the standard Graphviz build environment.

Also note also that we are now starting to include build information in the Critcl script (more on the build features later). But what about handling platform differences? Fortunately, this is one of the (many) things that Tcl does well ...

   #
   #   platform specific declarations
   #
   switch $tcl_platform(platform) {
     unix {
      switch $tcl_platform(os) {
         Darwin  {
            set xinclude /usr/X11R6/include
            set xlib /usr/X11R6/lib
         }
         default {
            set xinclude /usr/X11R6/lib
            set xlib $xinclude
         }
        }
        critcl::cheaders -I$xinclude
         critcl::clibraries -L$xlib -lX11
      }
      windows {
           critcl::cheaders -DWIN32 \
              -I$tk_prefix/win \
              -I$tk_prefix/xlib
      }
      default {
           puts stderr "tkspline hasn't been \
                     ported to \
                    $tcl_platform(platform)"
           exit 1
      }
   }

The only new Critcl procedure is the critcl::clibraries - this adds the specified commands to the C compiler command line (in this case, ensuring that the X11 runtime library is resolved when building the package shared library).

And finally,  we include the original Tkspline C code,  arranging for the original Tkspline_Init function to be called:

   critcl::ccode {
      #define Tkspline_Init ns_Tkspline_Init
      #include "tkspline.c"
   }

   critcl::cinit {
      Tk_CreateSmoothMethod(ip,
                 &splineSmoothMethod);
   }

The first line in the critcl::ccode invocation is a small trick to make the  Tkspline C code expect the same shared library initialisation routine as that generated by CriTcl.  After that, we just include the Tkspline code unchanged.

The critcl::cinit procedure injects code into the shared library initialisation function - in this case we want to add Tkspline as a canvas smoothing method.

So now, all that is left is compiling in the usual way:

   $ critcl -pkg. Tkspline.tcl     
   Source: Tkspline.tcl
   Library: Tkspline.so
   Package: lib/Tkspline

see also

Critcl Home Page

Tclkit Home Page

Starkit Home Page

Wikit Home Page

Tclers' Wiki

Steve's Website

Jean-Claude's Website

Paper by S. Landers & J.C. Wippler, as presented at Tcl/Tk 2002 conference - see also original PDF.

Papers & Presentations