For those of us who write their own Tcl code, scripts are probably fine but for almost everyone else executables are needed.
Freewrap is probably the easiest to use utility ever produced to generate executables from Tcl scripts. There are other alternatives around, such as Starkits, but when all gnocl sharables are in their own place and available for other apps or scripts, what more could be desired? So, how are the executables made? Firstly, obtain a copy of Freewrap from Sourceforge. Both pre-compiled binaries and source tarballs are available so take your choice. Next, copy the executable into some location in the system path such as /usr/local/bin and then you're ready to create some standalone apps.
In order to use Gnocl it's necessary to load binary packages in the right way. Its no longer possible to simply use the familiar ‘package require’ instruction, the alternative load command needs to be used. One way to load these libraries would be to include a unique copy with the application executable, indeed application specific modules can be accessed in this way. The Gnocl libraries are intended to be shared and so these ought to be accessed from their appropriate installations. To do this with the load command the full path and file name needs to be provided. For local copies this would be:
load ./gnocl.so
or even,
load ./lib/gnocl.so
Whereas in order to access a system wide installation of the Gnocl libraries this might be something like:
load /usr/lib/tcl/tcl8.5/gnocl0.9.95.so
With this in mind then, an absolute minimal script looks something like this:
#!/bin/sh
# the next line restarts using tclsh \
exec tclsh "$0" "$@"
load "./gnocl.so"
puts "Gnocl Version [gnocl::info version]"
set but1 [gnocl::button -text "Hello World!" -onClicked {gnocl::beep} ]
gnocl::window -child $but1 -onDelete {exit}
gnocl::mainLoop
This can then be turned into an executable using the command:
freewrapTCLSH hello.tcl
From this an executable named ‘hello’ would be generated.
Standalone Apps
You've slaved for months to develop that killer Linux app in Tcl/Gnocl and you want to share it with the world.
But,
what about your potential users? What if they don't know anything about
Gnocl or, most likely, do not want to go through the whole process of
downloading tarballs, dependencies and building apps from sourcecode?
Relax, this is not a problem. Freewrap can allow the wrapping of both
script and binary packages into itself. The bottom line is then,
there's no need even to install Gnocl or any other module for that
matter. Yay! I hear you cry. How is this done?
The FreewrapTCLSH
command can take a number of parameters which instruct it on how to
proceed. A simple list of files will tell it what to included in a
wrapped script. Returning to the familiar hello.tcl script, the
gnocl.so shared library can be wrapped together with the script using
like this:
freewrapTCLSH hello.tcl gnocl.so
Previously
the separate gnocl.so module was accessed using the load command.
Wrapped packages cannot be read directly and so need to be installed
and then loaded. The ::freewrap::unpack command does it for you. Here's how the hello.tcl script is modified:
#!/bin/sh
# the next line restarts using tclsh \
exec tclsh "$0" "$@"
# unpack, load and delete
set fpath [::freewrap::unpack gnocl.so]
load $fpath
file delete -force $fpath
puts "Gnocl Version [gnocl::info version]"
set but1 [gnocl::button \
-text "Hello World!" \
-onClicked {gnocl::beep} ]
gnocl::window \
-child $but1 \
-onDelete {exit}
gnocl::mainLoop
Here
the gnocl.so file is unpacked (the default directory is /usr/tmp) and
the path returned to the calling script. This can then be loaded as
usual before any clearing up of temp files takes place. This cluster of
commands is ripe for modification into a more general purpose procedure
which typically would look something like this:
proc freewrap_load {packages} {
foreach package $packages {
set pkg [::freewrap::unpack $package]
if {$pkg == ""} {
error "Package $package not found."
}
load $pkg
file delete -force $pkg
}
}
Automating the Process
When things get more complicated, alternative solutions are necessary.
Although
the process of adding new packages is simple in principle, no-one wants
to type lengthy options each time a fresh wrap is needed. The following
shell script shows how it's possible to draw in the 'core' Gnocl
package set and bring them together into a single wrapped application.
Here, fresh copies of shared objects are assembled during each wrap
session, useful if the packages too are still in development.
#---------------
# wrap.sh
#---------------
# William J Giddings
# 23/04/2010
#---------------
TCL_SOURCES=hello_2.tcl
BINARY_NAME=testApp
GNOCL_VERSION=0.9.95
PACKAGE_BASE_PATH=/usr/lib/tcl/tcl8.5
TEST=1
echo "----------------------------------------"
echo "Building $BINARY_NAME from $TCL_SOURCES"
echo "----------------------------------------"
echo "1) Copying packages"
cp $PACKAGE_BASE_PATH/gnocl$GNOCL_VERSION/gnocl.so ./
cp $PACKAGE_BASE_PATH/gnoclCanvas$GNOCL_VERSION/gnoclCanvas.so ./
cp $PACKAGE_BASE_PATH/gnoclGnome$GNOCL_VERSION/gnoclGnome.so ./
cp $PACKAGE_BASE_PATH/gnoclGconf$GNOCL_VERSION/gnoclGconf.so ./
cp $PACKAGE_BASE_PATH/gnoclVFS$GNOCL_VERSION/gnoclVFS.so ./
echo "2) Wrapping"
freewrapTCLSH $TCL_SOURCES \
gnocl.so \
gnoclCanvas.so \
gnoclGnome.so \
gnoclGconf.so \
gnoclVFS.so \
-o $BINARY_NAME
echo "3) Cleaning up"
rm *.so
if test $TEST -eq 1
then
echo "4) Testing $BINARY_NAME"
echo "----------------------------------------"
./$BINARY_NAME
fi
exit 0