1

I am a beginner with Tcl/Tk, but I am already in need to deploy an .app with Tcl/Tk frameworks in it (because the .app needs to rely on its own Tcl/Tk version and not on macOS standard and old Tcl/Tk). Can somebody point me to where I can find precompiled Frameworks or to a step-by-step guide on how to compile them on macOS?

Half a day of search has not been very fruitful in this regard. I guess my need is not at all very special, as I see many .apps shipping their own Tcl/Tk Frameworks. (PS: I need to access these Frameworks from Perl, but this shouldn't make any difference.)

mrcalvin
  • 3,291
  • 12
  • 18
Kelly o'Brian
  • 415
  • 3
  • 12

2 Answers2

3

Here is my build script. You will need to make modifications to suit your needs.

  • I make modifications to init.tcl so that Tcl will search in the proper locations and will not look first in the MacOS standard location. This part of the script will break starting with Tcl/Tk 8.7. It also has a path that is very specific to my installation (the 'darwin 64 tcl lib' part). It won't hurt anything to leave it in, or you can modify the path for your needs.
  • I make the application relocatable so that it can be run from any location. This can be a security issue. It is recommended that additional processing be done after installation to set the library paths to a static location.

I personally recommend Tcl/Tk 8.6.8 at this time, but it has to be built with an earlier XCode version (I use XCode Command Line Tools 9.2 on Sierra).
There are still various bug fixes for MacOS Mojave being worked on. Other people may recommend otherwise.

Variables:

  • macosxminver : The earliest version of MacOS that Tcl/Tk will be compiled for.
  • INSTLOC : The installation location. Point this somewhere other than your target directory and copy the files to your target directory afterwards. Note that the INSTLOC directory is completely removed by the script.
  • sver : short Tcl version. The only place this is used is in the SRCDIR definition. You may not need this depending on your SRCDIR directory structure.
  • ver : Tcl version number.
  • mver : Tcl major version number.
  • SRCDIR : Where the Tcl/Tk source trees are located. For the purposes of this script, I have a directory with the following structure:

directory structure:

tcl868/
  tcl8.6.8/
  tk8.6.8/

tclbuild.sh:

#!/bin/bash

macosxminver=10.9
sver=868cp
ver=8.6.8
mver=8.6
tclmver=$mver
tkmver=$mver
SRCDIR=$HOME/t/tcl${sver}
INSTLOC=$HOME/t/localB

if [[ $1 != "" ]]; then
  INSTLOC=$1
fi

if [[ -d $INSTLOC ]]; then
  rm -rf $INSTLOC
fi
mkdir $INSTLOC

cd $SRCDIR

test -d build && rm -rf build

cd $SRCDIR
cd tcl${ver}
if [[ $? -eq 0 ]]; then
  f=library/init.tcl
  if [[ ! -f $f-orig ]]; then
    cp -pf $f $f-orig
  fi
  cp -pf $f-orig $f

  ed $f << _HERE_
/issafe/
i
    foreach Dir [list \$::tcl_library [file dirname \$::tcl_library]] {
        if { [string match *Tcl.framework* \$Dir] } {
          regsub Tcl.framework \$Dir Tk.framework Dir
          if {\$Dir ni \$::auto_path} {
            lappend ::auto_path \$Dir
          }
        }
    }

    # This needs to be at the end
    # The real wish executable is in an odd place.
    # Find the tcl directory in the path.
    set Dir [file dirname [info nameofexecutable]]
    if { [string match *MacOS* \$Dir] } {
      regsub {MacOS.*} \$Dir {MacOS} Dir
      set Dir [file join \$Dir darwin 64 tcl lib]
      lappend ::auto_path \$Dir
    } else {
      set Dir [file join [file dirname [file dirname \\
           [info nameofexecutable]]] lib]
    }

.
?catch
?set Dir
.,.+4 s/^/#/
/catch
.+1,.+5 s/^/#/
w
q
_HERE_

  make -C macosx \
      PREFIX="" \
      CFLAGS_OPTIMIZE="-O2 -mmacosx-version-min=${macosxminver}" \
      INSTALL_ROOT=$INSTLOC install

  cd $SRCDIR

  chmod u+w $INSTLOC/bin/tclsh${tclmver}
  install_name_tool -change \
      "/Library/Frameworks/Tcl.framework/Versions/${tclmver}/Tcl" \
      @executable_path/../Library/Frameworks/Tcl.framework/Versions/${tclmver}/Tcl \
      $INSTLOC/bin/tclsh${tclmver}
fi

cd $SRCDIR
cd tk${ver}
if [[ $? -eq 0 ]]; then
  make -C macosx \
      PREFIX="" \
      CFLAGS_OPTIMIZE="-O2 -mmacosx-version-min=${macosxminver}" \
      INSTALL_ROOT=$INSTLOC install
  cd $SRCDIR

  chmod u+w $INSTLOC/Library/Frameworks/Tk.framework/Versions/${tkmver}/Resources/Wish.app/Contents/MacOS/Wish
  install_name_tool -change \
      "/Library/Frameworks/Tk.framework/Versions/${tkmver}/Tk" \
      @executable_path/../../../../Tk \
      $INSTLOC/Library/Frameworks/Tk.framework/Versions/${tkmver}/Resources/Wish.app/Contents/MacOS/Wish
  install_name_tool -change \
      "/Library/Frameworks/Tcl.framework/Versions/${tclmver}/Tcl" \
      @executable_path/../../../../../../../Tcl.framework/Versions/${tclmver}/Tcl \
      $INSTLOC/Library/Frameworks/Tk.framework/Versions/${tkmver}/Resources/Wish.app/Contents/MacOS/Wish
fi

cd $SRCDIR
find $INSTLOC -type f -print0 | xargs -0 chmod u+w
exit 0
Brad Lanam
  • 5,192
  • 2
  • 19
  • 29
  • Just wondering: Is there anything wrong with using the framework-aware build machinery in Tcl: `make -C /path/to/your/tcl/src/macosx install`. See also the [build instructions in macosx/README](http://core.tcl.tk/tcl/dir?ci=fceef4cf7f2f9bb4&name=macosx&r=core-8-6-branch). They work just fine for me. – mrcalvin Dec 18 '18 at 13:00
  • There's no difference. The script does a bit more to make sure the build is relocatable and works in its installed location. – Brad Lanam Dec 18 '18 at 15:20
  • thx for the explanation, certainly worth adding to the built-in build machinery? works with 8.6.9, btw. – mrcalvin Dec 18 '18 at 16:22
  • I would like to see the init.tcl script "fixed" so that it uses the base install directories as a starting point to locate packages. For relocating a Tcl/Tk installation, a utility script could be written that would reset the share library load locations (rather than having to re-install). – Brad Lanam Dec 18 '18 at 21:54
  • We're planning to make all that stuff fixed in 8.7 (along with packing all those files together in an archive for faster opening and a more robust installation). – Donal Fellows Dec 19 '18 at 18:46
  • My final comment, after a couple of days of testing. Thank you guys! I have been able to successfully compile frameworks (latest version) both with the proposed script as well as with the build instructions. They work perfectly for my needs (I pack them in an .app bundle and access the Tk component from Perl). I couldn't make out differences in term of portability, but I admit I take them as a "black-box" for now. – Kelly o'Brian Dec 20 '18 at 18:35
0

The proposed script fails for me on Mojave, after compiling for several minutes, with the following error:

ERROR: version conflict for package "Tcl": have 8.5.9, need 8.6-
If running this script from 'make html', set the NATIVE_TCLSH environment
variable to point to an installed tclsh8.6 (or the equivalent tclsh86.exe
on Windows).
make[3]: *** [html-tcl] Error 1
make[2]: *** [install-strip] Error 2
make[1]: *** [install-tcl] Error 2
make: *** [install-deploy] Error 2
tclbuild.sh: line 74: cd: /Users/xl/t/tcl869cp: No such file or directory
tclbuild.sh: line 83: cd: /Users/xl/t/tcl869cp: No such file or directory
tclbuild.sh: line 84: cd: tk8.6.9: No such file or directory
tclbuild.sh: line 103: cd: /Users/xl/t/tcl869cp: No such file or directory

I have the latest Tcl/Tk (8.6.9) resources and the same folder structure as indicated above.

Mike
  • 1
  • This is not a proper answer. Maybe you should create a new question to solve your problem. – vmf91 Mar 02 '19 at 15:29