The Question Mark - blog by Mark Volkmann

Deploying

Smalltalk can be used to build command-line, desktop, and web applications. After writing and testing the code in a standard Smalltalk image, it is recommended to create a stripped down version of the image that only contains what is necessary for running the application.

All developer tools can be removed. For command-line and web applications, everything related to the Morphic GUI framework can be removed.

Stripping an image is a manual process that is described in the FAST 2024 conference video Bootstrap: Creating Minimal Images from Scratch.

Also see Make a standalone click-&-run Smalltalk application for macOS.

Running Headless

To run Smalltalk programs that are command-line utilities, apps, or servers, use the Smalltalk VM that is bundled inside the macOS app CuisVM.app that is included in the Cuis-Smalltalk-Dev GitHub repository. This is actually a Squeak VM.

Squeak VMs can also be obtained from OpenSmalltalk. Under “Releases” on the right side, click “Latest”. Click the proper file for your operating system and processor. For example, squeak.cog.spur_macos64ARMv8.dmg. Double-click the downloaded file to install it.

To manually download and build a Squeak VM for macOS:

  1. Open a Terminal and cd to the directory where the VM will be created.
  2. Enter git clone https://github.com/OpenSmalltalk/opensmalltalk-vm.git
  3. Enter cd opensmalltalk-vm
  4. Enter ./scripts/updateSCCSVersions
  5. Enter cd building
  6. cd to the appropriate subdirectory for the target OS and processor. For example, macos64ARMv8.
  7. See the instructions in the file “HowToBuild”.
  8. Enter cd squeak.coq.spur
  9. Enter ./mvm -A. This will run for around 10 minutes and generate an extreme amount of output.
  10. Enter chmod a+x Squeak.app
  11. Create a symbolic link to the VM that is inside this app by entering ln -s "./Squeak.app/Contents/MacOS/Squeak" squeak-vm.

To simplify running files containing Smalltalk code from the command line, create a script named “cuis” in a directory that is in your PATH containing the following:

#!/usr/bin/env bash
# Runs a file containing Smalltalk code in headless mode using Cuis Smalltalk.

