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.4 - A More Complex Package

Writing packages using a self-contained Tcl script  is one thing, but what about more complex packages with external source files?

As an example, we'll look at making Eric Young's implementation of Blowfish encryption library [7] available as a Tcl package.

Firstly, we put the C source and headers for blowfish into a separate directory blowfish_c:

   $ ls blowfish_c
   bf_cfb64.c bf_enc.c  bf_locl.h
   bf_pi.h   bf_skey.c blowfish.h

Note that these files are unchanged from the original distribution.

Now, we create the blowfish.tcl Critcl script to create Tcl commands that invoke the Blowfish library functionality. We’ll also start to use some of the more advanced Critcl facilities.

Firstly, we need to get the Critcl package, but we’ll also check to see that compiling is supported by Critcl on the current platform:

   package require critcl
   if {![critcl::compiling]} {
     puts stderr "This package cannot \
                    be compiled without  \
                    critcl enabled"
      exit 1
   }

package provide blowfish 0.10

The critcl::compiling procedure returns 1 if  CriTcl is able to find a suitable compiler on the current system. There is a companion procedure critcl::scripting which returns the inverse of  critcl::compiling. Why? Depending on what you are doing it helps make some scripts (maybe even the one above) more readable.

Now we declare the C sources and headers needed when compiling blowfish:

   namespace eval blowfish {

      critcl::cheaders blowfish_c/*.h
      critcl::csources blowfish_c/*.c

      critcl::ccode {
         #include "blowfish.h"
      }

critcl::cheaders lets Critcl know that the specified files will be required when compiling the package, and will need to be copied to the Critcl cache.

critcl::csources specifies files that need to be compiled by Critcl when the package is build.

critcl::ccode is used to inject the specified C code  into the generated C source file. In this case, the code ensures that the blowfish library declarations are included before compiling any C functions.

Finally we create a C function to implement the blowfish Tcl command (this has been abbreviated - for the full listing see  Appendix 1). We do this using the critcl::ccommand procedure, which is similar to critcl::cproc but at a lower level - it ties C code to an objectified Tcl command (via the Tcl_CreateObjCommand function) without any further wrapping:

   namespace blowfish {
      ...
      critcl::ccommand blowfish \
            {dummy ip objc objv} {
           int index, dlen, klen, count = 0;
           unsigned char *data, *key;
           Tcl_Obj *obj;
           ...
           Tcl_SetObjResult(ip, obj);
           return TCL_OK;
      }
   }

And that‚Äôs it!  We just need to compile and test - this time on Linux:

   $ critcl -pkg. blowfish
   Source: blowfish.tcl
   Library: blowfish.so
   Package: lib/blowfish
   $ tclkit
   % lappend auto_path [pwd]/lib
   /usr/local/bin/tclkit/lib/tcl8.4 \
   /usr/local/bin/tclkit/lib \
   /home/steve/blowfish/lib
   % package require blowfish
   0.10
   % set plain "Hello world!"
   % set key "this is a secret"
   % set coded [blowfish::blowfish \
      encode $plain $key]
   % binary scan $coded H* secret
   % puts "coded = $secret"
   coded = 258d3a52bf61df2467bade73
   % puts "clear = [blowfish::blowfish \
      decode $coded $key]"
   clear = Hello world!

We can build on additional platforms, accumulating the contents of the lib directory as we go. This will give us a  lib directory like the following:

   lib
   `-- blowfish
      |-- critcl.tcl
      |-- pkgIndex.tcl
      |-- Darwin-ppc
      |   |-- blowfish.dylib
      |   `-- critcl.tcl
      |-- Linux-x86
      |   |-- blowfish.so
      |   `-- critcl.tcl
      `-- Solaris-sparc
           |-- blowfish.so
           `-- critcl.tcl

Note that there are other tools that allow you to build interfaces between Tcl and external libraries, in particular, the SWIG - Simplified Wrapper and Interface Generator [8].

SWIG provides a greater level of automation than Critcl. When using SWIG the developer prepares a small interface file that specifies what functions are to be wrapped. This is used by SWIG to generate the “glue” between an external library and Tcl - the equivalent of the critcl::ccommand is generated for you. On the other hand Critcl is significantly easier to deploy, and generates a package structure ready to use.

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