blob: 6db0acb60bac8ba7f9d3445098a17917184f421c [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
29}
30
31type AutoVar struct{ ex *Executor }
32
33func (v AutoVar) Flavor() string { return "undefined" }
34func (v AutoVar) Origin() string { return "automatic" }
35func (v AutoVar) IsDefined() bool { panic("not implemented") }
36func (v AutoVar) String() string { panic("not implemented") }
37func (v AutoVar) Append(ev *Evaluator, s string) Var {
38 panic("must not be called")
39}
40
41type AutoAtVar struct{ AutoVar }
42
43func (v AutoAtVar) Eval(w io.Writer, ev *Evaluator) {
44 fmt.Fprint(w, v.ex.currentOutput)
45}
46
47type AutoLessVar struct{ AutoVar }
48
49func (v AutoLessVar) Eval(w io.Writer, ev *Evaluator) {
50 if len(v.ex.currentInputs) > 0 {
51 fmt.Fprint(w, v.ex.currentInputs[0])
52 }
53}
54
55type AutoHatVar struct{ AutoVar }
56
57func (v AutoHatVar) Eval(w io.Writer, ev *Evaluator) {
Shinichiro Hamajia622c5e2015-04-13 19:09:30 +090058 var uniqueInputs []string
59 seen := make(map[string]bool)
60 for _, input := range v.ex.currentInputs {
61 if !seen[input] {
62 seen[input] = true
63 uniqueInputs = append(uniqueInputs, input)
64 }
65 }
66 fmt.Fprint(w, strings.Join(uniqueInputs, " "))
67}
68
69type AutoPlusVar struct{ AutoVar }
70
71func (v AutoPlusVar) Eval(w io.Writer, ev *Evaluator) {
Shinichiro Hamaji110af332015-04-13 19:04:50 +090072 fmt.Fprint(w, strings.Join(v.ex.currentInputs, " "))
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090073}
74
Shinichiro Hamajiee8b33c2015-04-13 20:08:38 +090075type AutoSuffixDVar struct {
76 AutoVar
77 v Var
78}
79
80func (v AutoSuffixDVar) Eval(w io.Writer, ev *Evaluator) {
81 var buf bytes.Buffer
82 v.v.Eval(&buf, ev)
83 for i, tok := range splitSpaces(buf.String()) {
84 if i > 0 {
85 w.Write([]byte{' '})
86 }
87 fmt.Fprint(w, filepath.Dir(tok))
88 }
89}
90
91type AutoSuffixFVar struct {
92 AutoVar
93 v Var
94}
95
96func (v AutoSuffixFVar) Eval(w io.Writer, ev *Evaluator) {
97 var buf bytes.Buffer
98 v.v.Eval(&buf, ev)
99 for i, tok := range splitSpaces(buf.String()) {
100 if i > 0 {
101 w.Write([]byte{' '})
102 }
103 fmt.Fprint(w, filepath.Base(tok))
104 }
105}
106
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900107func newExecutor(vars Vars) *Executor {
Shinichiro Hamaji110af332015-04-13 19:04:50 +0900108 ex := &Executor{
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900109 rules: make(map[string]*Rule),
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900110 suffixRules: make(map[string][]*Rule),
Fumitoshi Ukai4b82f192015-04-07 11:36:42 +0900111 done: make(map[string]int64),
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900112 vars: vars,
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900113 }
Shinichiro Hamaji110af332015-04-13 19:04:50 +0900114
Shinichiro Hamajiee8b33c2015-04-13 20:08:38 +0900115 for k, v := range map[string]Var{
116 "@": AutoAtVar{AutoVar: AutoVar{ex: ex}},
117 "<": AutoLessVar{AutoVar: AutoVar{ex: ex}},
118 "^": AutoHatVar{AutoVar: AutoVar{ex: ex}},
119 "+": AutoPlusVar{AutoVar: AutoVar{ex: ex}},
120 } {
121 ex.vars[k] = v
122 ex.vars[k+"D"] = AutoSuffixDVar{v: v}
123 ex.vars[k+"F"] = AutoSuffixFVar{v: v}
124 }
Shinichiro Hamaji110af332015-04-13 19:04:50 +0900125
126 return ex
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900127}
128
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900129// TODO(ukai): use time.Time?
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900130func getTimestamp(filename string) int64 {
131 st, err := os.Stat(filename)
132 if err != nil {
133 return -2
134 }
135 return st.ModTime().Unix()
136}
137
Fumitoshi Ukai6b378832015-04-06 16:54:37 +0900138func (ex *Executor) exists(target string) bool {
Fumitoshi Ukaif04610d2015-04-07 00:03:03 +0900139 _, present := ex.rules[target]
140 if present {
141 return true
142 }
Fumitoshi Ukai6b378832015-04-06 16:54:37 +0900143 rule, present := ex.rules[".PHONY"]
144 if present {
145 for _, input := range rule.inputs {
146 if target == input {
147 return true
148 }
149 }
150 }
151 return exists(target)
152}
153
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900154type runner struct {
155 output string
156 cmd string
157 echo bool
158 dryRun bool
159 ignoreError bool
Shinichiro Hamaji89551c92015-04-11 19:33:03 +0900160 shell string
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900161}
162
Shinichiro Hamaji973c69f2015-04-11 21:52:38 +0900163func evalCmd(ev *Evaluator, r runner, s string) []runner {
164 r = newRunner(r, s)
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900165 if strings.IndexByte(r.cmd, '$') < 0 {
166 // fast path
167 return []runner{r}
168 }
169 cmds := ev.evalExpr(r.cmd)
170 var runners []runner
171 for _, cmd := range strings.Split(cmds, "\n") {
Shinichiro Hamaji77353192015-04-13 16:04:15 +0900172 if len(runners) > 0 && strings.HasSuffix(runners[0].cmd, "\\") {
173 runners[0].cmd += "\n"
174 runners[0].cmd += cmd
175 } else {
176 runners = append(runners, newRunner(r, cmd))
177 }
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900178 }
179 return runners
180}
181
Shinichiro Hamaji973c69f2015-04-11 21:52:38 +0900182func newRunner(r runner, s string) runner {
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900183 for {
Shinichiro Hamajic88618f2015-04-11 19:58:06 +0900184 s = trimLeftSpace(s)
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900185 if s == "" {
186 return runner{}
Fumitoshi Ukai772fe1a2015-04-01 23:28:26 +0900187 }
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900188 switch s[0] {
189 case '@':
190 if !r.dryRun {
191 r.echo = false
192 }
193 s = s[1:]
194 continue
195 case '-':
196 r.ignoreError = true
197 s = s[1:]
Shinichiro Hamaji07e146b2015-04-02 16:17:24 +0900198 continue
199 }
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900200 break
201 }
202 r.cmd = s
203 return r
204}
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900205
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900206func (r runner) run() error {
207 if r.echo {
208 fmt.Printf("%s\n", r.cmd)
209 }
210 if r.dryRun {
211 return nil
212 }
Shinichiro Hamaji89551c92015-04-11 19:33:03 +0900213 args := []string{r.shell, "-c", r.cmd}
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900214 cmd := exec.Cmd{
215 Path: args[0],
216 Args: args,
217 }
218 out, err := cmd.CombinedOutput()
219 fmt.Printf("%s", out)
220 exit := exitStatus(err)
221 if r.ignoreError && exit != 0 {
222 fmt.Printf("[%s] Error %d (ignored)\n", r.output, exit)
223 err = nil
224 }
225 return err
226}
227
228func exitStatus(err error) int {
229 if err == nil {
230 return 0
231 }
232 exit := 1
233 if err, ok := err.(*exec.ExitError); ok {
234 if w, ok := err.ProcessState.Sys().(syscall.WaitStatus); ok {
235 return w.ExitStatus()
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900236 }
237 }
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900238 return exit
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900239}
240
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900241func replaceSuffix(s string, newsuf string) string {
242 // TODO: Factor out the logic around suffix rules and use
243 // it from substitution references.
244 // http://www.gnu.org/software/make/manual/make.html#Substitution-Refs
Shinichiro Hamaji5e2c3c72015-04-03 15:04:54 +0900245 return fmt.Sprintf("%s.%s", stripExt(s), newsuf)
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900246}
247
Shinichiro Hamaji0d0af5b2015-04-02 05:17:23 +0900248func (ex *Executor) canPickImplicitRule(rule *Rule, output string) bool {
249 outputPattern := rule.outputPatterns[0]
250 if !matchPattern(outputPattern, output) {
251 return false
252 }
253 for _, input := range rule.inputs {
254 input = substPattern(outputPattern, input, output)
Fumitoshi Ukai6b378832015-04-06 16:54:37 +0900255 if !ex.exists(input) {
Shinichiro Hamaji0d0af5b2015-04-02 05:17:23 +0900256 return false
257 }
258 }
259 return true
260}
261
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900262func (ex *Executor) pickRule(output string) (*Rule, bool) {
263 rule, present := ex.rules[output]
264 if present {
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900265 if len(rule.cmds) > 0 {
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900266 return rule, true
267 }
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900268 // If none of the explicit rules for a target has commands,
269 // then `make' searches for an applicable implicit rule to
270 // find some commands.
271 }
272
273 for _, irule := range ex.implicitRules {
274 if !ex.canPickImplicitRule(irule, output) {
275 continue
276 }
277 if rule != nil {
278 r := &Rule{}
279 *r = *rule
280 r.outputPatterns = irule.outputPatterns
281 // implicit rule's prerequisites will be used for $<
282 r.inputs = append(irule.inputs, r.inputs...)
283 if irule.vars != nil {
Shinichiro Hamaji63a77d42015-04-12 01:04:07 +0900284 r.vars = NewVars(rule.vars)
285 r.vars.Merge(irule.vars)
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900286 }
287 r.cmds = irule.cmds
288 // TODO(ukai): filename, lineno?
289 r.cmdLineno = irule.cmdLineno
290 return r, true
291 }
292 // TODO(ukai): check len(irule.cmd) ?
293 return irule, true
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900294 }
295
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900296 outputSuffix := filepath.Ext(output)
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900297 if !strings.HasPrefix(outputSuffix, ".") {
298 return rule, rule != nil
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900299 }
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900300 rules, present := ex.suffixRules[outputSuffix[1:]]
301 if !present {
302 return rule, rule != nil
303 }
304 for _, irule := range rules {
305 if len(irule.inputs) != 1 {
306 panic(fmt.Sprintf("unexpected number of input for a suffix rule (%d)", len(irule.inputs)))
307 }
Fumitoshi Ukai6b378832015-04-06 16:54:37 +0900308 if !ex.exists(replaceSuffix(output, irule.inputs[0])) {
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900309 continue
310 }
311 if rule != nil {
312 r := &Rule{}
313 *r = *rule
314 // TODO(ukai): input order is correct?
315 r.inputs = append([]string{replaceSuffix(output, irule.inputs[0])}, r.inputs...)
Shinichiro Hamaji63a77d42015-04-12 01:04:07 +0900316 r.vars = NewVars(rule.vars)
317 r.vars.Merge(irule.vars)
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900318 r.cmds = irule.cmds
319 // TODO(ukai): filename, lineno?
320 r.cmdLineno = irule.cmdLineno
321 return r, true
322 }
323 // TODO(ukai): check len(irule.cmd) ?
324 return irule, true
325 }
326 return rule, rule != nil
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900327}
328
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900329func (ex *Executor) build(output string, neededBy string) (int64, error) {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900330 Log("Building: %s", output)
Fumitoshi Ukai4b82f192015-04-07 11:36:42 +0900331 outputTs, ok := ex.done[output]
332 if ok {
Shinichiro Hamaji940bb6c2015-04-13 00:35:59 +0900333 if outputTs < 0 {
334 fmt.Printf("Circular %s <- %s dependency dropped.\n", neededBy, output)
335 }
Fumitoshi Ukaibac3ccf2015-04-08 13:41:22 +0900336 Log("Building: %s already done: %d", output, outputTs)
Fumitoshi Ukai4b82f192015-04-07 11:36:42 +0900337 return outputTs, nil
338 }
Shinichiro Hamaji940bb6c2015-04-13 00:35:59 +0900339 ex.done[output] = -1
Fumitoshi Ukai4b82f192015-04-07 11:36:42 +0900340 outputTs = getTimestamp(output)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900341
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900342 rule, present := ex.pickRule(output)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900343 if !present {
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900344 if outputTs >= 0 {
Shinichiro Hamaji61748ac2015-04-13 01:08:43 +0900345 ex.done[output] = outputTs
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900346 return outputTs, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900347 }
Shinichiro Hamajieb4da7f2015-04-11 20:28:54 +0900348 if neededBy == "" {
349 ErrorNoLocation("*** No rule to make target %q.", output)
350 } else {
351 ErrorNoLocation("*** No rule to make target %q, needed by %q.", output, neededBy)
352 }
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900353 return outputTs, fmt.Errorf("no rule to make target %q", output)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900354 }
Shinichiro Hamaji4e9ab1a2015-04-12 01:31:58 +0900355
356 var olds []oldVar
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +0900357 if rule.vars != nil {
Shinichiro Hamaji4e9ab1a2015-04-12 01:31:58 +0900358 for k, v := range rule.vars {
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900359 olds = append(olds, newOldVar(ex.vars, k))
360 ex.vars[k] = v
Shinichiro Hamaji4e9ab1a2015-04-12 01:31:58 +0900361 }
362 defer func() {
363 for _, old := range olds {
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900364 old.restore(ex.vars)
Shinichiro Hamaji4e9ab1a2015-04-12 01:31:58 +0900365 }
366 }()
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +0900367 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900368
369 latest := int64(-1)
Shinichiro Hamaji57aff982015-04-02 02:15:38 +0900370 var actualInputs []string
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900371 Log("Building: %s inputs:%q", output, rule.inputs)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900372 for _, input := range rule.inputs {
Shinichiro Hamaji7b203b22015-04-01 03:44:57 +0900373 if len(rule.outputPatterns) > 0 {
374 if len(rule.outputPatterns) > 1 {
375 panic("TODO: multiple output pattern is not supported yet")
376 }
377 input = substPattern(rule.outputPatterns[0], input, output)
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900378 } else if rule.isSuffixRule {
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900379 input = replaceSuffix(output, input)
Shinichiro Hamaji7b203b22015-04-01 03:44:57 +0900380 }
Shinichiro Hamaji57aff982015-04-02 02:15:38 +0900381 actualInputs = append(actualInputs, input)
Shinichiro Hamaji7b203b22015-04-01 03:44:57 +0900382
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900383 ts, err := ex.build(input, output)
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900384 if err != nil {
385 return outputTs, err
386 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900387 if latest < ts {
388 latest = ts
389 }
390 }
391
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +0900392 for _, input := range rule.orderOnlyInputs {
Fumitoshi Ukaif04610d2015-04-07 00:03:03 +0900393 if exists(input) {
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +0900394 continue
395 }
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900396 ts, err := ex.build(input, output)
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +0900397 if err != nil {
398 return outputTs, err
399 }
400 if latest < ts {
401 latest = ts
402 }
403 }
404
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900405 if outputTs >= latest {
Shinichiro Hamaji61748ac2015-04-13 01:08:43 +0900406 ex.done[output] = outputTs
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900407 return outputTs, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900408 }
409
Shinichiro Hamaji110af332015-04-13 19:04:50 +0900410 // For automatic variables.
411 ex.currentOutput = output
412 ex.currentInputs = actualInputs
413
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900414 ev := newEvaluator(ex.vars)
Shinichiro Hamajie708a9d2015-04-03 14:34:35 +0900415 ev.filename = rule.filename
416 ev.lineno = rule.cmdLineno
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900417 var runners []runner
Fumitoshi Ukaif04610d2015-04-07 00:03:03 +0900418 Log("Building: %s cmds:%q", output, rule.cmds)
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900419 r := runner{
420 output: output,
421 echo: true,
422 dryRun: dryRunFlag,
Shinichiro Hamaji77353192015-04-13 16:04:15 +0900423 shell: ex.shell,
Fumitoshi Ukai3e5161e2015-04-01 22:42:10 +0900424 }
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900425 for _, cmd := range rule.cmds {
Shinichiro Hamaji973c69f2015-04-11 21:52:38 +0900426 for _, r := range evalCmd(ev, r, cmd) {
427 if len(r.cmd) != 0 {
428 runners = append(runners, r)
429 }
430 }
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900431 }
432 for _, r := range runners {
433 err := r.run()
434 if err != nil {
435 exit := exitStatus(err)
436 fmt.Printf("[%s] Error %d: %v\n", r.output, exit, err)
437 return outputTs, err
438 }
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900439 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900440
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900441 outputTs = getTimestamp(output)
442 if outputTs < 0 {
443 outputTs = time.Now().Unix()
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900444 }
Fumitoshi Ukai4b82f192015-04-07 11:36:42 +0900445 ex.done[output] = outputTs
446 Log("Building: %s done %d", output, outputTs)
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900447 return outputTs, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900448}
449
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900450func (ex *Executor) populateSuffixRule(rule *Rule, output string) bool {
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900451 if len(output) == 0 || output[0] != '.' {
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900452 return false
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900453 }
454 rest := output[1:]
455 dotIndex := strings.IndexByte(rest, '.')
456 // If there is only a single dot or the third dot, this is not a
457 // suffix rule.
458 if dotIndex < 0 || strings.IndexByte(rest[dotIndex+1:], '.') >= 0 {
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900459 return false
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900460 }
461
462 // This is a suffix rule.
463 inputSuffix := rest[:dotIndex]
464 outputSuffix := rest[dotIndex+1:]
465 r := &Rule{}
466 *r = *rule
467 r.inputs = []string{inputSuffix}
468 r.isSuffixRule = true
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900469 ex.suffixRules[outputSuffix] = append([]*Rule{r}, ex.suffixRules[outputSuffix]...)
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900470 return true
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900471}
472
Shinichiro Hamajid1bd3312015-04-13 18:21:08 +0900473func mergeRules(oldRule, rule *Rule, output string, isSuffixRule bool) *Rule {
Shinichiro Hamajifaeba682015-04-13 18:11:27 +0900474 if oldRule.vars != nil || rule.vars != nil {
475 oldRule.isDoubleColon = rule.isDoubleColon
476 switch {
477 case rule.vars == nil && oldRule.vars != nil:
478 rule.vars = oldRule.vars
479 case rule.vars != nil && oldRule.vars == nil:
480 case rule.vars != nil && oldRule.vars != nil:
481 // parent would be the same vars?
482 oldRule.vars.Merge(rule.vars)
483 rule.vars = oldRule.vars
484 }
485 }
486
Shinichiro Hamajid1bd3312015-04-13 18:21:08 +0900487 if oldRule.isDoubleColon != rule.isDoubleColon {
488 Error(rule.filename, rule.lineno, "*** target file %q has both : and :: entries.", output)
489 }
490 if len(oldRule.cmds) > 0 && len(rule.cmds) > 0 && !isSuffixRule && !rule.isDoubleColon {
491 Warn(rule.filename, rule.cmdLineno, "overriding commands for target %q", output)
492 Warn(oldRule.filename, oldRule.cmdLineno, "ignoring old commands for target %q", output)
493 }
494
Shinichiro Hamajifaeba682015-04-13 18:11:27 +0900495 r := &Rule{}
496 *r = *rule
497 if rule.isDoubleColon {
498 r.cmds = append(oldRule.cmds, r.cmds...)
499 } else if len(oldRule.cmds) > 0 && len(rule.cmds) == 0 {
500 r.cmds = oldRule.cmds
501 }
502 // If the latter rule has a command (regardless of the
503 // commands in oldRule), inputs in the latter rule has a
504 // priority.
505 if len(rule.cmds) > 0 {
506 r.inputs = append(r.inputs, oldRule.inputs...)
507 r.orderOnlyInputs = append(r.orderOnlyInputs, oldRule.orderOnlyInputs...)
508 } else {
509 r.inputs = append(oldRule.inputs, r.inputs...)
510 r.orderOnlyInputs = append(oldRule.orderOnlyInputs, r.orderOnlyInputs...)
511 }
512 r.outputPatterns = append(r.outputPatterns, oldRule.outputPatterns...)
513 return r
514}
515
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900516func (ex *Executor) populateExplicitRule(rule *Rule) {
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900517 // It seems rules with no outputs are siliently ignored.
518 if len(rule.outputs) == 0 {
519 return
520 }
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900521 for _, output := range rule.outputs {
Fumitoshi Ukaie1e34442015-04-08 13:10:05 +0900522 output = filepath.Clean(output)
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900523
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900524 isSuffixRule := ex.populateSuffixRule(rule, output)
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900525
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900526 if oldRule, present := ex.rules[output]; present {
Shinichiro Hamajid1bd3312015-04-13 18:21:08 +0900527 r := mergeRules(oldRule, rule, output, isSuffixRule)
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900528 ex.rules[output] = r
529 } else {
530 ex.rules[output] = rule
Shinichiro Hamaji4a1cfc22015-04-11 13:54:46 +0900531 if ex.firstRule == nil && !strings.HasPrefix(output, ".") {
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900532 ex.firstRule = rule
533 }
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900534 }
535 }
536}
537
538func (ex *Executor) populateImplicitRule(rule *Rule) {
539 for _, outputPattern := range rule.outputPatterns {
540 r := &Rule{}
541 *r = *rule
542 r.outputPatterns = []string{outputPattern}
543 ex.implicitRules = append(ex.implicitRules, r)
544 }
545}
546
547func (ex *Executor) populateRules(er *EvalResult) {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900548 for _, rule := range er.rules {
Fumitoshi Ukaibac3ccf2015-04-08 13:41:22 +0900549 for i, input := range rule.inputs {
550 rule.inputs[i] = filepath.Clean(input)
551 }
552 for i, orderOnlyInput := range rule.orderOnlyInputs {
553 rule.orderOnlyInputs[i] = filepath.Clean(orderOnlyInput)
554 }
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900555 ex.populateExplicitRule(rule)
556
557 if len(rule.outputs) == 0 {
558 ex.populateImplicitRule(rule)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900559 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900560 }
561
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900562 // Reverse the implicit rule for easier lookup.
563 for i, r := range ex.implicitRules {
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900564 if i >= len(ex.implicitRules)/2 {
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900565 break
566 }
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900567 j := len(ex.implicitRules) - i - 1
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900568 ex.implicitRules[i] = ex.implicitRules[j]
569 ex.implicitRules[j] = r
570 }
571}
572
Shinichiro Hamaji8843a052015-04-13 16:46:56 +0900573func NewExecutor(er *EvalResult, vars Vars) *Executor {
574 ex := newExecutor(vars)
Shinichiro Hamaji89551c92015-04-11 19:33:03 +0900575 // TODO: We should move this to somewhere around evalCmd so that
576 // we can handle SHELL in target specific variables.
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900577 shellVar := ex.vars.Lookup("SHELL")
Shinichiro Hamaji89551c92015-04-11 19:33:03 +0900578 ex.shell = shellVar.String()
579
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900580 ex.populateRules(er)
Shinichiro Hamaji8843a052015-04-13 16:46:56 +0900581 return ex
582}
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900583
Shinichiro Hamaji8843a052015-04-13 16:46:56 +0900584func (ex *Executor) Exec(targets []string) error {
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900585 if len(targets) == 0 {
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900586 if ex.firstRule == nil {
587 ErrorNoLocation("*** No targets.")
588 }
589 targets = append(targets, ex.firstRule.outputs[0])
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900590 }
591
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900592 LogStats("%d variables", len(ex.vars))
Shinichiro Hamaji750988e2015-04-12 10:14:32 +0900593 LogStats("%d explicit rules", len(ex.rules))
594 LogStats("%d implicit rules", len(ex.implicitRules))
595 LogStats("%d suffix rules", len(ex.suffixRules))
596
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900597 for _, target := range targets {
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900598 _, err := ex.build(target, "")
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900599 if err != nil {
600 return err
601 }
602 }
603 return nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900604}