TIP 495: Tcl Based Build System for TEA projects

FlightAware bounty program for improvements to Tcl and certain Tcl packages.
Author:         Sean Woods <yoda@etoyoc.com>
State:          Draft
Type:           Project
Vote:           Pending
Created:        14-Jan-2018
Keywords:       Tcl,build system,extension building
Tcl-Version:    8.7


This tip proposes that we switch extension development away from implementing automation in autoconf and nmake and towards using Tcl.


A present day application developer has to use several more languages than simply Tcl and C to develop extensions for the language. Binary packages require a developer to master autoconf, Makefile and nmake. The reference Sample extension is really only useful for very, very trivial extensions. And even there requires some knowledge of the process to do the appropriate cuttoing and pasting. Most TEA packages have no concept of how they can populate a VFS for a kit, or bundle themselves as a zip file for proper packaging in a TEAPOT.

As one of the developers in charge of fixing day to day problems in TEA, I find myself writing a lot more sh than Tcl. And most of that writing is working around limitations in the sh language itself.

SH and autoconf are not going away. We are just changing their role from "building our make system" to "finding all the platform specific quirks so that Tcl can be our make system".

The reforms to TEA are several fold, but designed in such a way that present packages can continue to use their current build systems, unmodified. New projects (or old projects that upgrade to the TEA 4 standard) will be able to utilize the new features of TEA.

The principle change is that the process of building binaries is being moved out of the Makefile and Nmake, and into a Tcl script. Vestigal batch files for each can be left which call the new mechanisms in the old way.

Instead of the prime mover for packages being:

make all

New TEA packages will use the convention of:

tclsh make.tcl all

The make.tcl file does not have to implement bread and butter compile, integration and installation functions. They will be provided by a new package "practcl" which is distributed via tcllib, after Tcl 8.7 as a core distributed package, and a version of the library will also ship in the /tclconfig directory that TEA packages include in source distributions. It is a self contained library with no external dependencies, and runs in Tcl 8.6, or 8.5 with the TclOO extension.



All Tcl extensions will have a make.tcl file. That file will contain all of the instructions needed to build, install, package, and integrate that extension.

make.tcl will accept the following commands:

  1. all - Replicate the behavior of the previous TEA system, generate a dynamic library
  2. install ?destination? - Install the package to local environment or to the optional directory
  3. teapot - Generate a .zip or .tm file containing an installation image of the package
  4. info - Return a dict containing the following information: name - The name of the project version - The version of the project teapotfile - The name of the file generated by teapot libraryfile - The name of the dynamic library static_file - The name of the static library
  5. packages - Returns a list of packages and versions of those packages this project generates
  6. dynamic - Generate a dynamic library
  7. static - Generate a static library
  8. shell - Optional - Generate an executable with the package statically linked
  9. test - Run the test suite for the package


Instead of having autoconf write all over Makefiles and pkgIndex, the new TEA performs all of its substitutions in one file: config.tcl. That file contains a key/value list readable by a Tcl script. nmake environments will perform identical subsitutions to the same file.


A standard library of tools (provisinally named "practcl") will be provided in tcllib and as a single file distribution in the same repository as the TEA reference files. (http://core.tcl.tk/tclconfig)

This library includes implementations for all build, installation, and integration tasks. The file can be directly sourced, or invoked with "package require practcl".

## Example make.tcl file

set CWD [pwd]
set ::SRCDIR   [file dirname [file normalize [info script]]]
set ::SANDBOX  [file dirname $::SRCDIR]
package require practcl

# Build and configure and object named "LIBRARY"
array set ::project [::practcl::config.tcl $CWD]
::practcl::library create LIBRARY [array get ::project]
LIBRARY define set builddir $CWD
LIBRARY define set srcdir $SRCDIR
LIBRARY meta set author {{Tcl Core}}
LIBRARY meta set license BSD
LIBRARY add [file join $::SRCDIR generic sample.c]
LIBRARY add [file join $::SRCDIR generic sample.tcl]
LIBRARY define add public-verbatim [file join $::SRCDIR generic sample.h]

# Run ./configure or nmakehlp to generate the config.tcl file
if {![LIBRARY define exists TCL_SRC_DIR]} {
  # Common interactions will have pre-canned implementations
  LIBRARY make detect

# Define a target which generates the dynamic C code
LIBRARY make add implement {
  filename sample.c
} {
  # This script evaluates with in the LIBRARY
  # object's namespace
  my go
  my implement $::project(builddir)
  set fout [open pkgIndex.tcl w]
  puts $fout [LIBRARY package-ifneeded]
  close $fout

# Define the "all" target, and create aliases for "libraries"
# and "binaries"
LIBRARY make add all {
  aliases {binaries libraries}
  depends library

# Define the "library" target
LIBRARY make add library {
  triggers implement
  filename [LIBRARY define get libfile]
} {
  puts "BUILDING [my define get libfile]"
  my build-library [my define get libfile] [self]

# Process command line
switch [lindex $argv 0] {
  install {
    # Ensure the library is compiled
    LIBRARY make depends library doc
	# Make do acts on all of the steps computed by
	# make depends
	LIBRARY make do
	# Project specific installation procedure
  info {
    # Output information that integrators need
    set dat [LIBRARY target pkginfo]
    foreach {field value} $dat {
  	  puts [list $field: $value]
	exit 0

} teapot { # Ensure the library is compiled LIBRARY make depends library LIBRARY make do # Code to generate teapot distribution } default { # Work like a makefile and trigger build targets # Unlike a standard makefile "trigger" will re-kick # off any indicated steps LIBRARY make trigger {*}$argv LIBRARY make do } }

More Info

This is a work in progress.

Details are trickling in from the Practcl project