Version 5 of smake musings

Updated 2003-12-03 20:57:41

2003-11-20 VI I just love smake. Mostly because I have tclsh across all the platforms I work on. I thought there was something called "Jam", but couldn't find it. In any case I like the simple smake to the more complex (and more capable) bras.

Some notes about smake follow. I have also emailed the author.

  • The documentation describes "uptarget". The command is really "upTarget", note the uppercase T
  • In the code after the depend, the variable "target" is the current target being worked on.
  • If a target doesn't exist and if all the dependencies are up-to-date, then smake doesn't run the rule, which is counterintuitive, more on this below.
  • stdout and stderr redirection on the exec doesn't work.

Hm, didn't see your email. Maybe it got mixed up in all the spam :P Will look at these issues when I have a bit of time. --Setok


When a target doesn't exist but all the dependencies are up-to-date, smake doesn't run the rule, which is counter-intuitive. e.g.

   target a {
     depend {b.o c.o} {
        link a [list b.o c.o] 
     }
   }

Here you would expect that if a doesn't exist, but b.o and c.o are up-to-date, then the link will run. That doesn't seem to happen for me (I could be just using it wrong). In any case, to fix this here's what I added:

Just before this:

    if {$update} {
        uplevel 1 $op
        uplevel 1 {set targetUpdate 1}
    }

in the proc "depend", I added this:

    if !$update {
        set thistarget [lindex $SmakeTargetPath end]
        if ![file exists $thistarget] {
            dputs 3 "Target $thistarget hasn't been made yet, update"
            set update 1
        }
    }

Hope this helps someone!

2003-11-20 VI : A possible cleaner way to do the set this target is to do it like this:

    if !$update {
        upvar target thistarget
        if ![file exists $thistarget] {
            dputs 3 "Target $thistarget hasn't been made yet, update"
            set update 1
        }
    }

2003-11-20 VI : stdout and stderr redirection doesn't work. I often write a command like

     exec grep -n Error $logfile > errors.log

smake nicely renames exec and prints the line before executing, but in this case the redirection doesn't work. To fix that, I change:

        eval "exec_old $args >@ stdout 2>@ stderr"

to just

        eval "exec_old $args"

I'm not sure why the >@ and 2>@ are there. When would it be needed?


2003-12-03 VI : I do know now why 2>@ is required. If you don't do that then the stuff printed to stderr causes the tcl exec to think that there's been an error. So like make if we want to be just return code based, then we need to add the 2>@. A naive implementation :

 proc exec {args} {
    global TCL_ERROR

    if {![regexp ">&" $args] && ![regexp "|&" $args] && ![regexp "2>" $args]} {
        append args " 2>@ stderr"
    }

    puts $args

    set rc [catch {
        eval "exec_old $args"
    } errmsg]

    if {$rc == $TCL_ERROR} {
        puts stderr "$::errorCode\n$::errorInfo"
        error $errmsg
    }
 }

I also found that sometimes I have stuff that I want to print the stuff I'm doing in Tcl to the stdout because many things that were external commands in make become internal. e.g. file mkdir. So I added another trivial proc:

 proc tcl {args} {
    puts $args
    eval $args
 }

So I can mix exec and tcl calls in my commands and everything gets printed...