This page provides a "how to" guide to TclPro Wrapper. TclPro Wrapper generates a single executable file that bundles, or wraps, all the scripts and supporting files you need for your Tcl/Tk application. These include the standard Tcl script libraries, any supporting scripts you need, the main application script, and supporting files like GIFs or data files. A wrapped application is built from a statically compiled Tcl interpreter and a ZIP file containing all the other needed files. TclPro ships with a number of static shells, or you can compile your own.

Contents

  • 1. A single Tcl script.
  • 2. A single Tcl/Tk script.
  • 3. A script that sources other scripts.
  • 4. A script that sources scripts from a well known directory.
  • 5. A script that sources scripts relative to [info script].
  • 6. An application that uses auto-loading (i.e., tclIndex files).
  • 7. A script that uses -code hooks.
  • 8. A script that uses packages of other scripts.
  • 9. Converting an existing custom shell to an interpreter you can use with prowrap.
  • 10. Using the sample application to build a new interpreter.
  • 11. A dynamic shell with loadable binary packages.
  • 12. A custom shell that does a package require.
  • 13. An executable for a different platform.
  • Wrapping Examples

    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:
    1. Wrapped files have a relative pathname (e.g., lib/foo.tcl)
    2. 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/
    
    Add link to comments for /doc/howto/wrap.html

    Top of page
    Developer Home | Getting Started | Tcl Advocacy | Software Resources | Documents | Community | Links
    Site Map | Feedback | webmaster@-SPAM-.tcl.tk

    Last modified: April 24, 2001