blob: c419be13aa88b9f3e0c10ff4a3bb2a79ef3988ea [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"
Shinichiro Hamajib0f65482015-04-16 18:28:05 +09007 "path/filepath"
8 "strings"
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +09009 "sync"
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090010)
11
12type Executor struct {
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +090013 rules map[string]*Rule
14 implicitRules []*Rule
Shinichiro Hamaji20a43762015-04-02 02:42:25 +090015 suffixRules map[string][]*Rule
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +090016 firstRule *Rule
Shinichiro Hamaji89551c92015-04-11 19:33:03 +090017 shell string
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +090018 vars Vars
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +090019 varsLock sync.Mutex
Shinichiro Hamaji74a66002015-04-27 16:42:30 +090020 // target -> Job, nil means the target is currently being processed.
21 done map[string]*Job
22
23 wm *WorkerManager
Shinichiro Hamaji110af332015-04-13 19:04:50 +090024
Shinichiro Hamajib0f65482015-04-16 18:28:05 +090025 currentOutput string
26 currentInputs []string
27 currentStem string
28
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +090029 trace []string
30 buildCnt int
31 alreadyDoneCnt int
32 noRuleCnt int
33 upToDateCnt int
34 runCommandCnt int
Shinichiro Hamaji110af332015-04-13 19:04:50 +090035}
36
37type AutoVar struct{ ex *Executor }
38
39func (v AutoVar) Flavor() string { return "undefined" }
40func (v AutoVar) Origin() string { return "automatic" }
41func (v AutoVar) IsDefined() bool { panic("not implemented") }
42func (v AutoVar) String() string { panic("not implemented") }
Shinichiro Hamajiea170b12015-04-15 10:02:33 +090043func (v AutoVar) Append(*Evaluator, string) Var {
44 panic("must not be called")
45}
46func (v AutoVar) AppendVar(*Evaluator, Var) Var {
Shinichiro Hamaji110af332015-04-13 19:04:50 +090047 panic("must not be called")
48}
Shinichiro Hamajic8bc7312015-04-28 02:48:03 +090049func (v AutoVar) Serialize() SerializableVar {
50 panic(fmt.Sprintf("cannot serialize auto var: %q", v))
51}
Shinichiro Hamaji723f56a2015-05-15 17:12:55 +090052func (v AutoVar) Dump(w io.Writer) {
53 panic(fmt.Sprintf("cannot dump auto var: %q", v))
54}
Shinichiro Hamaji110af332015-04-13 19:04:50 +090055
56type AutoAtVar struct{ AutoVar }
57
58func (v AutoAtVar) Eval(w io.Writer, ev *Evaluator) {
59 fmt.Fprint(w, v.ex.currentOutput)
60}
61
62type AutoLessVar struct{ AutoVar }
63
64func (v AutoLessVar) Eval(w io.Writer, ev *Evaluator) {
65 if len(v.ex.currentInputs) > 0 {
66 fmt.Fprint(w, v.ex.currentInputs[0])
67 }
68}
69
70type AutoHatVar struct{ AutoVar }
71
72func (v AutoHatVar) Eval(w io.Writer, ev *Evaluator) {
Shinichiro Hamajia622c5e2015-04-13 19:09:30 +090073 var uniqueInputs []string
74 seen := make(map[string]bool)
75 for _, input := range v.ex.currentInputs {
76 if !seen[input] {
77 seen[input] = true
78 uniqueInputs = append(uniqueInputs, input)
79 }
80 }
81 fmt.Fprint(w, strings.Join(uniqueInputs, " "))
82}
83
84type AutoPlusVar struct{ AutoVar }
85
86func (v AutoPlusVar) Eval(w io.Writer, ev *Evaluator) {
Shinichiro Hamaji110af332015-04-13 19:04:50 +090087 fmt.Fprint(w, strings.Join(v.ex.currentInputs, " "))
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090088}
89
Shinichiro Hamajibb9772d2015-04-13 21:41:22 +090090type AutoStarVar struct{ AutoVar }
91
92func (v AutoStarVar) Eval(w io.Writer, ev *Evaluator) {
93 // TODO: Use currentStem. See auto_stem_var.mk
94 fmt.Fprint(w, stripExt(v.ex.currentOutput))
95}
96
Shinichiro Hamajiee8b33c2015-04-13 20:08:38 +090097type AutoSuffixDVar struct {
98 AutoVar
99 v Var
100}
101
102func (v AutoSuffixDVar) Eval(w io.Writer, ev *Evaluator) {
103 var buf bytes.Buffer
104 v.v.Eval(&buf, ev)
105 for i, tok := range splitSpaces(buf.String()) {
106 if i > 0 {
107 w.Write([]byte{' '})
108 }
109 fmt.Fprint(w, filepath.Dir(tok))
110 }
111}
112
113type AutoSuffixFVar struct {
114 AutoVar
115 v Var
116}
117
118func (v AutoSuffixFVar) Eval(w io.Writer, ev *Evaluator) {
119 var buf bytes.Buffer
120 v.v.Eval(&buf, ev)
121 for i, tok := range splitSpaces(buf.String()) {
122 if i > 0 {
123 w.Write([]byte{' '})
124 }
125 fmt.Fprint(w, filepath.Base(tok))
126 }
127}
128
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900129func (ex *Executor) makeJobs(n *DepNode, neededBy *Job) error {
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900130 output := n.Output
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900131 if neededBy != nil {
132 Log("MakeJob: %s for %s", output, neededBy.n.Output)
133 }
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +0900134 ex.buildCnt++
135 if ex.buildCnt%100 == 0 {
136 ex.reportStats()
137 }
138
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900139 j, present := ex.done[output]
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900140
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900141 if present {
142 if j == nil {
143 if !n.IsPhony {
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +0900144 fmt.Printf("Circular %s <- %s dependency dropped.\n", neededBy.n.Output, n.Output)
145 }
146 if neededBy != nil {
147 neededBy.numDeps--
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900148 }
Shinichiro Hamajieb4da7f2015-04-11 20:28:54 +0900149 } else {
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +0900150 Log("%s already done: %d", j.n.Output, j.outputTs)
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900151 if neededBy != nil {
Shinichiro Hamaji55c50bd2015-04-27 21:05:47 +0900152 ex.wm.ReportNewDep(j, neededBy)
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900153 }
Shinichiro Hamajieb4da7f2015-04-11 20:28:54 +0900154 }
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900155 return nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900156 }
Shinichiro Hamaji4e9ab1a2015-04-12 01:31:58 +0900157
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900158 j = &Job{
159 n: n,
160 ex: ex,
161 numDeps: len(n.Deps),
162 depsTs: int64(-1),
163 }
164 if neededBy != nil {
165 j.parents = append(j.parents, neededBy)
166 }
167
168 ex.done[output] = nil
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +0900169 // We iterate n.Deps twice. In the first run, we may modify
170 // numDeps. There will be a race if we do so after the first
171 // ex.makeJobs(d, j).
172 var deps []*DepNode
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900173 for _, d := range n.Deps {
174 if d.IsOrderOnly && exists(d.Output) {
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900175 j.numDeps--
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +0900176 continue
177 }
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +0900178 deps = append(deps, d)
179 }
Shinichiro Hamaji8e4dd9d2015-05-15 00:04:44 +0900180 Log("new: %s (%d)", j.n.Output, j.numDeps)
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +0900181
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +0900182 for _, d := range deps {
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900183 ex.trace = append(ex.trace, d.Output)
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900184 err := ex.makeJobs(d, j)
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +0900185 ex.trace = ex.trace[0 : len(ex.trace)-1]
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +0900186 if err != nil {
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900187 return err
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +0900188 }
189 }
190
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900191 ex.done[output] = j
192 ex.wm.PostJob(j)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900193
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900194 return nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900195}
196
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +0900197func (ex *Executor) reportStats() {
198 if !katiLogFlag && !katiStatsFlag {
199 return
200 }
201
202 LogStats("build=%d alreadyDone=%d noRule=%d, upToDate=%d runCommand=%d",
203 ex.buildCnt, ex.alreadyDoneCnt, ex.noRuleCnt, ex.upToDateCnt, ex.runCommandCnt)
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +0900204 if len(ex.trace) > 1 {
205 LogStats("trace=%q", ex.trace)
206 }
207}
208
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900209func NewExecutor(vars Vars) *Executor {
210 ex := &Executor{
211 rules: make(map[string]*Rule),
212 suffixRules: make(map[string][]*Rule),
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900213 done: make(map[string]*Job),
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900214 vars: vars,
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900215 wm: NewWorkerManager(),
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900216 }
Shinichiro Hamajib0f65482015-04-16 18:28:05 +0900217 // TODO: We should move this to somewhere around evalCmd so that
218 // we can handle SHELL in target specific variables.
219 shellVar := ex.vars.Lookup("SHELL")
220 ex.shell = shellVar.String()
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900221 for k, v := range map[string]Var{
222 "@": AutoAtVar{AutoVar: AutoVar{ex: ex}},
223 "<": AutoLessVar{AutoVar: AutoVar{ex: ex}},
224 "^": AutoHatVar{AutoVar: AutoVar{ex: ex}},
225 "+": AutoPlusVar{AutoVar: AutoVar{ex: ex}},
226 "*": AutoStarVar{AutoVar: AutoVar{ex: ex}},
227 } {
228 ex.vars[k] = v
229 ex.vars[k+"D"] = AutoSuffixDVar{v: v}
230 ex.vars[k+"F"] = AutoSuffixFVar{v: v}
231 }
Shinichiro Hamaji8843a052015-04-13 16:46:56 +0900232 return ex
233}
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900234
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900235func (ex *Executor) Exec(roots []*DepNode) error {
236 for _, root := range roots {
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900237 ex.makeJobs(root, nil)
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900238 }
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900239 ex.wm.Wait()
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900240 return nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900241}
Shinichiro Hamajib41fd502015-04-29 03:34:07 +0900242
243func (ex *Executor) createRunners(n *DepNode, avoidIO bool) ([]runner, bool) {
244 var restores []func()
245 defer func() {
Shinichiro Hamajid7044b12015-05-14 17:37:32 +0900246 for i := len(restores) - 1; i >= 0; i-- {
247 restores[i]()
Shinichiro Hamajib41fd502015-04-29 03:34:07 +0900248 }
249 }()
250
251 ex.varsLock.Lock()
252 restores = append(restores, func() { ex.varsLock.Unlock() })
253 // For automatic variables.
254 ex.currentOutput = n.Output
255 ex.currentInputs = n.ActualInputs
256 for k, v := range n.TargetSpecificVars {
257 restores = append(restores, ex.vars.save(k))
258 ex.vars[k] = v
259 }
260
261 ev := newEvaluator(ex.vars)
262 ev.avoidIO = avoidIO
263 ev.filename = n.Filename
264 ev.lineno = n.Lineno
265 var runners []runner
266 Log("Building: %s cmds:%q", n.Output, n.Cmds)
267 r := runner{
268 output: n.Output,
269 echo: true,
270 shell: ex.shell,
271 }
272 for _, cmd := range n.Cmds {
273 for _, r := range evalCmd(ev, r, cmd) {
274 if len(r.cmd) != 0 {
275 runners = append(runners, r)
276 }
277 }
278 }
279 return runners, ev.hasIO
280}
281
282func EvalCommands(nodes []*DepNode, vars Vars) {
283 ioCnt := 0
284 ex := NewExecutor(vars)
285 for i, n := range nodes {
286 runners, hasIO := ex.createRunners(n, true)
287 if hasIO {
288 ioCnt++
Shinichiro Hamajicedc5c82015-05-13 17:03:20 +0900289 if ioCnt%100 == 0 {
Shinichiro Hamajib41fd502015-04-29 03:34:07 +0900290 LogStats("%d/%d rules have IO", ioCnt, i+1)
291 }
292 continue
293 }
294
295 n.Cmds = []string{}
296 n.TargetSpecificVars = make(Vars)
297 for _, r := range runners {
298 cmd := r.cmd
299 // TODO: Do not preserve the effect of dryRunFlag.
300 if r.echo {
301 cmd = "@" + cmd
302 }
303 if r.ignoreError {
304 cmd = "-" + cmd
305 }
306 n.Cmds = append(n.Cmds, cmd)
307 }
308 }
309
310 LogStats("%d/%d rules have IO", ioCnt, len(nodes))
311}