proc file.newer? {f _than_ f2} { if {![file exists $f] || ![file exists $f2]} { return 1 } if {[file mtime $f] > [file mtime $f2]} { return 1 } return 0 } proc is.file? f { return [file isfile $f] } proc is.target? t { return [info exists ::targetAr($t)] } array set ::targetAr {} proc make {t _from_ fromList _using_ body} { set ::targetAr($t) [list $fromList $body] interp alias {} $t {} make.target $t } proc make.target t { if {[is.target? $t]} { foreach {fromList body} [set ::targetAr($t)] break set build 0 foreach f $fromList { if {[is.target? $f]} { set r [make.target $f] if {[is.file? $f] && [file.newer? $f than $t]} { set build 1 } elseif {$r} { set build 1 } } elseif {[is.file? $f]} { if {!$build} { set build [file.newer? $f than $t] } } else { return -code error "$f isn't a target or existing source" } } if {$build} { uplevel #0 $body return 1 } return 0 } else { return -code error "make.target called with an invalid target: $t" } } proc mexec args { set cmd [join $args] puts $cmd catch {eval exec -- $cmd} msg if {[string length $msg]} { puts $msg } }We will now give examples of usage.It's quite easy to use, and everything is evaluated in level 0 (global). It passes all of these tests for me. You can play around with the touch command to see that it properly generates targets when needed.
set ::CC gcc set ::CFLAGS "-Wall -W" make test_2.o from test_2.c using { mexec $CC $CFLAGS -c test_2.c } make test_lib.a from [list test_2.o test_3.c] using { mexec $CC $CFLAGS -c test_3.c mexec ar cr test_lib.a test_2.o test_3.o mexec ranlib test_lib.a } make a.exe from [list test_1.c test_lib.a] using { mexec $CC $CFLAGS test_1.c test_lib.a -o a.exe } proc main {} { if {0 == $::argc} { a.exe } elseif {1 == $::argc} { eval [lindex $::argv 0] } else { return -code error "invalid number of arguments: $::argv0 ?target?" } } mainYou can also use targets and sources with directory paths like so:
make tdir/a.exe from [list tdir/test_1.c tdir/test_2.c tdir/test_3.c] using { set d tdir exec gcc $d/test_1.c $d/test_2.c $d/test_3.c -o $d/a.exe } tdir/a.exe
EF The code above has served as the basis for my make library http://www.sics.se/~emmanuel/?Code:make. I only have added the possibility to force the execution of some rules using make.force. The code is part of the library.
See also: smake, bras