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.exeEF 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

