Version 3 of Experiences with a custom tclsh

Updated 2002-09-10 19:13:32

Arjen Markus (9 september 2002) Being an enthousiastic user of Critcl, I ran into a small problem the other day: I needed to use a set of static (archive) libraries and the UNIX operating system I used (SUN Solaris) did not allow me to use them as part of a dynamic (shared) library.

So, the solution was to create a "custom shell", with the static libraries linked into the shell, instead of them being a loadable extension.

This page describes how I did this.

The first step was to use Critcl with the option "-keepsrc 1" to keep the generated C source file. I renamed the file to "glue.c", this being the (unimaginative) name of the package I wanted.

The second step was editing the file "tclAppInit.c", so that it would initialise my package as a static package:

   int
   Tcl_AppInit(interp)
       Tcl_Interp *interp;         /* Interpreter for application. */
   {
       ...


       /*
        |  Call the init procedures for included packages.  Each call should
        |  look like this:
        | 
        |  if (Mod_Init(interp) == TCL_ERROR) {
        |      return TCL_ERROR;
        |  }
        |
        | where "Mod" is the name of the module.
        */
       if (Glue_Init(interp) == TCL_ERROR) {
          return TCL_ERROR;
       }
       ...
   }

(This required little more than copying and editing the example in the very file.)

With the following commands, I got the custom shell I needed:

   cc -g -c tclAppInit.c -DUSE_TCL_STUBS
   cc -g -c glue.c -DUSE_TCL_STUBS
   f77 -g -o gluesh tclAppInit.o glue.o -L$TCLLIBPATH \
      -ltcl8.3 -ltclstub8.3 libreader1.a libreader2.a -lm

(slightly edited, irrelevant details have been omitted)

Notes:

  • Even though "stubs" are enabled, you still need to link against the Tcl library itself, as the function Tcl_Main() is not contained in the stubs.
  • I use "f77" as the linker, because some of the libraries contain Fortran routines. "f77" takes care of including the Fortran run-time libraries.

Running this custom shell requires, however, two more actions:

  • The environment variable LD_LIBRARY_PATH needs to point to the directory containing the Tcl shared library
  • As the shell is based on "tclAppInit.c", it expects to find a start-up script "init.tcl" somewhere among a list of fixed directories and directories relative to the location of the shell. The easiest (and laziest) way out was to create a soft-link to the installation directory containing Tcl on my system.

For the LD_LIBRARY_PATH point, there is an easier way: Use the linker's rpath directive. rpath means runtime path, and you can specify a colon separated list of directories ld(_elf).so searches for the fitting libraries. E.g. suppose you have your tcl libraries in /usr/somewhere/tcl/lib, you'd change the linking step to include something like:

 -Wl,-R/usr/lib:/lib:/usr/somewhere/tcl/lib

or

 -Wl,-rpath/usr/lib:/lib:/usr/somewhere/tcl/lib

depending on your compiler (-Wl, passes all stuff after the comma to the linker itself - older linkers implement -R, newer implement -rpath in addition to -R.) This is true for gcc (and ld), I have to admit that I have no idea of f77 :) (but if you use g77, it is basically a wrapper around gcc, which allows you to use those -Wl, ... options again)

-Martin

AM On the subject of g77 being a wrapper for gcc, I think many users of g77 would disagree. There is considerable confusion, as some systems offered a script "g77" that invoked the well-known Fortran-to-C converter, f2c. But as far as I understand it, g77 is an independent product that simply happens to share a lot with gcc.


See also: Building a custom tclsh


Category Tutorial