**tclmake 2022, v. 2.0** [SEH] 20220110 -- I've done some refurbishing of the original tclmake code released as part of the [https://ptolemy.berkeley.edu/%|%Ptolemy] project at Berkeley, and added some new features. The new code can be found at: [https://github.com/TclLab/tclmake] tclmake is not meant to be a clone of standard make, but it borrows many features and adds a few useful features of its own. Anyone with experience using standard make should find it easy to pick up and use tclmake. If you've ever struggled with writing a GNU makefile and thought, 'this would go a lot easier if I could write the update logic in Tcl', then tclmake may be the tool for you. What a tclmake makefile looks like: MAKE_INIT = make_init SDX = lib/sdx.kit RUNTIME = bin/basekit proc make_init {} { set ::env(PATH) $::env(PATH):[file norm ~/bin] } --test-wrap : set target "$!" if {![file exists $target]} return set vfs [file root $target].vfs lassign [exec basekit $(SDX) version $target] date time version lassign [exec basekit $(SDX) version $vfs] vfsdate vfstime vfsversion MAKE_UPDATE $target [list $version ne $vfsversion] %.kit : %.vfs --test-wrap puts "Wrapping $@:" exec basekit $(SDX) wrap "$@" -vfs "$<" $(WRAP_OPTIONS) %.exe : %.kit if {"$(RUNTIME)" eq ""} { error "Make variable RUNTIME must be defined to make starpack." } puts "Wrapping $@:" set vfs [file root "$@"].vfs exec basekit $(SDX) wrap "$@" -vfs $vfs -runtime "$(RUNTIME)" $(WRAP_OPTIONS) Like GNU make, tclmake features simple and pattern rules with targets and prerequisites, make variables and automatic variables with values inserted by macro substitution. tclmake can be used as a stand-alone command line program, or as a package within another Tcl project. tclmake allows you to define Tcl procs in the makefile, allowing you to organize complex update logic within your makefile. You can define a 'MAKE_INIT' make variable to contain a Tcl script. If the variable exists after the makefile has been parsed but before updating of targets begins, this script will be evaluated. The script can for example change directories, load packages or otherwise initialize the environment. The procedure MAKE_UPDATE is available to be called by any Tcl script in the makefile. It takes two arguments: a target name and a conditional expression. If the conditional evaluates to true, the update script of the specified target is run regardless of whether the target is out of date with respect to its prerequisites. If the expression is false, the target will not be updated even if it is out of date. The MAKE_UPDATE proc allows you to define any criteria for updating a target, beyond simply comparing file modification times. If MAKE_UPDATE is called in the script of one of the target's prerequisites, when prerequisite updating is done and it's time for the target to be updated, the target's update script will be run or not based on the result of the MAKE_UPDATE conditional. The example makefile above shows rules for wrapping a starkit and creating a starpack. If you want to know if a wrapped starkit needs to be updated from its unwrapped counterpart, you need to know if any file in the unwrapped starkit has changed. In a standard GNU makefile, you'd have to include all files in the unwrapped starkit as dependencies, and ensure this list of files remains current as your starkit is developed. Fortunately the sdx package includes a command to create a version stamp for a starkit, which operates identically on a wrapped and an unwrapped starkit. The option rule '--test-wrap' generates version stamps for a wrapped and unwrapped starkit, and the MAKE_UPDATE proc is used to compare the version stamps and mark if the wrapped starkit needs to be regenerated. ---- Version 1.0 released 1998: Author: John Reekie Contact: John Reekie atatat uts dot edu dot au [http://ptolemy.eecs.berkeley.edu/%7Ejohnr/archives/code/tclmake/%|%Tclmake] ---- [AM] After some initial struggles to get it to work, I managed to create an intriguing little makefile. To give some context: * I used a Github package https://github.com/WarrenWeckesser/dde_solver/ that contains a Fortran module in the main directory and a bunch of examples in the subdirectory `examples`. * Rather than write out the names of the examples in a makefile, I used [[glob]] to find the names of the individual source files and then the rule definitons that tclmake supports to automatically build all the examples. The result is this minimalistic makefile in the tclmake style: ====== # makefile for "DDE_SOLVER" module and its examples SOURCES = [glob examples/*.f90] EXES = [string map {.f90 .exe} $(SOURCES)] %.exe : %.f90 dde_solver_m.o gfortran -o $@ $< dde_solver_m.o all: {*}$(EXES) puts $(SOURCES) dde_solver_m.o : dde_solver_m.f90 gfortran -o $@ $< dde_solver_m.o ====== Note the list expansion in the "all" target. It took a bit of experimentation (as I am a trifle rusty on my make skills), but it works. You could go on with parametrising the stuff (.exe and .o and the name of the compiler), but for a first not-so-trivial makefile this does well enough. <> Application | Dev. Tools | make