blob: 6afd0e861108d66a0cdae0e7ae38e483f850b10d [file] [log] [blame]
Fumitoshi Ukai119dc912015-03-30 16:52:41 +09001package main
2
3import (
Shinichiro Hamajib0f65482015-04-16 18:28:05 +09004 "bytes"
Fumitoshi Ukai119dc912015-03-30 16:52:41 +09005 "fmt"
Shinichiro Hamajib0f65482015-04-16 18:28:05 +09006 "io"
Fumitoshi Ukai119dc912015-03-30 16:52:41 +09007 "os"
Shinichiro Hamajib0f65482015-04-16 18:28:05 +09008 "path/filepath"
9 "strings"
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +090010 "sync"
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090011)
12
13type Executor struct {
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +090014 rules map[string]*Rule
15 implicitRules []*Rule
Shinichiro Hamaji20a43762015-04-02 02:42:25 +090016 suffixRules map[string][]*Rule
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +090017 firstRule *Rule
Shinichiro Hamaji89551c92015-04-11 19:33:03 +090018 shell string
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +090019 vars Vars
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +090020 varsLock sync.Mutex
Shinichiro Hamaji74a66002015-04-27 16:42:30 +090021 // target -> Job, nil means the target is currently being processed.
22 done map[string]*Job
23
24 wm *WorkerManager
Shinichiro Hamaji110af332015-04-13 19:04:50 +090025
Shinichiro Hamajib0f65482015-04-16 18:28:05 +090026 currentOutput string
27 currentInputs []string
28 currentStem string
29
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +090030 trace []string
31 buildCnt int
32 alreadyDoneCnt int
33 noRuleCnt int
34 upToDateCnt int
35 runCommandCnt int
Shinichiro Hamaji110af332015-04-13 19:04:50 +090036}
37
38type AutoVar struct{ ex *Executor }
39
40func (v AutoVar) Flavor() string { return "undefined" }
41func (v AutoVar) Origin() string { return "automatic" }
42func (v AutoVar) IsDefined() bool { panic("not implemented") }
43func (v AutoVar) String() string { panic("not implemented") }
Shinichiro Hamajiea170b12015-04-15 10:02:33 +090044func (v AutoVar) Append(*Evaluator, string) Var {
45 panic("must not be called")
46}
47func (v AutoVar) AppendVar(*Evaluator, Var) Var {
Shinichiro Hamaji110af332015-04-13 19:04:50 +090048 panic("must not be called")
49}
Shinichiro Hamajic8bc7312015-04-28 02:48:03 +090050func (v AutoVar) Serialize() SerializableVar {
51 panic(fmt.Sprintf("cannot serialize auto var: %q", v))
52}
Shinichiro Hamaji723f56a2015-05-15 17:12:55 +090053func (v AutoVar) Dump(w io.Writer) {
54 panic(fmt.Sprintf("cannot dump auto var: %q", v))
55}
Shinichiro Hamaji110af332015-04-13 19:04:50 +090056
57type AutoAtVar struct{ AutoVar }
58
59func (v AutoAtVar) Eval(w io.Writer, ev *Evaluator) {
60 fmt.Fprint(w, v.ex.currentOutput)
61}
62
63type AutoLessVar struct{ AutoVar }
64
65func (v AutoLessVar) Eval(w io.Writer, ev *Evaluator) {
66 if len(v.ex.currentInputs) > 0 {
67 fmt.Fprint(w, v.ex.currentInputs[0])
68 }
69}
70
71type AutoHatVar struct{ AutoVar }
72
73func (v AutoHatVar) Eval(w io.Writer, ev *Evaluator) {
Shinichiro Hamajia622c5e2015-04-13 19:09:30 +090074 var uniqueInputs []string
75 seen := make(map[string]bool)
76 for _, input := range v.ex.currentInputs {
77 if !seen[input] {
78 seen[input] = true
79 uniqueInputs = append(uniqueInputs, input)
80 }
81 }
82 fmt.Fprint(w, strings.Join(uniqueInputs, " "))
83}
84
85type AutoPlusVar struct{ AutoVar }
86
87func (v AutoPlusVar) Eval(w io.Writer, ev *Evaluator) {
Shinichiro Hamaji110af332015-04-13 19:04:50 +090088 fmt.Fprint(w, strings.Join(v.ex.currentInputs, " "))
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090089}
90
Shinichiro Hamajibb9772d2015-04-13 21:41:22 +090091type AutoStarVar struct{ AutoVar }
92
93func (v AutoStarVar) Eval(w io.Writer, ev *Evaluator) {
94 // TODO: Use currentStem. See auto_stem_var.mk
95 fmt.Fprint(w, stripExt(v.ex.currentOutput))
96}
97
Shinichiro Hamajiee8b33c2015-04-13 20:08:38 +090098type AutoSuffixDVar struct {
99 AutoVar
100 v Var
101}
102
103func (v AutoSuffixDVar) Eval(w io.Writer, ev *Evaluator) {
104 var buf bytes.Buffer
105 v.v.Eval(&buf, ev)
106 for i, tok := range splitSpaces(buf.String()) {
107 if i > 0 {
108 w.Write([]byte{' '})
109 }
110 fmt.Fprint(w, filepath.Dir(tok))
111 }
112}
113
114type AutoSuffixFVar struct {
115 AutoVar
116 v Var
117}
118
119func (v AutoSuffixFVar) Eval(w io.Writer, ev *Evaluator) {
120 var buf bytes.Buffer
121 v.v.Eval(&buf, ev)
122 for i, tok := range splitSpaces(buf.String()) {
123 if i > 0 {
124 w.Write([]byte{' '})
125 }
126 fmt.Fprint(w, filepath.Base(tok))
127 }
128}
129
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900130// TODO(ukai): use time.Time?
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900131func getTimestamp(filename string) int64 {
132 st, err := os.Stat(filename)
133 if err != nil {
134 return -2
135 }
136 return st.ModTime().Unix()
137}
138
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900139func (ex *Executor) makeJobs(n *DepNode, neededBy *Job) error {
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900140 output := n.Output
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900141 if neededBy != nil {
142 Log("MakeJob: %s for %s", output, neededBy.n.Output)
143 }
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +0900144 ex.buildCnt++
145 if ex.buildCnt%100 == 0 {
146 ex.reportStats()
147 }
148
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900149 j, present := ex.done[output]
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900150
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900151 if present {
152 if j == nil {
153 if !n.IsPhony {
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +0900154 fmt.Printf("Circular %s <- %s dependency dropped.\n", neededBy.n.Output, n.Output)
155 }
156 if neededBy != nil {
157 neededBy.numDeps--
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900158 }
Shinichiro Hamajieb4da7f2015-04-11 20:28:54 +0900159 } else {
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +0900160 Log("%s already done: %d", j.n.Output, j.outputTs)
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900161 if neededBy != nil {
Shinichiro Hamaji55c50bd2015-04-27 21:05:47 +0900162 ex.wm.ReportNewDep(j, neededBy)
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900163 }
Shinichiro Hamajieb4da7f2015-04-11 20:28:54 +0900164 }
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900165 return nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900166 }
Shinichiro Hamaji4e9ab1a2015-04-12 01:31:58 +0900167
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900168 j = &Job{
169 n: n,
170 ex: ex,
171 numDeps: len(n.Deps),
172 depsTs: int64(-1),
173 }
174 if neededBy != nil {
175 j.parents = append(j.parents, neededBy)
176 }
177
178 ex.done[output] = nil
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +0900179 // We iterate n.Deps twice. In the first run, we may modify
180 // numDeps. There will be a race if we do so after the first
181 // ex.makeJobs(d, j).
182 var deps []*DepNode
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900183 for _, d := range n.Deps {
184 if d.IsOrderOnly && exists(d.Output) {
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900185 j.numDeps--
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +0900186 continue
187 }
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +0900188 deps = append(deps, d)
189 }
Shinichiro Hamaji8e4dd9d2015-05-15 00:04:44 +0900190 Log("new: %s (%d)", j.n.Output, j.numDeps)
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +0900191
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +0900192 for _, d := range deps {
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900193 ex.trace = append(ex.trace, d.Output)
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900194 err := ex.makeJobs(d, j)
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +0900195 ex.trace = ex.trace[0 : len(ex.trace)-1]
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +0900196 if err != nil {
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900197 return err
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +0900198 }
199 }
200
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900201 ex.done[output] = j
202 ex.wm.PostJob(j)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900203
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900204 return nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900205}
206
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +0900207func (ex *Executor) reportStats() {
208 if !katiLogFlag && !katiStatsFlag {
209 return
210 }
211
212 LogStats("build=%d alreadyDone=%d noRule=%d, upToDate=%d runCommand=%d",
213 ex.buildCnt, ex.alreadyDoneCnt, ex.noRuleCnt, ex.upToDateCnt, ex.runCommandCnt)
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +0900214 if len(ex.trace) > 1 {
215 LogStats("trace=%q", ex.trace)
216 }
217}
218
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900219func NewExecutor(vars Vars) *Executor {
220 ex := &Executor{
221 rules: make(map[string]*Rule),
222 suffixRules: make(map[string][]*Rule),
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900223 done: make(map[string]*Job),
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900224 vars: vars,
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900225 wm: NewWorkerManager(),
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900226 }
Shinichiro Hamajib0f65482015-04-16 18:28:05 +0900227 // TODO: We should move this to somewhere around evalCmd so that
228 // we can handle SHELL in target specific variables.
229 shellVar := ex.vars.Lookup("SHELL")
230 ex.shell = shellVar.String()
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900231 for k, v := range map[string]Var{
232 "@": AutoAtVar{AutoVar: AutoVar{ex: ex}},
233 "<": AutoLessVar{AutoVar: AutoVar{ex: ex}},
234 "^": AutoHatVar{AutoVar: AutoVar{ex: ex}},
235 "+": AutoPlusVar{AutoVar: AutoVar{ex: ex}},
236 "*": AutoStarVar{AutoVar: AutoVar{ex: ex}},
237 } {
238 ex.vars[k] = v
239 ex.vars[k+"D"] = AutoSuffixDVar{v: v}
240 ex.vars[k+"F"] = AutoSuffixFVar{v: v}
241 }
Shinichiro Hamaji8843a052015-04-13 16:46:56 +0900242 return ex
243}
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900244
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900245func (ex *Executor) Exec(roots []*DepNode) error {
246 for _, root := range roots {
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900247 ex.makeJobs(root, nil)
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900248 }
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900249 ex.wm.Wait()
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900250 return nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900251}
Shinichiro Hamajib41fd502015-04-29 03:34:07 +0900252
253func (ex *Executor) createRunners(n *DepNode, avoidIO bool) ([]runner, bool) {
254 var restores []func()
255 defer func() {
Shinichiro Hamajid7044b12015-05-14 17:37:32 +0900256 for i := len(restores) - 1; i >= 0; i-- {
257 restores[i]()
Shinichiro Hamajib41fd502015-04-29 03:34:07 +0900258 }
259 }()
260
261 ex.varsLock.Lock()
262 restores = append(restores, func() { ex.varsLock.Unlock() })
263 // For automatic variables.
264 ex.currentOutput = n.Output
265 ex.currentInputs = n.ActualInputs
266 for k, v := range n.TargetSpecificVars {
267 restores = append(restores, ex.vars.save(k))
268 ex.vars[k] = v
269 }
270
271 ev := newEvaluator(ex.vars)
272 ev.avoidIO = avoidIO
273 ev.filename = n.Filename
274 ev.lineno = n.Lineno
275 var runners []runner
276 Log("Building: %s cmds:%q", n.Output, n.Cmds)
277 r := runner{
278 output: n.Output,
279 echo: true,
280 shell: ex.shell,
281 }
282 for _, cmd := range n.Cmds {
283 for _, r := range evalCmd(ev, r, cmd) {
284 if len(r.cmd) != 0 {
285 runners = append(runners, r)
286 }
287 }
288 }
289 return runners, ev.hasIO
290}
291
292func EvalCommands(nodes []*DepNode, vars Vars) {
293 ioCnt := 0
294 ex := NewExecutor(vars)
295 for i, n := range nodes {
296 runners, hasIO := ex.createRunners(n, true)
297 if hasIO {
298 ioCnt++
Shinichiro Hamajicedc5c82015-05-13 17:03:20 +0900299 if ioCnt%100 == 0 {
Shinichiro Hamajib41fd502015-04-29 03:34:07 +0900300 LogStats("%d/%d rules have IO", ioCnt, i+1)
301 }
302 continue
303 }
304
305 n.Cmds = []string{}
306 n.TargetSpecificVars = make(Vars)
307 for _, r := range runners {
308 cmd := r.cmd
309 // TODO: Do not preserve the effect of dryRunFlag.
310 if r.echo {
311 cmd = "@" + cmd
312 }
313 if r.ignoreError {
314 cmd = "-" + cmd
315 }
316 n.Cmds = append(n.Cmds, cmd)
317 }
318 }
319
320 LogStats("%d/%d rules have IO", ioCnt, len(nodes))
321}