Tcl and Tk have regular builds of their code as single file distributions. You currently (2022-06-15) need a Github login to access the results (due to anti-bot measures by Github). The builds are processed using Github's infrastructure and do things like running the test suite in lots of configurations, but we're interested on this page in the distribution building code:
Tcl's is here: https://github.com/tcltk/tcl/blob/main/.github/workflows/onefiledist.yml
Tk's is here: https://github.com/tcltk/tk/blob/main/.github/workflows/onefiledist.yml
They use the Github workflow format (which is YAML following a particular schema). Of interest at the top is this:
on: [push]
which says "build whenever a new push to the git repository is done" (which is usually daily when we synch from core.tcl-lang.org). More info about workflow triggers is here .
Then there's one actual workflow job per platform (doesn't have to be like that, but it's mighty convenient). Jobs contain a bunch of steps; the workflow succeeds when all the steps for all the jobs succeed. Success of a shell-scripted step is the usual Unix shell definition.
Let's look at the stages for building Tcl for Linux:
- name: Checkout uses: actions/checkout@v3
The "Checkout" stage just grabs the code from the Tcl repository (which repo is implicit in the workflow; Github knows that it is being run for the repo).
- name: Prepare run: | touch generic/tclStubInit.c generic/tclOOStubInit.c mkdir 1dist echo "VER_PATH=$(cd tools; pwd)/addVerToFile.tcl" >> $GITHUB_ENV working-directory: .
The "Prepare" step sets some stuff up by running a small shell script. The addVertoFile.tcl script is in the tools directory; we're storing the path to it in the multi-step shared environment so that we can find it easily.
- name: Configure run: ./configure --disable-symbols --disable-shared --enable-zipfs working-directory: unix
The "Configure" step runs the configure script in the unix directory. We're making a release build (no symbols) that is static (single file distributions should be this) and includes zipfs (I think that's enabled by default, but might as well be explicit as we definitely want it!)
- name: Build run: | make tclsh make shell SCRIPT="$VER_PATH $GITHUB_ENV" echo "TCL_ZIP=`pwd`/`echo libtcl*.zip`" >> $GITHUB_ENV working-directory: unix
The "Build" step does the build. In particular, we make tclsh, then call our addVerToFile.tcl script from earlier to add the real version data into the environment. Finally, we locate the library zip file (produced normally in the build) so that we can also find that easily later.
After this step, the environment contains definitions for:
We don't actually need TCL_ZIP for this build. Probably because the makefiles have gained smarts that used to be held externally. That's good.
- name: Package run: | cp ../unix/tclsh tclsh${TCL_PATCHLEVEL}_snapshot chmod +x tclsh${TCL_PATCHLEVEL}_snapshot tar -cf tclsh${TCL_PATCHLEVEL}_snapshot.tar tclsh${TCL_PATCHLEVEL}_snapshot working-directory: 1dist
The "Package" step (which works in its own directory) copies the tclsh, marks it as executable, and parcels it up into a TAR file (because that keeps the executable bit). We don't bother compressing it; the compression gains are going to be small (and Github's internal infrastructure compresses things anyway).
- name: Upload uses: actions/upload-artifact@v3 with: name: Tclsh ${{ env.TCL_PATCHLEVEL }} Linux single-file build (snapshot) path: 1dist/*.tar
The "Upload" step takes the built and packaged executable and ships it to the Github artifact distribution system. If we were to want to put the builds elsewhere, this is the step that would change.
Other platforms follow a very similar model, but with different details. The packaging step for macOS is particularly messy because we need to create a .dmg file, but the mess is pretty much localized to just there (and the "Prepare" step).
Any application of signatures would be done either during the "Package" step or as another step immediately afterwards. Code signing is very platform-specific (and isn't usually done for a simple TAR file distribution or single-executable distribution on Linux; it tends to be more the reserve of .rpm or .apt files, but those have a different set of intended consumers).
Tk follows a similar model, but there's a few more steps to get things right (because Tk depends on more things than Tcl).