Find precompiled or compile Tcl/Tk Frameworks for

2019-08-23 16:48发布

问题:

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.)

回答1:

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


回答2:

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.