configdef

configdef is a simple but versatile configuration utility for Tcl developers, extension writers in particular. While it can be effectively used in non-Tcl projects, configdef is not intended as a general purpose configuration system like Gnu configure or cmake.

configdef has the advantage that it works on any platform capable of running Tcl (that is, nearly all systems) and doesn't rely on shell scripts to generate Makefiles. Because it's written in Tcl, configdef capabilities can readily be extended with standard Tcl.

Availability:

Fossil repo: https://thinairarts.com/fossil/configdef/index
Download: https://thinairarts.com/fossil/configdef/download
Documentation: https://thinairarts.com/fossil/configdef/file?name=doc/configdef-doc.html

Installation:

The repo bin directory contains binaries for Linux and Windows, including config and genPkgIndex (Linux), or config.exe and genPkgIndex.exe (Windows). Copy the Linux or Windows files to a directory on the executable path.

Running on other platforms requires generating binaries from source. This is straightforward to accomplish--follow the steps described in the project documentation.

Using configdef

A config.def file is a template for generating a Makefile. Templates are per-directory, that is, specific to contents of a particular directory. Normally each configurable directory has its own config.def.

Running the supplied config utility in a directory with a config.def generates a Makefile according to template information. The resulting Makefile is compatible with Gnu make. Other make utilities may work depending on compatibility with Gnu Makefile syntax.

A config.def file is a completely ordinary Tcl file consisting of several variables, each containing a list processed by config to form part of the output Makefile.

The project documentation contains detailed info about the config.def format and usage.

Here's a config.def fragment and resulting Makefile.

    # config.def

    # Defaults var contains a list of global variables and values. 
    # These variables are accessible in remaining sections
    set Defaults {
        tcldir /usr/local/tcl/tcl90b1
        tclsrc /usr/local/src/tcl/tcl90b1
        srcdir /usr/local/prog/projects/myproj/src
        srcvers 1.11
        ...
    }

    # several other Tcl variables are avaialable: tclver, tclstub
    # tclbin, tclsh, tcllib, tclinc. Can be overridden on config 
    # command line
    # Some variables are predefined, e.g., OBJEXT=.o|.obj|etc.
    # The left hand member of each list pair becomes a Makefile
    # variable of the form TCLDIR = ...
    set DEFINES {
        tcldir $tcldir
        tclsrc $tclsrc
        src {[expr {$srcvers eq "1.11" ? "\$(SRCDIR)/1.11" : "\$(SRCDIR)/1.10"}]}
        objs {f1.\$(OBJEXT) f2.\$(OBJEXT)}
        ...
    }

    # [stdrecp] ("standard recipe") substitution ->
    #   "$(CC) $(CFLAGS) -c $< -o $@"
    # 
    set RULES {
        prog.$(EXT) {$(OBJS)} {
            {$(CC) -o $@ $(OBJS)}
        }
        f1.$(OBJEXT) {f1.c f1.h} {
            {$(CC) -o $@ -c $<}
        }
        f2.$(OBJEXT) {f2.c f2.h} {[stdrecp]} 

        ...
    }

Generated Makefile

    # Makefile

    # these variables are auto generated--can be overridden on
    # config command line, e.g.:
    #   config cc=clang
    CC = gcc
    LIBEXT = so
    OBJEXT = o
    EXE = 

    TCLDIR = /usr/local/tcl/tcl90b1
    TCLSRC = /usr/local/src/tcl/tcl90b1
    SRCDIR = /usr/local/prog/projects/myproj/src
    SRC = $(SRCDIR)/A
    OBJS = f1.o f2.o
    ...

    prog.$(EXE): $(OBJS)
        $(CC) -o $@ $(OBJS)

    f1.$(OBJEXT): f1.c f1.h
        $(CC) -o $@ -c $<

    f2.$(OBJEXT): f2.c f2.h
        $(CC) $(CFLAGS) -c $< -o $@
    ...

For "real-world" examples, the nxproc project has a number of instructive config.def files.

2024-01-29 jrapdx