- 1.
A single Tcl script.
-
Suppose you have written a simple application that fits comfortably
in one script, myapp.tcl.
The command line to wrap this into an executable
named myapp is this:
prowrap -uses tclsh myscript.tcl -o myapp
The -uses tclsh
flag is a shorthand that means "start with the statically
compiled Tcl shell and the standard Tcl libraries."
The -o myapp option defines the name of the resulting program,
which is prowrapout (or prowrapout.exe) by default.
- 2.
A single Tcl/Tk script.
-
If your script uses Tk (i.e., wish), then you need the
-uses wish flag:
prowrap -uses wish myscript.tcl -o myapp
This uses the standard wish interpreter and wraps the
Tk script libraries as well as the standard Tcl libraries.
- 3.
A script that sources other scripts.
-
Suppose your main script uses the source command to load
several other scripts. Obviously, you must wrap the other scripts.
However, you also need to understand how to name the scripts in your
source command. There are two basic rules:
- Wrapped files have a relative pathname (e.g., lib/foo.tcl)
- Your script must reference them the same way they are specified
on the prowrap command line.
To be concrete, let's suppose myscript.tcl includes these
commands:
source help.tcl
source utils.tcl
The prowrap command line should look like this:
prowrap -uses wish myscript.tcl help.tcl utils.tcl -o myapp
Of course, this means all the .tcl files are in the same directory
when you are using prowrap.
- 4.
A script that sources scripts from a well known directory.
-
One problem with the previous example is you must be in the
same directory as myscript.tcl to run it successfully.
(This is before wrapping.)
One approach is to hardwire the script location:
set home /usr/local/src/myapp
source [file join $home help.tcl]
source [file join $home utils.tcl]
You have to modify this to work in a wrapped application
because the wrapped files canot be named with an absolute path like
/usr/local/src/myapp/help.tcl.
One technique works like this:
if {[info exists tcl_platform(isWrapped)]} {
set home myapp
} else {
set home /usr/local/src/myapp
}
source [file join $home help.tcl]
source [file join $home utils.tcl]
The tcl_platform(isWrapped) variable is only defined when
the application is wrapped, so the above code works before and
after wrapping.
The prowrap command line is:
prowrap -uses wish myscript.tcl \
-relativeto /usr/local/src \
/usr/local/src/myapp/help.tcl \
/usr/local/src/myapp/utils.tcl \
-o myapp
The -relativeto flag strips the /usr/local/src off the names that
come after that point in the command line. This means that the
additional files are visible as myapp/help.tcl
and myapp/utils.tcl in the wrapped application.
- 5.
A script that sources scripts relative to [info script].
-
One common trick to avoid hard-wiring pathnames into your
scripts is to figure out where the script is located with
info script and then source things relative to that:
set home [file dirname [info script]]
source [file join $home help.tcl]
source [file join $home utils.tcl]
The home variable is set to the directory containing
the script, and the other scripts are kept in the same location.
You can make the above code work before and after wrapping.
The prowrap command line has to be:
prowrap -uses wish myscript.tcl \
./help.tcl ./utils.tcl -o myapp
This is because info script will return myscript.tcl,
and file dirname will return . (i.e., "dot").
- 6.
An application that uses auto-loading (i.e., tclIndex files).
-
As the number of scripts in your application grows, it becomes
more convenient to use libraries or packages and let the
auto-loading mechanism run the source commands as needed.
This is also a great way to share code among applications.
Suppose help.tcl and utils.tcl are in a subdirectory
named /usr/local/lib/common on your system, and that
directory contains a tclIndex file created with
auto_mkindex.
Your script would contain this command to make the procedures
visible in those files available:
lappend auto_path /usr/local/lib/common
This needs to change in your wrapped application.
You can use a variation on the info script trick,
or just test for wrapping and use a relative name:
if {[info exists tcl_platform(isWrapped)]} {
lappend auto_path lib/common
} else {
lappend auto_path /usr/local/lib/common
}
Now you have to remember to wrap the tclIndex file, too.
The prowrap command line is:
prowrap -uses wish myscript.tcl \
-relativeto /usr/local \
/usr/local/lib/common/*.tcl \
/usr/local/lib/common/tclIndex -o myapp
This wraps the .tcl files and the tclIndex from /usr/local/lib/common,
and the -relativeto flag strips the /usr/local off the names of
those files.
Here we assume your UNIX command shell has expanded *.tcl.
(On Windows, prowrap does this glob expansion.)
Your script can access them with names like
lib/common/help.tcl.
The addition of lib/common to your auto_path and
the tclIndex file in that directory will result in exactly
this name being used by the Tcl auto-loading facility.
- 7.
A script that uses -code hooks.
-
If you don't like having to change your scripts when they
are wrapped, you may be able to take advantage of the
-code feature of TclPro Wrapper.
This option lets you specify some Tcl code that is executed
very early during startup of the wrapped application.
For example, we could add the appropriate value to
the package search path at this point:
prowrap -uses wish myscript.tcl \
-relativeto /usr/local \
/usr/local/lib/common/*.tcl \
/usr/local/lib/common/tclIndex \
-code "lappend auto_path lib/common" \
-o myapp
This way you could leave the hard-wired absolute pathname in your
original script. If the absolute pathname exists while the wrapped
application is running, the wrapped directory will still be first
in the auto_path.
- 8.
A script that uses packages of other scripts.
-
With standard Tcl, you can create a directory next to the Tcl script
library and the standard auto_path value will make any packages
in that directory visible.
Suppose your Tcl installation has its script library (i.e., $tcl_library) in
/usr/local/lib/tcl8.0.
You can put your packages into
/usr/local/lib/common
and create a package index with pkg_mkIndex.
Once you do this,
your application uses package require and the scripts
for the packages will be sourced automatically.
package require help
package require utils
TclPro Wrapper understands pkgIndex.tcl files and will automatically
add wrapped directories to your auto_path
if they contain pkgIndex.tcl files.
You can wrap
all these packages and automatically update your auto_path with:
prowrap -uses wish myscript.tcl \
-relativeto /usr/local \
/usr/local/lib/common/*.tcl -o myapp
If you examine your auto_path in the wrapped application, it will
contain the following paths:
lib/tcl8.0
lib
/TclPro/lib
/TclPro/arch/lib
lib/tcl8.0/http2.0
lib/common
- 9.
Converting an existing custom shell to an interpreter you can use with prowrap.
-
This examle assumes you already have built a custom Tcl shell
that adds some new commands or bundles in a needed extension.
If you have never done this, skip to the next example.
Building a custom shell with standard Tcl involves the Tcl_Main
library procedure and the Tcl_AppInit callback. A condensed
version of this C code might look like this:
#include
#include
int Tcl_AppInit();
main(int argc, char *argv[])
{
Tk_Main(argc, argv, Tcl_AppInit());
exit 0;
}
int
Tcl_AppInit(Tcl_Interp *interp)
{
Tcl_Init(interp); /* Check return values */
Tk_Init(interp);
Blt_Init(interp);
}
To convert this to a wrapped application you just need to call
Pro_WrapTkMain instead of Tk_Main,
or
Pro_WrapTclMain instead of Tcl_Main.
You may also want to call Tbcload_Init
if you are wrapping .tbc files produced by TclPro Compiler.
There are sample main programs and AppInit routines
for Unix and Windows in
/TclPro/lib/tcl8.0/tclProUnixMain.c
/TclPro/lib/tcl8.0/tclProWinMain.c
/TclPro/lib/tk8.0/tkProUnixMain.c
/TclPro/lib/tk8.0/tkProWinMain.c
If you have an existing custom shell, you should compare your
code with the above examples. Those files are used to
create protclsh80 and prowish80.
Next you need to modify your existing Makefile to
add the wrapper library, and optionally the byte-code loader.
You need to add these libraries:
-L /TclPro/arch/lib
-lwrapper10s -ltbcload10s -ltk8.0 -tcl8.0
You may also have to specify libtcl8.0.a instead
of -ltcl8.0 to make sure you statically link the Tcl library.
You will need to add to your include path so you can
pick up "proWrap.h" or "proTcbLoad.h":
-I /TclPro/include
Note!
In TclPro 1.0 and 1.1,
Pro_WrapTkMain and Pro_WrapTclMain
are distributed in source form only;
they are not in the wrapper library.
You'll find these sources in
/TclPro/lib/tcl8.0/proWrapTclMain.c
/TclPro/lib/tk8.0/proWrapTkMain.c
You will have to compile these yourself.
In extreme cases you may need to copy and edit these, but
only if you have had to make similar changes in Tcl_Main
or Tk_Main.
Finally, the prowrap command line uses -executable file
to specify the custom Tcl shell. You also need the standard Tcl libraries,
and the easiest way to do that is to specify -uses wish
before the -executable option. That overrides the standard
executable (i.e., wrapwish80s.in) but keeps the standard script
libraries.
As an example, here is a
Makefile that
compiles and wraps an application.
- 10.
Using the sample application to build a new interpreter.
-
TclPro ships with a sample application in
/TclPro/demos/sampleApp/
The first step is to make sure you can make the sample application,
then worry about modifying it to add the extensions you need.
On UNIX platforms you do this:
cd /TclPro/demos/sampleApp/
configure --enable-gcc
make
If you have compiled other extensions, this setup should be
familiar to you.
(The --enable-gcc flag indicates you are using the gcc compiler.
If you are using the vendor's "cc", then leave this out.)
The result of running configure is a Makefile that is
tailored to your particular flavor of UNIX.
On Windows you can run "nmake -f sampleApp.mak" to
build the app with the Microsoft VC++ Compiler.
The sample application depends on some C source files that are kept
in another location.
First, there are sample main programs and Tcl_AppInit procedures.
/TclPro/lib/tcl8.0/proTclUnixMain.c
/TclPro/lib/tcl8.0/proTclWinMain.c
/TclPro/lib/tk8.0/proTkUnixMain.c
/TclPro/lib/tk8.0proTkWinMain.c
You will want to copy the appropriate one of these
depending on if you use Unix or Windows, and need
a Tcl or Tcl/Tk shell.
These are the same source files used to
create protclsh80 and prowish80.
For example, to make a Tcl/Tk shell on UNIX, start with this:
cd /TclPro/demos/sampleApp/
cp /TclPro/lib/tk8.0/proTkUnixMain.c myMain.c
Now you need to edit this file to add the appropriate
initialization calls to the Tk_AppInit (or Tcl_AppInit)
procedure. Tcl extensions should have an Extention_Init
procedure that defines all their Tcl commands.
Examples include Blt_Init, Sybtcl_Init, and so on.
Model your new code after the other initializations
that look like this:
if (Tbcload_Init(interp) == TCL_ERROR) {
return TCL_ERROR;
}
Tcl_StaticPackage(interp, "tbcload",
Tbcload_Init, Tbcload_SafeInit);
If your extension doesn't have a SafeInit procedure, just use NULL
for that argument.
If you are adding your own commands with Tcl_CreateCommand,
insert these calls, too.
Now you need to edit the Makefile to build a shell that uses
your myMain.c and any libraries or source files for extensions.
To continue our example, copy this Makefile production for
the static wish shell:
${SAMPLE_STATIC_WISH}: ${SAMPLE_WISH_OBJS}
${CC} -o $@ ${CC_GUI_FLAGS} ${LD_FLAGS} \
${SAMPLE_WISH_OBJS} \
${STATIC_TK_LIB_FLAGS}
You need to change this to use myMain.o and any required libraries.
You might add something like this:
MYOBJS = myMain.o proWrapTkMain.o
mywish: ${MYOBJS}
${CC} -o $@ ${CC_GUI_FLAGS} ${LD_FLAGS} ${MYOBJS} \
/usr/local/src/sybtcl-2.5/unix/shsybtcl.o \
/home/sybase/lib/libsybdb.a \
${STATIC_TK_LIB_FLAGS}
The prowrap command line uses -executable file
to specify the custom Tcl shell. You also need the standard Tcl libraries,
and the easiest way to do that is to specify -uses wish
before the -executable option. That overrides the standard
executable but keeps the standard script
libraries.
prowrap -uses wish -executable mywish mysyb.tcl -o mysyb
- 11.
A dynamic shell with loadable binary packages.
-
If you only have DLLs (i.e., shared libraries) and
cannot create a statically-linked custom shell,
then you must these distribute DLLs along with your wrapped application.
This is because it is not possible to dynamically link against
a file contained in the wrapped application.
In other words, you cannot use the Tcl load command
and specify a DLL that is inside your wrapped application.
Distributing DLLs is also useful if you have a collection of applications
in your product.
The DLLs will save disk space for your distribution,
and the operating system can share code space among applications that use
the same DLLs.
Specify -uses tclsh-dynamic or
-uses wish-dynamic to get the dynamically linked shells.
One major issue you will have to work out for a dynamic distribution is
how to organize your files and your users environment so the
shared libraries can be found at runtime.
As well as the DLLS for the extensions, you also need to
remember the Tcl and Tk shared libraries.
On Windows you can put all the DLLs into the same directory as
the wrapped application and they will be found automatically.
On UNIX you will have to set up the LD_LIBRARY_PATH environment
variable so it includes the
directory containing the shared libraries.
Look at the UNIX TclPro wrapper scripts for an example of how
we do it. Examples include /TclPro/arch/bin/protclsh80,
which is a wrapper script that sets up the environment before
calling protclsh80.bin.
- 12.
A custom shell that does a package require.
-
The motivating example here is wrapping a custom
shell that includes, for example, Tcl-DP, and using
scripts that say:
package require Dp
First, follow the instructions for creating a custom shell
that statically links the extension libraries into the shell.
You will also have to wrap any script files that are associated
with your extension.
If your Tcl_AppInit function calls the extension _Init function
(e.g., Dp_Init)
then your scripts will be able to use the commands defined
in the library without a package require command.
If the _Init function is not called
in your Tcl_AppInit, then you will have to either use load
or package require to trigger a call to the _Init function.
The following command "loads" a statically linked extension:
load {} Dp
The file name is empty, so Tcl just looks for the Dp_Init function
call.
If you need to use package require,
then you must wrap a pkgIndex.tcl file that contains the
necessary load command in a package ifneeded command.
Put the following line of code into this custom pkgIndex.tcl file:
package ifneeded Dp 3.0 [list load {} Dp]
Next, put this pkgIndex.tcl file into a subdirectory of the
lib directory that contains your Tcl script library. We recommend
the lib/static directory. If you have several statically linked packages,
the lib/static/pkgIndex.tcl file can have package ifneeded
commands for each one.
Finally, make sure this pkgIndex.tcl is wrapped. You may need to
append the lib/static directory to the auto_path variable using
a -code command line argument. (For
more information about the -code argument,
please see FAQ 7.)
- 13.
An executable for a different platform.
-
Suppose you develop on Linux and want to wrap an application
for Solaris or Windows.
Let's take the first example: wrapping on Linux for Solaris.
First, when you install TclPro, install for both the Linux and
Solaris platforms. You can install for any or all of the
supported UNIX versions.
Once you've done that, cross-platform wrapping boils down to
specifying a platform-specific executable.
Here is a simple example:
prowrap -out myapp.solaris -uses wish \
-executable ~/TclPro1.3/solaris-sparc/lib/wrapwish82s.in \
myscript.tcl
The -uses wish is important because it ensures that all the
right Tk script libraries are wrapped and that the right
initialization is done. You must also put that before
the -executable flag because the -uses implies the Linux executable,
and then the -executable flag overrides it.
We have used the static shell here, too, identified by the "82s.in".
That will make it easier to distribute.
If you want to go from Linux to Windows (or Windows to Linux) then
you have to merge the Unix and Windows installations of TclPro,
or have both installations available via network file systems.
The easiest way to do this is install TclPro on Windows and then
copy its win32-ix86 folder into your Unix installation of
TclPro. Here are the contents of the top-level TclPro installation
after you've done that:
INSTALL.LOG
README
demos/
doc/
hpux-parisc/
include/
irix-mips/
lib/
license.txt
linux-ix86/
solaris-sparc/
src/
win32-ix86/