blob: e17c1612bc5391ebc5b27fd20acf730a87e0cbef [file] [log] [blame]
Fumitoshi Ukai119dc912015-03-30 16:52:41 +09001package main
2
3import (
Shinichiro Hamajiee8b33c2015-04-13 20:08:38 +09004 "bytes"
Fumitoshi Ukai119dc912015-03-30 16:52:41 +09005 "fmt"
Shinichiro Hamaji110af332015-04-13 19:04:50 +09006 "io"
Fumitoshi Ukai119dc912015-03-30 16:52:41 +09007 "os"
8 "os/exec"
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +09009 "path/filepath"
Fumitoshi Ukai3e5161e2015-04-01 22:42:10 +090010 "strings"
Fumitoshi Ukai772fe1a2015-04-01 23:28:26 +090011 "syscall"
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090012 "time"
13)
14
15type Executor struct {
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +090016 rules map[string]*Rule
17 implicitRules []*Rule
Shinichiro Hamaji20a43762015-04-02 02:42:25 +090018 suffixRules map[string][]*Rule
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +090019 firstRule *Rule
Shinichiro Hamaji89551c92015-04-11 19:33:03 +090020 shell string
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +090021 vars Vars
Shinichiro Hamaji940bb6c2015-04-13 00:35:59 +090022 // target -> timestamp, a negative timestamp means the target is
23 // currently being processed.
Fumitoshi Ukai4b82f192015-04-07 11:36:42 +090024 done map[string]int64
Shinichiro Hamaji110af332015-04-13 19:04:50 +090025
26 currentOutput string
27 currentInputs []string
28 currentStem string
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +090029
30 trace []string
31 buildCnt int
32 alreadyDoneCnt int
33 noRuleCnt int
34 upToDateCnt int
35 runCommandCnt int
36 pickExplicitRuleCnt int
37 pickImplicitRuleCnt int
38 pickSuffixRuleCnt int
39 pickExplicitRuleWithoutCmdCnt int
Shinichiro Hamaji110af332015-04-13 19:04:50 +090040}
41
42type AutoVar struct{ ex *Executor }
43
44func (v AutoVar) Flavor() string { return "undefined" }
45func (v AutoVar) Origin() string { return "automatic" }
46func (v AutoVar) IsDefined() bool { panic("not implemented") }
47func (v AutoVar) String() string { panic("not implemented") }
Shinichiro Hamajiea170b12015-04-15 10:02:33 +090048func (v AutoVar) Append(*Evaluator, string) Var {
49 panic("must not be called")
50}
51func (v AutoVar) AppendVar(*Evaluator, Var) Var {
Shinichiro Hamaji110af332015-04-13 19:04:50 +090052 panic("must not be called")
53}
54
55type AutoAtVar struct{ AutoVar }
56
57func (v AutoAtVar) Eval(w io.Writer, ev *Evaluator) {
58 fmt.Fprint(w, v.ex.currentOutput)
59}
60
61type AutoLessVar struct{ AutoVar }
62
63func (v AutoLessVar) Eval(w io.Writer, ev *Evaluator) {
64 if len(v.ex.currentInputs) > 0 {
65 fmt.Fprint(w, v.ex.currentInputs[0])
66 }
67}
68
69type AutoHatVar struct{ AutoVar }
70
71func (v AutoHatVar) Eval(w io.Writer, ev *Evaluator) {
Shinichiro Hamajia622c5e2015-04-13 19:09:30 +090072 var uniqueInputs []string
73 seen := make(map[string]bool)
74 for _, input := range v.ex.currentInputs {
75 if !seen[input] {
76 seen[input] = true
77 uniqueInputs = append(uniqueInputs, input)
78 }
79 }
80 fmt.Fprint(w, strings.Join(uniqueInputs, " "))
81}
82
83type AutoPlusVar struct{ AutoVar }
84
85func (v AutoPlusVar) Eval(w io.Writer, ev *Evaluator) {
Shinichiro Hamaji110af332015-04-13 19:04:50 +090086 fmt.Fprint(w, strings.Join(v.ex.currentInputs, " "))
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090087}
88
Shinichiro Hamajibb9772d2015-04-13 21:41:22 +090089type AutoStarVar struct{ AutoVar }
90
91func (v AutoStarVar) Eval(w io.Writer, ev *Evaluator) {
92 // TODO: Use currentStem. See auto_stem_var.mk
93 fmt.Fprint(w, stripExt(v.ex.currentOutput))
94}
95
Shinichiro Hamajiee8b33c2015-04-13 20:08:38 +090096type AutoSuffixDVar struct {
97 AutoVar
98 v Var
99}
100
101func (v AutoSuffixDVar) Eval(w io.Writer, ev *Evaluator) {
102 var buf bytes.Buffer
103 v.v.Eval(&buf, ev)
104 for i, tok := range splitSpaces(buf.String()) {
105 if i > 0 {
106 w.Write([]byte{' '})
107 }
108 fmt.Fprint(w, filepath.Dir(tok))
109 }
110}
111
112type AutoSuffixFVar struct {
113 AutoVar
114 v Var
115}
116
117func (v AutoSuffixFVar) Eval(w io.Writer, ev *Evaluator) {
118 var buf bytes.Buffer
119 v.v.Eval(&buf, ev)
120 for i, tok := range splitSpaces(buf.String()) {
121 if i > 0 {
122 w.Write([]byte{' '})
123 }
124 fmt.Fprint(w, filepath.Base(tok))
125 }
126}
127
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900128func newExecutor(vars Vars) *Executor {
Shinichiro Hamaji110af332015-04-13 19:04:50 +0900129 ex := &Executor{
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900130 rules: make(map[string]*Rule),
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900131 suffixRules: make(map[string][]*Rule),
Fumitoshi Ukai4b82f192015-04-07 11:36:42 +0900132 done: make(map[string]int64),
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900133 vars: vars,
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900134 }
Shinichiro Hamaji110af332015-04-13 19:04:50 +0900135
Shinichiro Hamajiee8b33c2015-04-13 20:08:38 +0900136 for k, v := range map[string]Var{
137 "@": AutoAtVar{AutoVar: AutoVar{ex: ex}},
138 "<": AutoLessVar{AutoVar: AutoVar{ex: ex}},
139 "^": AutoHatVar{AutoVar: AutoVar{ex: ex}},
140 "+": AutoPlusVar{AutoVar: AutoVar{ex: ex}},
Shinichiro Hamajibb9772d2015-04-13 21:41:22 +0900141 "*": AutoStarVar{AutoVar: AutoVar{ex: ex}},
Shinichiro Hamajiee8b33c2015-04-13 20:08:38 +0900142 } {
143 ex.vars[k] = v
144 ex.vars[k+"D"] = AutoSuffixDVar{v: v}
145 ex.vars[k+"F"] = AutoSuffixFVar{v: v}
146 }
Shinichiro Hamaji110af332015-04-13 19:04:50 +0900147
148 return ex
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900149}
150
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900151// TODO(ukai): use time.Time?
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900152func getTimestamp(filename string) int64 {
153 st, err := os.Stat(filename)
154 if err != nil {
155 return -2
156 }
157 return st.ModTime().Unix()
158}
159
Fumitoshi Ukai6b378832015-04-06 16:54:37 +0900160func (ex *Executor) exists(target string) bool {
Fumitoshi Ukaif04610d2015-04-07 00:03:03 +0900161 _, present := ex.rules[target]
162 if present {
163 return true
164 }
Fumitoshi Ukai6b378832015-04-06 16:54:37 +0900165 rule, present := ex.rules[".PHONY"]
166 if present {
167 for _, input := range rule.inputs {
168 if target == input {
169 return true
170 }
171 }
172 }
173 return exists(target)
174}
175
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900176type runner struct {
177 output string
178 cmd string
179 echo bool
180 dryRun bool
181 ignoreError bool
Shinichiro Hamaji89551c92015-04-11 19:33:03 +0900182 shell string
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900183}
184
Shinichiro Hamaji973c69f2015-04-11 21:52:38 +0900185func evalCmd(ev *Evaluator, r runner, s string) []runner {
186 r = newRunner(r, s)
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900187 if strings.IndexByte(r.cmd, '$') < 0 {
188 // fast path
189 return []runner{r}
190 }
191 cmds := ev.evalExpr(r.cmd)
192 var runners []runner
193 for _, cmd := range strings.Split(cmds, "\n") {
Shinichiro Hamaji77353192015-04-13 16:04:15 +0900194 if len(runners) > 0 && strings.HasSuffix(runners[0].cmd, "\\") {
195 runners[0].cmd += "\n"
196 runners[0].cmd += cmd
197 } else {
198 runners = append(runners, newRunner(r, cmd))
199 }
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900200 }
201 return runners
202}
203
Shinichiro Hamaji973c69f2015-04-11 21:52:38 +0900204func newRunner(r runner, s string) runner {
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900205 for {
Shinichiro Hamajic88618f2015-04-11 19:58:06 +0900206 s = trimLeftSpace(s)
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900207 if s == "" {
208 return runner{}
Fumitoshi Ukai772fe1a2015-04-01 23:28:26 +0900209 }
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900210 switch s[0] {
211 case '@':
212 if !r.dryRun {
213 r.echo = false
214 }
215 s = s[1:]
216 continue
217 case '-':
218 r.ignoreError = true
219 s = s[1:]
Shinichiro Hamaji07e146b2015-04-02 16:17:24 +0900220 continue
221 }
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900222 break
223 }
224 r.cmd = s
225 return r
226}
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900227
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900228func (r runner) run() error {
229 if r.echo {
230 fmt.Printf("%s\n", r.cmd)
231 }
232 if r.dryRun {
233 return nil
234 }
Shinichiro Hamaji89551c92015-04-11 19:33:03 +0900235 args := []string{r.shell, "-c", r.cmd}
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900236 cmd := exec.Cmd{
237 Path: args[0],
238 Args: args,
239 }
240 out, err := cmd.CombinedOutput()
241 fmt.Printf("%s", out)
242 exit := exitStatus(err)
243 if r.ignoreError && exit != 0 {
244 fmt.Printf("[%s] Error %d (ignored)\n", r.output, exit)
245 err = nil
246 }
247 return err
248}
249
250func exitStatus(err error) int {
251 if err == nil {
252 return 0
253 }
254 exit := 1
255 if err, ok := err.(*exec.ExitError); ok {
256 if w, ok := err.ProcessState.Sys().(syscall.WaitStatus); ok {
257 return w.ExitStatus()
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900258 }
259 }
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900260 return exit
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900261}
262
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900263func replaceSuffix(s string, newsuf string) string {
264 // TODO: Factor out the logic around suffix rules and use
265 // it from substitution references.
266 // http://www.gnu.org/software/make/manual/make.html#Substitution-Refs
Shinichiro Hamaji5e2c3c72015-04-03 15:04:54 +0900267 return fmt.Sprintf("%s.%s", stripExt(s), newsuf)
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900268}
269
Shinichiro Hamaji0d0af5b2015-04-02 05:17:23 +0900270func (ex *Executor) canPickImplicitRule(rule *Rule, output string) bool {
271 outputPattern := rule.outputPatterns[0]
272 if !matchPattern(outputPattern, output) {
273 return false
274 }
275 for _, input := range rule.inputs {
276 input = substPattern(outputPattern, input, output)
Fumitoshi Ukai6b378832015-04-06 16:54:37 +0900277 if !ex.exists(input) {
Shinichiro Hamaji0d0af5b2015-04-02 05:17:23 +0900278 return false
279 }
280 }
281 return true
282}
283
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900284func (ex *Executor) pickRule(output string) (*Rule, bool) {
285 rule, present := ex.rules[output]
286 if present {
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +0900287 ex.pickExplicitRuleCnt++
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900288 if len(rule.cmds) > 0 {
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900289 return rule, true
290 }
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900291 // If none of the explicit rules for a target has commands,
292 // then `make' searches for an applicable implicit rule to
293 // find some commands.
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +0900294 ex.pickExplicitRuleWithoutCmdCnt++
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900295 }
296
297 for _, irule := range ex.implicitRules {
298 if !ex.canPickImplicitRule(irule, output) {
299 continue
300 }
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +0900301 ex.pickImplicitRuleCnt++
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900302 if rule != nil {
303 r := &Rule{}
304 *r = *rule
305 r.outputPatterns = irule.outputPatterns
306 // implicit rule's prerequisites will be used for $<
307 r.inputs = append(irule.inputs, r.inputs...)
308 if irule.vars != nil {
Shinichiro Hamajiea170b12015-04-15 10:02:33 +0900309 r.vars = append(r.vars, rule.vars...)
310 r.vars = append(r.vars, irule.vars...)
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900311 }
312 r.cmds = irule.cmds
313 // TODO(ukai): filename, lineno?
314 r.cmdLineno = irule.cmdLineno
315 return r, true
316 }
317 // TODO(ukai): check len(irule.cmd) ?
318 return irule, true
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900319 }
320
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900321 outputSuffix := filepath.Ext(output)
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900322 if !strings.HasPrefix(outputSuffix, ".") {
323 return rule, rule != nil
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900324 }
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900325 rules, present := ex.suffixRules[outputSuffix[1:]]
326 if !present {
327 return rule, rule != nil
328 }
329 for _, irule := range rules {
330 if len(irule.inputs) != 1 {
331 panic(fmt.Sprintf("unexpected number of input for a suffix rule (%d)", len(irule.inputs)))
332 }
Fumitoshi Ukai6b378832015-04-06 16:54:37 +0900333 if !ex.exists(replaceSuffix(output, irule.inputs[0])) {
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900334 continue
335 }
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +0900336 ex.pickSuffixRuleCnt++
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900337 if rule != nil {
338 r := &Rule{}
339 *r = *rule
340 // TODO(ukai): input order is correct?
341 r.inputs = append([]string{replaceSuffix(output, irule.inputs[0])}, r.inputs...)
Shinichiro Hamajiea170b12015-04-15 10:02:33 +0900342 r.vars = append(r.vars, rule.vars...)
343 r.vars = append(r.vars, irule.vars...)
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900344 r.cmds = irule.cmds
345 // TODO(ukai): filename, lineno?
346 r.cmdLineno = irule.cmdLineno
347 return r, true
348 }
349 // TODO(ukai): check len(irule.cmd) ?
350 return irule, true
351 }
352 return rule, rule != nil
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900353}
354
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900355func (ex *Executor) build(output string, neededBy string) (int64, error) {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900356 Log("Building: %s", output)
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +0900357 ex.buildCnt++
358 if ex.buildCnt%100 == 0 {
359 ex.reportStats()
360 }
361
Fumitoshi Ukai4b82f192015-04-07 11:36:42 +0900362 outputTs, ok := ex.done[output]
363 if ok {
Shinichiro Hamaji940bb6c2015-04-13 00:35:59 +0900364 if outputTs < 0 {
365 fmt.Printf("Circular %s <- %s dependency dropped.\n", neededBy, output)
366 }
Fumitoshi Ukaibac3ccf2015-04-08 13:41:22 +0900367 Log("Building: %s already done: %d", output, outputTs)
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +0900368 ex.alreadyDoneCnt++
Fumitoshi Ukai4b82f192015-04-07 11:36:42 +0900369 return outputTs, nil
370 }
Shinichiro Hamaji940bb6c2015-04-13 00:35:59 +0900371 ex.done[output] = -1
Fumitoshi Ukai4b82f192015-04-07 11:36:42 +0900372 outputTs = getTimestamp(output)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900373
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900374 rule, present := ex.pickRule(output)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900375 if !present {
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900376 if outputTs >= 0 {
Shinichiro Hamaji61748ac2015-04-13 01:08:43 +0900377 ex.done[output] = outputTs
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +0900378 ex.noRuleCnt++
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900379 return outputTs, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900380 }
Shinichiro Hamajieb4da7f2015-04-11 20:28:54 +0900381 if neededBy == "" {
382 ErrorNoLocation("*** No rule to make target %q.", output)
383 } else {
384 ErrorNoLocation("*** No rule to make target %q, needed by %q.", output, neededBy)
385 }
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900386 return outputTs, fmt.Errorf("no rule to make target %q", output)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900387 }
Shinichiro Hamaji4e9ab1a2015-04-12 01:31:58 +0900388
389 var olds []oldVar
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +0900390 if rule.vars != nil {
Shinichiro Hamajiea170b12015-04-15 10:02:33 +0900391 for _, v := range rule.vars {
392 olds = append(olds, newOldVar(ex.vars, v.name))
393 switch v.op {
394 case ":=", "=":
395 ex.vars[v.name] = v.v
396 case "+=":
397 oldVar := ex.vars[v.name]
398 // Not sure why make does not append a
399 // whitespace... See
400 // target_specific_var_append.
401 if oldVar.String() == "" {
402 ex.vars[v.name] = v.v
403 } else {
404 ex.vars[v.name] = oldVar.AppendVar(newEvaluator(ex.vars), v.v)
405 }
406 case "?=":
407 if _, present := ex.vars[v.name]; !present {
408 ex.vars[v.name] = v.v
409 }
410 }
Shinichiro Hamaji4e9ab1a2015-04-12 01:31:58 +0900411 }
412 defer func() {
413 for _, old := range olds {
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900414 old.restore(ex.vars)
Shinichiro Hamaji4e9ab1a2015-04-12 01:31:58 +0900415 }
416 }()
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +0900417 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900418
419 latest := int64(-1)
Shinichiro Hamaji57aff982015-04-02 02:15:38 +0900420 var actualInputs []string
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900421 Log("Building: %s inputs:%q", output, rule.inputs)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900422 for _, input := range rule.inputs {
Shinichiro Hamaji7b203b22015-04-01 03:44:57 +0900423 if len(rule.outputPatterns) > 0 {
424 if len(rule.outputPatterns) > 1 {
425 panic("TODO: multiple output pattern is not supported yet")
426 }
427 input = substPattern(rule.outputPatterns[0], input, output)
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900428 } else if rule.isSuffixRule {
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900429 input = replaceSuffix(output, input)
Shinichiro Hamaji7b203b22015-04-01 03:44:57 +0900430 }
Shinichiro Hamaji57aff982015-04-02 02:15:38 +0900431 actualInputs = append(actualInputs, input)
Shinichiro Hamaji7b203b22015-04-01 03:44:57 +0900432
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +0900433 ex.trace = append(ex.trace, input)
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900434 ts, err := ex.build(input, output)
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +0900435 ex.trace = ex.trace[0 : len(ex.trace)-1]
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900436 if err != nil {
437 return outputTs, err
438 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900439 if latest < ts {
440 latest = ts
441 }
442 }
443
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +0900444 for _, input := range rule.orderOnlyInputs {
Fumitoshi Ukaif04610d2015-04-07 00:03:03 +0900445 if exists(input) {
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +0900446 continue
447 }
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +0900448
449 ex.trace = append(ex.trace, input)
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900450 ts, err := ex.build(input, output)
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +0900451 ex.trace = ex.trace[0 : len(ex.trace)-1]
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +0900452 if err != nil {
453 return outputTs, err
454 }
455 if latest < ts {
456 latest = ts
457 }
458 }
459
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900460 if outputTs >= latest {
Shinichiro Hamaji61748ac2015-04-13 01:08:43 +0900461 ex.done[output] = outputTs
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +0900462 ex.upToDateCnt++
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900463 return outputTs, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900464 }
465
Shinichiro Hamaji110af332015-04-13 19:04:50 +0900466 // For automatic variables.
467 ex.currentOutput = output
468 ex.currentInputs = actualInputs
469
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900470 ev := newEvaluator(ex.vars)
Shinichiro Hamajie708a9d2015-04-03 14:34:35 +0900471 ev.filename = rule.filename
472 ev.lineno = rule.cmdLineno
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900473 var runners []runner
Fumitoshi Ukaif04610d2015-04-07 00:03:03 +0900474 Log("Building: %s cmds:%q", output, rule.cmds)
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900475 r := runner{
476 output: output,
477 echo: true,
478 dryRun: dryRunFlag,
Shinichiro Hamaji77353192015-04-13 16:04:15 +0900479 shell: ex.shell,
Fumitoshi Ukai3e5161e2015-04-01 22:42:10 +0900480 }
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900481 for _, cmd := range rule.cmds {
Shinichiro Hamaji973c69f2015-04-11 21:52:38 +0900482 for _, r := range evalCmd(ev, r, cmd) {
483 if len(r.cmd) != 0 {
484 runners = append(runners, r)
485 }
486 }
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900487 }
488 for _, r := range runners {
489 err := r.run()
490 if err != nil {
491 exit := exitStatus(err)
492 fmt.Printf("[%s] Error %d: %v\n", r.output, exit, err)
493 return outputTs, err
494 }
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900495 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900496
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900497 outputTs = getTimestamp(output)
498 if outputTs < 0 {
499 outputTs = time.Now().Unix()
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900500 }
Fumitoshi Ukai4b82f192015-04-07 11:36:42 +0900501 ex.done[output] = outputTs
502 Log("Building: %s done %d", output, outputTs)
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +0900503 ex.runCommandCnt++
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900504 return outputTs, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900505}
506
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900507func (ex *Executor) populateSuffixRule(rule *Rule, output string) bool {
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900508 if len(output) == 0 || output[0] != '.' {
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900509 return false
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900510 }
511 rest := output[1:]
512 dotIndex := strings.IndexByte(rest, '.')
513 // If there is only a single dot or the third dot, this is not a
514 // suffix rule.
515 if dotIndex < 0 || strings.IndexByte(rest[dotIndex+1:], '.') >= 0 {
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900516 return false
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900517 }
518
519 // This is a suffix rule.
520 inputSuffix := rest[:dotIndex]
521 outputSuffix := rest[dotIndex+1:]
522 r := &Rule{}
523 *r = *rule
524 r.inputs = []string{inputSuffix}
525 r.isSuffixRule = true
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900526 ex.suffixRules[outputSuffix] = append([]*Rule{r}, ex.suffixRules[outputSuffix]...)
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900527 return true
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900528}
529
Shinichiro Hamajid1bd3312015-04-13 18:21:08 +0900530func mergeRules(oldRule, rule *Rule, output string, isSuffixRule bool) *Rule {
Shinichiro Hamajiea170b12015-04-15 10:02:33 +0900531 if oldRule == rule {
532 panic("Merging a same rule")
533 }
Shinichiro Hamajifaeba682015-04-13 18:11:27 +0900534 if oldRule.vars != nil || rule.vars != nil {
535 oldRule.isDoubleColon = rule.isDoubleColon
536 switch {
537 case rule.vars == nil && oldRule.vars != nil:
538 rule.vars = oldRule.vars
539 case rule.vars != nil && oldRule.vars == nil:
540 case rule.vars != nil && oldRule.vars != nil:
541 // parent would be the same vars?
Shinichiro Hamajiea170b12015-04-15 10:02:33 +0900542 rule.vars = append(oldRule.vars, rule.vars...)
Shinichiro Hamajifaeba682015-04-13 18:11:27 +0900543 }
544 }
545
Shinichiro Hamajid1bd3312015-04-13 18:21:08 +0900546 if oldRule.isDoubleColon != rule.isDoubleColon {
547 Error(rule.filename, rule.lineno, "*** target file %q has both : and :: entries.", output)
548 }
549 if len(oldRule.cmds) > 0 && len(rule.cmds) > 0 && !isSuffixRule && !rule.isDoubleColon {
550 Warn(rule.filename, rule.cmdLineno, "overriding commands for target %q", output)
551 Warn(oldRule.filename, oldRule.cmdLineno, "ignoring old commands for target %q", output)
552 }
553
Shinichiro Hamajifaeba682015-04-13 18:11:27 +0900554 r := &Rule{}
555 *r = *rule
556 if rule.isDoubleColon {
557 r.cmds = append(oldRule.cmds, r.cmds...)
558 } else if len(oldRule.cmds) > 0 && len(rule.cmds) == 0 {
559 r.cmds = oldRule.cmds
560 }
561 // If the latter rule has a command (regardless of the
562 // commands in oldRule), inputs in the latter rule has a
563 // priority.
564 if len(rule.cmds) > 0 {
565 r.inputs = append(r.inputs, oldRule.inputs...)
566 r.orderOnlyInputs = append(r.orderOnlyInputs, oldRule.orderOnlyInputs...)
567 } else {
568 r.inputs = append(oldRule.inputs, r.inputs...)
569 r.orderOnlyInputs = append(oldRule.orderOnlyInputs, r.orderOnlyInputs...)
570 }
571 r.outputPatterns = append(r.outputPatterns, oldRule.outputPatterns...)
572 return r
573}
574
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900575func (ex *Executor) populateExplicitRule(rule *Rule) {
Shinichiro Hamajiea170b12015-04-15 10:02:33 +0900576 fmt.Printf("populateExplicitRule\n")
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900577 // It seems rules with no outputs are siliently ignored.
578 if len(rule.outputs) == 0 {
579 return
580 }
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900581 for _, output := range rule.outputs {
Fumitoshi Ukaie1e34442015-04-08 13:10:05 +0900582 output = filepath.Clean(output)
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900583
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900584 isSuffixRule := ex.populateSuffixRule(rule, output)
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900585
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900586 if oldRule, present := ex.rules[output]; present {
Shinichiro Hamajiea170b12015-04-15 10:02:33 +0900587 fmt.Printf("merge\n")
Shinichiro Hamajid1bd3312015-04-13 18:21:08 +0900588 r := mergeRules(oldRule, rule, output, isSuffixRule)
Shinichiro Hamajiea170b12015-04-15 10:02:33 +0900589 fmt.Printf("merge done\n")
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900590 ex.rules[output] = r
591 } else {
592 ex.rules[output] = rule
Shinichiro Hamaji4a1cfc22015-04-11 13:54:46 +0900593 if ex.firstRule == nil && !strings.HasPrefix(output, ".") {
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900594 ex.firstRule = rule
595 }
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900596 }
597 }
Shinichiro Hamajiea170b12015-04-15 10:02:33 +0900598 fmt.Printf("populateExplicitRule done\n")
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900599}
600
601func (ex *Executor) populateImplicitRule(rule *Rule) {
602 for _, outputPattern := range rule.outputPatterns {
603 r := &Rule{}
604 *r = *rule
605 r.outputPatterns = []string{outputPattern}
606 ex.implicitRules = append(ex.implicitRules, r)
607 }
608}
609
610func (ex *Executor) populateRules(er *EvalResult) {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900611 for _, rule := range er.rules {
Fumitoshi Ukaibac3ccf2015-04-08 13:41:22 +0900612 for i, input := range rule.inputs {
613 rule.inputs[i] = filepath.Clean(input)
614 }
615 for i, orderOnlyInput := range rule.orderOnlyInputs {
616 rule.orderOnlyInputs[i] = filepath.Clean(orderOnlyInput)
617 }
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900618 ex.populateExplicitRule(rule)
619
620 if len(rule.outputs) == 0 {
621 ex.populateImplicitRule(rule)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900622 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900623 }
624
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900625 // Reverse the implicit rule for easier lookup.
626 for i, r := range ex.implicitRules {
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900627 if i >= len(ex.implicitRules)/2 {
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900628 break
629 }
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900630 j := len(ex.implicitRules) - i - 1
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900631 ex.implicitRules[i] = ex.implicitRules[j]
632 ex.implicitRules[j] = r
633 }
634}
635
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +0900636func (ex *Executor) reportStats() {
637 if !katiLogFlag && !katiStatsFlag {
638 return
639 }
640
641 LogStats("build=%d alreadyDone=%d noRule=%d, upToDate=%d runCommand=%d",
642 ex.buildCnt, ex.alreadyDoneCnt, ex.noRuleCnt, ex.upToDateCnt, ex.runCommandCnt)
643 LogStats("explicit=%d implicit=%d suffix=%d explicitWOCmd=%d",
644 ex.pickExplicitRuleCnt, ex.pickImplicitRuleCnt, ex.pickSuffixRuleCnt, ex.pickExplicitRuleWithoutCmdCnt)
645 if len(ex.trace) > 1 {
646 LogStats("trace=%q", ex.trace)
647 }
648}
649
Shinichiro Hamaji8843a052015-04-13 16:46:56 +0900650func NewExecutor(er *EvalResult, vars Vars) *Executor {
651 ex := newExecutor(vars)
Shinichiro Hamaji89551c92015-04-11 19:33:03 +0900652 // TODO: We should move this to somewhere around evalCmd so that
653 // we can handle SHELL in target specific variables.
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900654 shellVar := ex.vars.Lookup("SHELL")
Shinichiro Hamaji89551c92015-04-11 19:33:03 +0900655 ex.shell = shellVar.String()
656
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900657 ex.populateRules(er)
Shinichiro Hamaji8843a052015-04-13 16:46:56 +0900658 return ex
659}
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900660
Shinichiro Hamaji8843a052015-04-13 16:46:56 +0900661func (ex *Executor) Exec(targets []string) error {
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900662 if len(targets) == 0 {
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900663 if ex.firstRule == nil {
664 ErrorNoLocation("*** No targets.")
665 }
666 targets = append(targets, ex.firstRule.outputs[0])
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900667 }
668
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900669 LogStats("%d variables", len(ex.vars))
Shinichiro Hamaji750988e2015-04-12 10:14:32 +0900670 LogStats("%d explicit rules", len(ex.rules))
671 LogStats("%d implicit rules", len(ex.implicitRules))
672 LogStats("%d suffix rules", len(ex.suffixRules))
673
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900674 for _, target := range targets {
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +0900675 ex.trace = []string{target}
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900676 _, err := ex.build(target, "")
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900677 if err != nil {
678 return err
679 }
680 }
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +0900681 ex.reportStats()
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900682 return nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900683}