How to make a Tcl application - part four

Arjen Markus (6 january 2004) This is the fourth part of the tutorial How to make a Tcl application


7. Delivering your application

Let us return now to the first example, that of finding files. We want to make this available as a tool for our clients (or colleagues, friends, anybody). How do we do that? That, unfortunately, is not that easily done:

  • Does the target computer system already have (the right version of) Tcl/Tk installed? Or can we do that ourselves? (Or some system administrator?)
  • Do we want the source code to be available to our client?
  • How is the client going to use it? Does he/she want to use it as if it were a simple command or does he/she want to use it via the desktop (in the Start menu for instance)?

7.1 Installation on UNIX/Linux

First we go for the easy situation: our client has Tcl/Tk installed and he/she knows enough about programming to be able to put the application in some directory and make sure that directory is in the path.

Now on a UNIX/Linux system we can use a little trick to make the Tcl script behave as any ordinary shell script:

  • Make the main script file executable (chmod +x ...)
  • Add the following lines to the top of the script:
#!/bin/sh
# \
exec tclsh "$0" ${1+"$@"}

(Note: remove the leading space from at least the first line!)

What does this do? Well the first line is shell script magic: the "#!" is a magic sequence that instructs any UNIX/Linux shell program to load the program named after that and let that handle the file. So, in this case, the Bourne shell is started and that starts interpreting our Tcl file ...

The third line in our file now causes the Bourne shell to hand over execution to a Tcl shell (tclsh or wish, whichever you need) passing on all the arguments that were given in the first place, including the full name of the original script file (that is what the weird incantation is all about). This allows us to circumvent hardcoding the path to the Tcl shell in our source code.

Now, the really unexpected bit, the Tcl shell is started and that considers the first three lines to be comments: the first two because of the # sign and the third because the Tcl parser has seen a backslash at the previous line and therefore joins up the third line with the second one.

So, in this strange way, the Tcl shell program is started automatically and our application can go ahead ...

All that is needed now is a suitable place to put our source code - preferably in the user's path - and eh presto!, the installation is ready.

An alternative is, of course, to create a small shell script that resides in some convenient directory (~/bin might be a good idea) and that starts the application via:

#!/bin/sh
APPDIR=/usr/local/myapp
exec tclsh $APPDIR/bin/myapp.tcl "${1+"$@"}

7.2 Installation on Windows

If we again assume that Tcl/Tk has been installed or will be installed on the target system, then the installation process has created some file association between a Tcl shell and the file extension ".tcl".

With some versions of Windows (notably NT and XP) this should be enough to be able to start the program in a DOS box:

c:\> myapp.tcl

(It will certainly be enough to start it via a file manager.)

If this does not work, then the following procedure is guaranteed to work:

  • Create a small batch file, myapp.bat, with commands like:
 @echo off
 "...path1...\tclsh.exe" "...path2...\myapp.tcl" %1 %2 %3 %4 %5 %6 %7 %8 %9
  • The string "...path1..." must be replaced by the correct full path to the Tcl installation, the string "...path2..." must be replaced by the full path to the application that you want to start.
  • Put this batch file into some directory that is in the path (c:\bin is one possible choice)
  • Be sure to keep the quotation marks! On Windows it is very commonplace to store files in directories that have spaces in their names - a nuisance because it incessantly causes parsing problems.

7.3 Installation on Mac OS X

P.M. - unfortunately

7.4 Things to consider: the directory structure

The above discourse assumes that you have made your application so that it can reside anywhere and be run anywhere. This is fairly easy to do when it consists of a single source file and does not need anything else. But if you need to source some library files or need access to data files, then you must be more careful.

Here are some tips:

  • In the main code for the main source file, make sure you store the name of the directory that holds your source file for later use: the global variable argv0 can be used to retrieve the information (or better still: the command info script as this is more general applicable).
  • When you need to source or read other files, make sure their names are relative to that directory.
  • Store all files that are part of your application in a directory structure like this:
.../myapp/
          bin/       - directory holding the sources
          doc/       - directory with information about the application
          lib/       - directory with some configuration files for instance
          README     - quick overview
          myapp.bat  - short Windows/DOS batch file to start the program
          myapp      - short UNIX/Linux shell script to start the program

Here is a small, nonsensical, example:

# myapp.tcl --
#
#
# Procedure: Print the welcome message
#
proc hello {text} {
   puts $text
}
#
# Procedure: Print the goodbye message
#
proc goodbye {text} {
   puts $text
}

# main --
#    Initialise the application (read the configuration file)
#
#    Note:
#    Store the directory where the main source file resides
#    for later use. We need to do it in the main code outside
#    any procedure as the information is "volatile".
#
#
set appdir [file dirname [info script]]

#
# The messages file is a small Tcl source file that defines the
# variable hellotext and goodbyetext, but to be save, set defaults
# here
#
set hellotext   "Starting the application ..."
set goodbyetext "Done"

source [file join $appdir ".." "lib" "messages"]

#
# Start the application
#
hello $hellotext
#
# After all the processing, we are done
#
goodbye $goodbyetext

7.5 Things to consider: wrapping

The scenarios we have described sofar assume that Tcl/Tk is installed on the system (and it is useable by the client of our application) and we are willing to deliver the source code. If either condition fails, these scenarios will not work.

There is a very good alternative to installing Tcl/Tk: you can wrap your application. There are several methods to do this, and as a side effect, your code becomes unreadable (at least for ordinary users). If you need to hide your source code altogether, then the use of Tclpro may be a solution for you.

Here are a few possibilities:

  • Use freewrap to wrap your sources into a standalone executable. (you can find more information at: ...)
  • Use Tclpro (see ...) or DevKit from ActiveState (see ...) to compile your source code into so-called tbc files, that way your source code is not delivered in any form to the client.
  • Use Tclkit (see ...) to pack up your source code and create a platform-independent "starkit". This can also be turned into a standalone executable (a "starpack").

This tutorial describes the third option in some detail, as the process is simple, elegant and very general:

  • First produce a basic starkit by wrapping up the main code:
tclkit sdx qwrap myapp.tcl
  • If you need to add more files to the application, unwrap it:
 tclkit sdx unwrap myapp.kit
  • This creates the basic directory structure for your starkit. You can now add more files as you see fit. These files will end up in a virtual file system: you can read them from within the starkit.
  • When you are done, wrap the whole thing up again:
 tclkit sdx unwrap myapp.kit

Et voila, you application is ready for shipping. Just deliver it together with the tclkit for the platform in question.

The other solutions mentioned here may use different methods, but the effect is pretty much the same: a standalone executable that does not rely on anything else to be installed on the target machine.

DKF: FWIW, the modern tclpro (a.k.a TclDevKit) wrapping utility builds starkits too (with minor differences IIRC).

7.6 Things to consider: the desktop

Modern practice on many computer systems nowadays demands that applications be started from the Start menu of the desktop or by some other graphical means.

This may be a general practice, but the details are extremely platform-dependent. See chapter 8 .... for more information.

One problem that such a procedure introduces is: what is the start-up directory? If you use a command shell, then the start-up directory is whatever the working directory is. But when you launch a program via the desktop, there is a fixed directory that needs to have been defined beforehand.

Depending on the features of your application, that may or may not be suitable: a word processor is not likely to mind too much, whereas a tool for finding files is probably best started in some relevant directory.