configdef is a configuration utility created for Tcl developers, Tcl extension writers in particular. While configdef may also be useful in non-Tcl projects, at this point it doesn't provide the comprehensive capabilities of Gnu configure or cmake. configdef does offer simplicity, flexibility and works on any system that can run an up-to-date Tcl interpreter (which is virtually all of them).
The configdef archive contains ready-to-run binaries for Windows and Linux systems.
For other OS, or when custom features are needed, binaries can be regenerated. For such purposes it's necessary to have a statically compiled Tcl 8.7 or 9.0. This will be described in detail in a later section.
Decompress the downloaded archive in any convenient directory. Archives contain the following file structure:
+ configdef
+ bin
- config
- config.exe
- genPkgIndex
- genPkgIndex.exe
+ doc
- configdef-doc.md
- configdef-doc.pdf
+ generic
- config.tcl
- genPkgIndex.tcl
- mkconfig.tcl
- mkGenPkgIndex.tcl
- tcltkparams.tcl
+ tools
+ config8.vfs
+ config9.vfs
+ genPkgIndex8.vfs
+ genPkgIndex9.vfs
+ unix
+ win
It's only necessary to copy config and genPkgIndex (or the *.exe files) to a directory on the exec path. For unix users that's typically /usr/local/bin. Windows users might want to create a "bin" directory in their home directory and add it to their personal or system-wide path.
The config.def file describes and defines configuration options that are transformed into a usable Makefile. The syntax of this Makefile is compatible with any recent version of Gnu make.
config.def is intended to be processed by the config utility on a per directory basis. IOW every directory with configurable options will have its own config.def file. It's possible to cascade configuration such that config.def in a directory sets up or points to config.def in one or more subdirectories.
Note that config.def is a normal Tcl file and can contain additional procs, global variables or source other Tcl files as needed. The basic components are described in this section.
Vars variable contains a list of undefined variables that must be defined on the config command line. For example:
set Vars {filename}
config -filename=myfile.tcl
# if filename not supplied:
ERROR: missing input: -filename=...
Defaults variable has a list of variable+default value pairs. Variables listed here don't have to be supplied on the config command line except to override the default:
set Defaults {
tcldir c:/tcl87b1s
...
}
# global variable "tcldir" is visible in config.def
# This invocation overrides the default value:
config -tcldir=c:/tcl90b1s
helptext. Optional list of strings providing help for mandatory arguments to config. (As described above re: Vars.) These strings are displayed when config -help
is called.
helptext_optional. Optional list of strings with help text for optional params to config. Optional params correspond to variables given under Defaults.
DEFINES. The DEFINES variable contains a list of variable/value pairs. Here the first member of the pair becomes a Makefile variable and the second is the value.
set DEFINES {
tclinc $tclinc
tcllib $tcllib
...
}
# in the Makefile:
TCLINC = c:/tcl87b1/include
TCLLIB = c:/tcl87b1/lib
...
When there are several Makefile variables to initialize it's convenient to use this special syntax:
set DEFINES {
* {tclinc tcllib tclsrc ...}
...
}
The output is identical to the prior example.
configdef provides a large number of Tcl-related variables automatically when "tcldir" or "tclsrc" is specified in Defaults or on the config command line. ("tcldir" is the directory where Tcl is installed, "tclsrc" is the Tcl source directory. Similarly, Tk variables are generated when "tkdir" and "tksrc" are provided.)
DEFINES don't have to be predefined in Defaults. It's quite possible and often useful to create values for arbitrary variables. DEFINES values can make use of the full range of Tcl facilities:
set DEFINES {
...
config_vfs {../config[string index $::tclver 0].vfs}
progs {\$(CONFIG) \$(PKGNDX)}
...
}
# Makefile:
CONFIG_VFS = ../config8.vfs
PROGS = $(CONFIG) $(PKGNDX)
Note that a value must be enclosed in {} when it contains spaces, Tcl variables or commands. Also "$" must be escaped with "\" when the $ refers to Makefile and not Tcl variables. Furthermore, values defined in Defaults or command line and used directly need not be namespace-qualified (":. However when used in a command in the value (right-hand side) then the global namespace qualifiers are necessary.
The RULES variable is slightly more complex. This variable defines Makefile rules, with each rule consisting of 3 parts: the target, list of dependencies, and a list of operations. RULES looks like this:
set RULES {
all {$(PROGS)} {
}
cfginit {} {
{rm -rf $(CONFIG_VFSLIB)}
{cp -r $(TCLLBRY) $(CONFIG_VFSLIB)}
{cp $(GEN)/config.tcl $(GEN)/tcltkparams.tcl $(CONFIG_VFS)}
}
$(CONFIG) {$(CONFIG_VFS)/config.tcl \
$(CONFIG_VFS)/tcltkparams.tcl} {
{make cfginit}
{$(TCLSH) $(GEN)/mkconfig.tcl}
}
...
}
# Makefile:
all: $(PROGS)
cfginit:
rm -rf $(CONFIG_VFSLIB)
cp -r $(TCLLBRY) $(CONFIG_VFSLIB)
cp $(GEN)/config.tcl $(GEN)/tcltkparams.tcl $(CONFIG_VFS)
$(CONFIG): $(CONFIG_VFS)/config.tcl $(CONFIG_VFS)/tcltkparams.tcl
make cfginit
$(TCLSH) $(GEN)/mkconfig.tcl
Note that the rules list is evaluated but the target and dependencies are not. Because Makefile variables are common and essential in rules, $... is not treated as a Tcl variable during configdef evaluation, except when enclosed in a Tcl command invocation:
$(MYTARGET) {<dependency list>} {
{[expr {$::my_tcl_variable ? <do something> : <do something else>}]}
{$(CC) -o $@ -c $< ...}
}
# <$my_tcl_variable> is evaluated as expected, but $(CC), etc., are ignored
As noted above, configuration can proceed from one directory to another. All that's necessary is defining a proc named "nextcfg" that takes no arguments. The proc returns a list of directories/config arguments. Each directory will be visited in turn and config arguments applied.
proc nextcfg {} {
lappend ls ../subdirA [list -tcldir=$::tcldir] \
../subdirB [list -tcllib=$::tcllib]
return $ls
}
nextcfg can make use of Defaults, procs, and other Tcl features defined in config.def, assuming that the section was already processed. For this reason, nextcfg is typically placed at the bottom of the config.def file.
configdef includes the genPkgIndex utility which unsurprisingly generates a pkgIndex.tcl file for binary extensions.
genPkgIndex takes 2 mandatory and 2 optional arguments. The syntax is as follows:
genPkgIndex(.exe) -pkgnm <package name> -pkgver <pkg version> ?-script <string>? ?-filename <output file>?
If <filename> is not given then output goes to stdout. If <script> is absent then the built-in standard pkgIndex.tcl is generated:
genPkgIndex -pkgnm mypkg -pkgver 1.1
# writes to stdout:
# if {[package vsatisfies [package provide Tcl] 9.0-]} {
# package ifneeded mypkg 1.0 [list load [file join $dir tcl9mypkg10.dll]]
# } else {
# package ifneeded mypkg 1.0 [list load [file join $ dir mypkg10.dll]]
# }
Of course, a script can be provided. The script should have embedded $pkgnm, $pkgver, $tcl9libnm and $libnm variables at the appropriate places. Otherwise $, [, ] characters must be backslash escaped.
Complete source code is included in the release archive. Generating binaries for supported platforms is pretty straightforward. The only required dependency is a statically compiled Tcl 8.7 or 9.0 tclsh. Consult the Tcl documentation for details of compiling Tcl.
If configdef sources have been modified, very likely the default config and genPkgIndex are no longer valid. To generate these files follow these steps:
As a convenience to users configdef supplies a number of Tcl global variables. These can be redefined in Defaults or DEFINES lists.
Several variables are computed by configdef that automatically appear in the Makefile.
variable | Makefile | value | (info) |
---|---|---|---|
cc | CC | gcc | |
libext | LIBEXT | dll, so | |
objext | OBJEXT | obj, o | |
exe | EXE | .exe, "" | |
starext | STAREXT | .lib, .a | (static archive extension) |
Establishing certain variables in Defaults or on the command line leads to automatically produced variables.
(Defaults) tcldir /path/to/installed_Tcl
(cmdline) -tcldir=/path/to/installed_Tcl
variable | value |
---|---|
tclbin | $tcldir/bin |
tclsh | $tcldir/bin/tclsh* |
tclinc | $tcldir/include |
tcllib | $tcldir/lib |
tclstub | $tcldir/lib/tcl*stub* |
tclver | tcl version |
(Defaults) tclsrc /path/to/Tcl_source_dir
(cmdline) -tclsrc=/path/to/Tcl_source_dir
variable | value | info |
---|---|---|
tcllbry | $tclsrc/library | |
tclobjd | $tclsrc/obj_dir | dir containing object files |
tclshsd | $tclsrc/tclsh* | tclsh (in source directory) |
tclstubsd | $tclsrc/tcl*stub* | stub (in source directory) |
tclgen | $tclsrc/generic | |
tclver | tcl version |
(Defaults) tkdir /path/to/installed_Tk
(cmdline) -tkdir=/path/to/installed_Tk
variable | value | info |
---|---|---|
tkbin | $tkdir/bin | |
tksh | $tkdir/bin/wish* | |
tkinc | $tkdir/include | |
tklib | $tkdir/lib | |
tkstub | $tkdir/lib/tk*stub* | |
tkver | Tk version |
(Defaults) tclsrc /path/to/Tk_source_dir
(cmdline) -tclsrc=/path/to/Tk_source_dir
variable | value | info |
---|---|---|
tklbry | $tksrc/library | |
tkobjd | $tksrc/obj_dir | dir containing Tk object files |
tkwishsd | $tksrc/wish* | |
tkstubsd | $tksrc/tk*stub* | |
tkgen | $tksrc/generic | |
tkver | Tk version |