if [ $# -ne 1 ]; then
  echo usage: cuis {file-name}
  exit 1
fi

CUIS_DIR=$SMALLTALK_DIR/Cuis-Smalltalk-Dev
VM=$CUIS_DIR/CuisVM.app/Contents/MacOS/Squeak
IMAGE=$CUIS_DIR/CuisImage/Cuis7.1-6452.image
$VM -headless $IMAGE -s $1

Create .st files containing Smalltalk code. For example, the file demo.st could contain the following:

| stdout |
stdout := StdIOWriteStream.
stdout nextPutAll: 'Hello, World!'; newLine.
Smalltalk quit

To run this, enter cuis demo.st.

TODO: This was working, but just hangs now. Why?

To get help on options, cd to your Cuis-Smalltalk-Dev directory and enter the following:

./CuisVM.app/Contents/MacOS/Squeak -help

For more detail see the SystemDictionary class displayCommandLineUsageOn: class method.

Building a Mac App

See https://www.youtube.com/watch?v=T95k9m5zcX4&list=PLu8vLCSA-4hklsvT9W6ruintbdx_K0DYW&index=4

See https://www.youtube.com/watch?v=b3oGOMCjKU8&list=PLu8vLCSA-4hklsvT9W6ruintbdx_K0DYW&index=3.

The steps to create a double-clickable macOS app are:

  • In the /Applications directory, create the directory structure {app-name}.app/Contents/MacOS.

  • To see what is inside this directory in the Finder, right-click the {app-name}.app file and select “Show Package Contents”.

  • Copy a Squeak VM into this directory. One can be found in Applications/Squeak.app/Contents/MacOS/Squeak.

  • Copy a Squeak image that implements the app into this directory with the name {image-name}.image.

  • Create the following shell script in this directory with the file name {app-name}:

    #!/bin/sh
    DIR=`dirname $0`
    exec $DIR/Squeak.app/Contents/MacOS/Squeak $DIR/{image-name}.image
    exit 0 # TODO: Is this needed?
    
  • Make the shell script executable by running chmod a+x {app-name}.

  • Create the file PkgInfo into this directory containing “APPL????” with no newline character.

  • Add an app icon. Copy an image onto the clipboard. One source for app icons is https://www.macosicongallery.com. In the Finder, right-click the app in the Applications directory and select “Get Info”. Click the app icon in the upper-left of the dialog that appears and press cmd-v to paste the new icon.

Preparing User Images

To create images that define applications to be used by non-developers, it is a good idea to disable and remove developer features. This the confusion that can arise when users accidentally open developer features and results in smaller images.

To hide the taskbar at the bottom of the World:

UISupervisor runningWorld hideTaskbar.

To disable the World menu so clicking on the World background no longer opens it:

TODO: How is this done?

Perhaps the way to prevent MessageNotUnderstood and other errors from displaying a debugger window is to execute the following:

SystemDictionary removeKey: #Debugger

The SystemDictionary class method isDevelopmentEnvironmentPresent checks for that key in the SystemDictionary.

Steps to Deploy TodoApp

  • Open a base image (currently named Cuis7.1-6713.image).

  • Open a Workspace.

  • Enter Feature require: 'UI-MetaProperties' and “Do it” (perhaps not everything installed by this is needed).

  • Enter Feature require: #TodoApp and “Do it”.

  • Enter TodoApp new. and “Do it”.

  • Position and size the “Todo App” window as desired.

  • Close the Workspace and Transcript windows.

  • Remove the taskbar at the bottom.

    • cmd-click the taskbar.
    • Click the menu halo button and select debug…inspect morph.
    • Enter self delete in the bottom pane and “Do it”.
    • Close the Inspect window.
  • Open the World menu and pin it so it remains open.

  • Open a Browser.

  • Disable the World menu.

    Use the Browser to modify the WorldMorph getMenu method to contain only the following:

    ^nil
    
  • Disable Morph halos.

    Use the Browser to modify the Morph mouseButton3Down:localPosition: method so the following line is commented out:

    self addHalo: aMouseButtonEvent.
    
  • Change error handling.

    Display a simple error dialog instead of opening a Debug window. To do this, modify the UnhandledError defaultAction method to contain only the following:

    self inform: exception description
    
  • Close the Browser.

  • Save the image with a new name.

    • Click “Save Image as…” in the pinned World menu.
    • Enter a name for the app (ex. TodoApp).
    • Close the World menu.
  • Quit the VM.

  • Create the following shell script in a file whose name is the app name (ex. todoapp). This assumes that the environment variable SMALLTALK_DIR is set to the path where the Cuis-Smalltalk-Dev local repository resides.

    #!/usr/bin/env zsh
    CUIS_DIR=$SMALLTALK_DIR/Cuis-Smalltalk-Dev
    VM=$CUIS_DIR/CuisVM.app/Contents/MacOS/Squeak
    IMAGE=$CUIS_DIR/CuisImage/TodoApp.image
    $VM $IMAGE
    
  • To run the app, open a Terminal, cd to the directory containing the script, and enter ./todoapp.

Hilaire Fernandes Approach

This does not remove the World menu.

  • cd to Cuis-Smalltalk-Dev directory

  • git clone https://github.com/hilaire/CuisApp.git

  • Modify the value of the cuisVersion variable near the beginning of the file CuisApp/build/makeBundle.sh to something like “7.1-6713”.

  • Build an image for the app by entering ./CuisApp/build/makeBundle.sh --build TODO: It’s unclear whether this can run in macOS. I get the following:

    CuisVM.app/Contents/Linux-x86_64/squeak: line 29: /usr/bin/ldd: No such file or directory
    CuisVM.app/Contents/Linux-x86_64/squeak: line 29: /bin/fgrep: No such file or directory
    Error. Could not determine platform's libc path for VM.
    Try forcing $PLATFORMLIBDIR in CuisVM.app/Contents/Linux-x86_64/squeak, based on LIBC_SO.
    

    TODO: Where is the new image saved?

  • Create a bundle for macOS by entering ./CuisApp/build/makeBundle.sh --package mac

  • Create a bundle for Windows by entering ./CuisApp/build/makeBundle.sh --package windows

  • Create a bundle for GNU Linux by entering ./CuisApp/build/makeBundle.sh --package gnulinux

To run a bundle … TODO: Where is it saved?