diff --git a/TODO.md b/TODO.md index 6efe159..af09541 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1,6 @@ # Short-term + * Expand ${foo}. * Unit tests. * Expanding regex matches in targets. * Dummy rule for multiple explicit targets @@ -14,7 +15,4 @@ * An attribute to demand n processors for a particular rule. This way resource hog rules can be run on their own without disabling parallel make. - * A switch that prints the rules that will be executed and prompts to user - to do so. I often find myself doing `mk -n` before `mk` to make sure my - rules aren't bogus. diff --git a/graph.go b/graph.go index 9fa13f0..b6a4571 100644 --- a/graph.go +++ b/graph.go @@ -29,6 +29,7 @@ type nodeStatus int const ( nodeStatusReady nodeStatus = iota nodeStatusStarted + nodeStatusNop nodeStatusDone nodeStatusFailed ) diff --git a/mk.go b/mk.go index cfa145d..ab76fa8 100644 --- a/mk.go +++ b/mk.go @@ -90,6 +90,7 @@ func mkNode(g *graph, u *node, dryrun bool) { wd, _ := os.Getwd() mkError(fmt.Sprintf("don't know how to make %s in %s\n", u.name, wd)) } + finalstatus = nodeStatusNop return } @@ -118,17 +119,13 @@ func mkNode(g *graph, u *node, dryrun bool) { e.r.mutex.Lock() for i := range prereqs { prereqs[i].mutex.Lock() - // needs to be built? - u.updateTimestamp() - if !prereqs[i].exists || rebuildall || (u.exists && u.t.Before(prereqs[i].t)) { - switch prereqs[i].status { - case nodeStatusReady: - go mkNode(g, prereqs[i], dryrun) - fallthrough - case nodeStatusStarted: - prereqs[i].listeners = append(prereqs[i].listeners, prereqstat) - pending++ - } + switch prereqs[i].status { + case nodeStatusReady: + go mkNode(g, prereqs[i], dryrun) + fallthrough + case nodeStatusStarted: + prereqs[i].listeners = append(prereqs[i].listeners, prereqstat) + pending++ } prereqs[i].mutex.Unlock() } @@ -143,13 +140,36 @@ func mkNode(g *graph, u *node, dryrun bool) { } } + uptodate := true + if !e.r.attributes.virtual { + u.updateTimestamp() + if u.exists { + for i := range prereqs { + if u.t.Before(prereqs[i].t) || prereqs[i].status == nodeStatusDone { + uptodate = false + } + } + } else { + uptodate = false + } + } else { + uptodate = false + } + + if rebuildall { + uptodate = false + } + // execute the recipe, unless the prereqs failed - if finalstatus != nodeStatusFailed && len(e.r.recipe) > 0 { + if !uptodate && finalstatus != nodeStatusFailed && len(e.r.recipe) > 0 { reserveSubproc() if !dorecipe(u.name, u, e, dryrun) { finalstatus = nodeStatusFailed } + u.updateTimestamp() finishSubproc() + } else if finalstatus != nodeStatusFailed { + finalstatus = nodeStatusNop } }