Version 0 of Building Stand-Alone Tcl/Tk Applications under Mac OS X

Updated 2004-11-08 16:19:00

MAK This is a summary of steps required to build a stand-alone Tcl/Tk application under Mac OS X. Most of this is gleaned from tcl-mac list archives and through experimentation. By stand-alone I mean an application that will run on any system, regardless of whether or not Tcl/Tk is already installed. I've described the process assuming that you've got a binary application as opposed to just wanting to wrap a Tcl script, since that's what I'm trying to do. Other tips and information, which as what to do if you just want to wrap a Tcl script, would be welcome.

1. Use the embedded builds ("make embedded" from the tcl/macosx and tk/macosx directories). This does three things for you.

First, the extra cruft of documentation and other non-essential files are excluded from the Tcl.framework and Tk.framework directories, so that when you include them in your application bundle they do not make the size of the bundle larger than necessary.

Second, it creates a stand-alone "Wish Shell.app" application bundle, which you may choose to use as a template for building your own application bundle. It contains the Tcl and Tk frameworks inside it so this app can be used on any system, regardless of whether or not Tcl/Tk is installed. This is, I believe, how the TclTkAquaStandalone [L1 ] distribution is built.

Third, the binaries in the bundle (including the Wish Shell binary and the Tcl and Tk frameworks) are linked with executable-relative paths to each other using the @executable_path magic keyword. That is, if you run 'otool -L "Wish Shell.app/Contents/MacOS/Wish Shell"' the output looks like:

 Wish Shell:
        @executable_path/../Frameworks/Tk.framework/Tk (compatibility version 8.4.0, current version 8.4.0)
        @executable_path/../Frameworks/Tcl.framework/Tcl (compatibility version 8.4.0, current version 8.4.0)
        /usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.0.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 71.1.1)

This is essential for the application to use the included Tcl/Tk binaries instead of trying to find them in the usual system-wide location (/Library/Frameworks/Tcl.framework and Tk.framework).

2. You need an application bundle. As mentioned above, the embedded build will create a stand-alone "Wish Shell.app" which you can use as a template, but it is useful to know how the bundle is structured, and to be able to build it yourself. Some references that may be helpful:

  • Anatomy of a Bundle [L2 ]
  • Information Property List Files [L3 ]

The basic structure that you'll need for the bundle, including an applicaton-specific icon, is as follows:

 MyApp.app/
    Contents/
        Info.plist
        Frameworks/
            Tcl.framework/
            Tk.framework/
        MacOS/
            MyApp
        Resources/
            MyApp.icns

Here, MyApp is the name of your application. The info.plist file is the Information Property List file. It's an XML file that provides information to the operating system about your application, such as the name of the binary (MyApp), the application's version, and the name of the icon file, possibly document file types that it opens, etc.

3. Copy Tcl.framework and Tk.framework from "Wish Shell.app" into the place shown above. You should not need to do anything else with them, since they have already been linked with the @executable_path keyword in them.

4. Your application binary (MyApp) will undoubtedly point to the wrong location for the frameworks, rather than using @executable_path as the frameworks do. This is a problem that you need to fix or else your application won't run on another system without Tcl/Tk installed, or installed in some other location. You can fix this with the install_name_tool command line tool provided with OS X's development tools:

   install_name_tool -change old new file

'old' is the currently existing path in the binary, which you can obtain using "otool -L MyApp.app/Contents/MacOS/MyApp". I'm not sure how to automate this yet so you can fix the paths with a makefile (anyone?), but what you need to do is:

   install_name_tool -change /old/path/to/Tcl \
       @executable_path/../Frameworks/Tk.framework/Tcl \
       MyApp.app/Contents/MacOS/MyApp
   install_name_tool -change /old/path/to/Tk \
       @executable_path/../Frameworks/Tk.framework/Tk \
       MyApp.app/Contents/MacOS/MyApp

Your application's binary should now find Tcl/Tk in the right location, no matter where or on what system the application is placed.