blob: 4ded636c54689cf125a63b8c9a8a8b80bb141464 [file] [log] [blame]
Fumitoshi Ukai119dc912015-03-30 16:52:41 +09001package main
2
3import (
4 "fmt"
Shinichiro Hamaji110af332015-04-13 19:04:50 +09005 "io"
Fumitoshi Ukai119dc912015-03-30 16:52:41 +09006 "os"
7 "os/exec"
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +09008 "path/filepath"
Fumitoshi Ukai3e5161e2015-04-01 22:42:10 +09009 "strings"
Fumitoshi Ukai772fe1a2015-04-01 23:28:26 +090010 "syscall"
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090011 "time"
12)
13
14type Executor struct {
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +090015 rules map[string]*Rule
16 implicitRules []*Rule
Shinichiro Hamaji20a43762015-04-02 02:42:25 +090017 suffixRules map[string][]*Rule
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +090018 firstRule *Rule
Shinichiro Hamaji89551c92015-04-11 19:33:03 +090019 shell string
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +090020 vars Vars
Shinichiro Hamaji940bb6c2015-04-13 00:35:59 +090021 // target -> timestamp, a negative timestamp means the target is
22 // currently being processed.
Fumitoshi Ukai4b82f192015-04-07 11:36:42 +090023 done map[string]int64
Shinichiro Hamaji110af332015-04-13 19:04:50 +090024
25 currentOutput string
26 currentInputs []string
27 currentStem string
28}
29
30type AutoVar struct{ ex *Executor }
31
32func (v AutoVar) Flavor() string { return "undefined" }
33func (v AutoVar) Origin() string { return "automatic" }
34func (v AutoVar) IsDefined() bool { panic("not implemented") }
35func (v AutoVar) String() string { panic("not implemented") }
36func (v AutoVar) Append(ev *Evaluator, s string) Var {
37 panic("must not be called")
38}
39
40type AutoAtVar struct{ AutoVar }
41
42func (v AutoAtVar) Eval(w io.Writer, ev *Evaluator) {
43 fmt.Fprint(w, v.ex.currentOutput)
44}
45
46type AutoLessVar struct{ AutoVar }
47
48func (v AutoLessVar) Eval(w io.Writer, ev *Evaluator) {
49 if len(v.ex.currentInputs) > 0 {
50 fmt.Fprint(w, v.ex.currentInputs[0])
51 }
52}
53
54type AutoHatVar struct{ AutoVar }
55
56func (v AutoHatVar) Eval(w io.Writer, ev *Evaluator) {
Shinichiro Hamajia622c5e2015-04-13 19:09:30 +090057 var uniqueInputs []string
58 seen := make(map[string]bool)
59 for _, input := range v.ex.currentInputs {
60 if !seen[input] {
61 seen[input] = true
62 uniqueInputs = append(uniqueInputs, input)
63 }
64 }
65 fmt.Fprint(w, strings.Join(uniqueInputs, " "))
66}
67
68type AutoPlusVar struct{ AutoVar }
69
70func (v AutoPlusVar) Eval(w io.Writer, ev *Evaluator) {
Shinichiro Hamaji110af332015-04-13 19:04:50 +090071 fmt.Fprint(w, strings.Join(v.ex.currentInputs, " "))
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090072}
73
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +090074func newExecutor(vars Vars) *Executor {
Shinichiro Hamaji110af332015-04-13 19:04:50 +090075 ex := &Executor{
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +090076 rules: make(map[string]*Rule),
Shinichiro Hamaji20a43762015-04-02 02:42:25 +090077 suffixRules: make(map[string][]*Rule),
Fumitoshi Ukai4b82f192015-04-07 11:36:42 +090078 done: make(map[string]int64),
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +090079 vars: vars,
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090080 }
Shinichiro Hamaji110af332015-04-13 19:04:50 +090081
82 ex.vars["@"] = AutoAtVar{AutoVar: AutoVar{ex: ex}}
83 ex.vars["<"] = AutoLessVar{AutoVar: AutoVar{ex: ex}}
84 ex.vars["^"] = AutoHatVar{AutoVar: AutoVar{ex: ex}}
Shinichiro Hamajia622c5e2015-04-13 19:09:30 +090085 ex.vars["+"] = AutoPlusVar{AutoVar: AutoVar{ex: ex}}
Shinichiro Hamaji110af332015-04-13 19:04:50 +090086
87 return ex
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090088}
89
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +090090// TODO(ukai): use time.Time?
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090091func getTimestamp(filename string) int64 {
92 st, err := os.Stat(filename)
93 if err != nil {
94 return -2
95 }
96 return st.ModTime().Unix()
97}
98
Fumitoshi Ukai6b378832015-04-06 16:54:37 +090099func (ex *Executor) exists(target string) bool {
Fumitoshi Ukaif04610d2015-04-07 00:03:03 +0900100 _, present := ex.rules[target]
101 if present {
102 return true
103 }
Fumitoshi Ukai6b378832015-04-06 16:54:37 +0900104 rule, present := ex.rules[".PHONY"]
105 if present {
106 for _, input := range rule.inputs {
107 if target == input {
108 return true
109 }
110 }
111 }
112 return exists(target)
113}
114
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900115type runner struct {
116 output string
117 cmd string
118 echo bool
119 dryRun bool
120 ignoreError bool
Shinichiro Hamaji89551c92015-04-11 19:33:03 +0900121 shell string
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900122}
123
Shinichiro Hamaji973c69f2015-04-11 21:52:38 +0900124func evalCmd(ev *Evaluator, r runner, s string) []runner {
125 r = newRunner(r, s)
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900126 if strings.IndexByte(r.cmd, '$') < 0 {
127 // fast path
128 return []runner{r}
129 }
130 cmds := ev.evalExpr(r.cmd)
131 var runners []runner
132 for _, cmd := range strings.Split(cmds, "\n") {
Shinichiro Hamaji77353192015-04-13 16:04:15 +0900133 if len(runners) > 0 && strings.HasSuffix(runners[0].cmd, "\\") {
134 runners[0].cmd += "\n"
135 runners[0].cmd += cmd
136 } else {
137 runners = append(runners, newRunner(r, cmd))
138 }
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900139 }
140 return runners
141}
142
Shinichiro Hamaji973c69f2015-04-11 21:52:38 +0900143func newRunner(r runner, s string) runner {
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900144 for {
Shinichiro Hamajic88618f2015-04-11 19:58:06 +0900145 s = trimLeftSpace(s)
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900146 if s == "" {
147 return runner{}
Fumitoshi Ukai772fe1a2015-04-01 23:28:26 +0900148 }
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900149 switch s[0] {
150 case '@':
151 if !r.dryRun {
152 r.echo = false
153 }
154 s = s[1:]
155 continue
156 case '-':
157 r.ignoreError = true
158 s = s[1:]
Shinichiro Hamaji07e146b2015-04-02 16:17:24 +0900159 continue
160 }
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900161 break
162 }
163 r.cmd = s
164 return r
165}
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900166
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900167func (r runner) run() error {
168 if r.echo {
169 fmt.Printf("%s\n", r.cmd)
170 }
171 if r.dryRun {
172 return nil
173 }
Shinichiro Hamaji89551c92015-04-11 19:33:03 +0900174 args := []string{r.shell, "-c", r.cmd}
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900175 cmd := exec.Cmd{
176 Path: args[0],
177 Args: args,
178 }
179 out, err := cmd.CombinedOutput()
180 fmt.Printf("%s", out)
181 exit := exitStatus(err)
182 if r.ignoreError && exit != 0 {
183 fmt.Printf("[%s] Error %d (ignored)\n", r.output, exit)
184 err = nil
185 }
186 return err
187}
188
189func exitStatus(err error) int {
190 if err == nil {
191 return 0
192 }
193 exit := 1
194 if err, ok := err.(*exec.ExitError); ok {
195 if w, ok := err.ProcessState.Sys().(syscall.WaitStatus); ok {
196 return w.ExitStatus()
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900197 }
198 }
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900199 return exit
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900200}
201
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900202func replaceSuffix(s string, newsuf string) string {
203 // TODO: Factor out the logic around suffix rules and use
204 // it from substitution references.
205 // http://www.gnu.org/software/make/manual/make.html#Substitution-Refs
Shinichiro Hamaji5e2c3c72015-04-03 15:04:54 +0900206 return fmt.Sprintf("%s.%s", stripExt(s), newsuf)
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900207}
208
Shinichiro Hamaji0d0af5b2015-04-02 05:17:23 +0900209func (ex *Executor) canPickImplicitRule(rule *Rule, output string) bool {
210 outputPattern := rule.outputPatterns[0]
211 if !matchPattern(outputPattern, output) {
212 return false
213 }
214 for _, input := range rule.inputs {
215 input = substPattern(outputPattern, input, output)
Fumitoshi Ukai6b378832015-04-06 16:54:37 +0900216 if !ex.exists(input) {
Shinichiro Hamaji0d0af5b2015-04-02 05:17:23 +0900217 return false
218 }
219 }
220 return true
221}
222
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900223func (ex *Executor) pickRule(output string) (*Rule, bool) {
224 rule, present := ex.rules[output]
225 if present {
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900226 if len(rule.cmds) > 0 {
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900227 return rule, true
228 }
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900229 // If none of the explicit rules for a target has commands,
230 // then `make' searches for an applicable implicit rule to
231 // find some commands.
232 }
233
234 for _, irule := range ex.implicitRules {
235 if !ex.canPickImplicitRule(irule, output) {
236 continue
237 }
238 if rule != nil {
239 r := &Rule{}
240 *r = *rule
241 r.outputPatterns = irule.outputPatterns
242 // implicit rule's prerequisites will be used for $<
243 r.inputs = append(irule.inputs, r.inputs...)
244 if irule.vars != nil {
Shinichiro Hamaji63a77d42015-04-12 01:04:07 +0900245 r.vars = NewVars(rule.vars)
246 r.vars.Merge(irule.vars)
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900247 }
248 r.cmds = irule.cmds
249 // TODO(ukai): filename, lineno?
250 r.cmdLineno = irule.cmdLineno
251 return r, true
252 }
253 // TODO(ukai): check len(irule.cmd) ?
254 return irule, true
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900255 }
256
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900257 outputSuffix := filepath.Ext(output)
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900258 if !strings.HasPrefix(outputSuffix, ".") {
259 return rule, rule != nil
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900260 }
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900261 rules, present := ex.suffixRules[outputSuffix[1:]]
262 if !present {
263 return rule, rule != nil
264 }
265 for _, irule := range rules {
266 if len(irule.inputs) != 1 {
267 panic(fmt.Sprintf("unexpected number of input for a suffix rule (%d)", len(irule.inputs)))
268 }
Fumitoshi Ukai6b378832015-04-06 16:54:37 +0900269 if !ex.exists(replaceSuffix(output, irule.inputs[0])) {
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900270 continue
271 }
272 if rule != nil {
273 r := &Rule{}
274 *r = *rule
275 // TODO(ukai): input order is correct?
276 r.inputs = append([]string{replaceSuffix(output, irule.inputs[0])}, r.inputs...)
Shinichiro Hamaji63a77d42015-04-12 01:04:07 +0900277 r.vars = NewVars(rule.vars)
278 r.vars.Merge(irule.vars)
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900279 r.cmds = irule.cmds
280 // TODO(ukai): filename, lineno?
281 r.cmdLineno = irule.cmdLineno
282 return r, true
283 }
284 // TODO(ukai): check len(irule.cmd) ?
285 return irule, true
286 }
287 return rule, rule != nil
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900288}
289
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900290func (ex *Executor) build(output string, neededBy string) (int64, error) {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900291 Log("Building: %s", output)
Fumitoshi Ukai4b82f192015-04-07 11:36:42 +0900292 outputTs, ok := ex.done[output]
293 if ok {
Shinichiro Hamaji940bb6c2015-04-13 00:35:59 +0900294 if outputTs < 0 {
295 fmt.Printf("Circular %s <- %s dependency dropped.\n", neededBy, output)
296 }
Fumitoshi Ukaibac3ccf2015-04-08 13:41:22 +0900297 Log("Building: %s already done: %d", output, outputTs)
Fumitoshi Ukai4b82f192015-04-07 11:36:42 +0900298 return outputTs, nil
299 }
Shinichiro Hamaji940bb6c2015-04-13 00:35:59 +0900300 ex.done[output] = -1
Fumitoshi Ukai4b82f192015-04-07 11:36:42 +0900301 outputTs = getTimestamp(output)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900302
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900303 rule, present := ex.pickRule(output)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900304 if !present {
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900305 if outputTs >= 0 {
Shinichiro Hamaji61748ac2015-04-13 01:08:43 +0900306 ex.done[output] = outputTs
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900307 return outputTs, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900308 }
Shinichiro Hamajieb4da7f2015-04-11 20:28:54 +0900309 if neededBy == "" {
310 ErrorNoLocation("*** No rule to make target %q.", output)
311 } else {
312 ErrorNoLocation("*** No rule to make target %q, needed by %q.", output, neededBy)
313 }
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900314 return outputTs, fmt.Errorf("no rule to make target %q", output)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900315 }
Shinichiro Hamaji4e9ab1a2015-04-12 01:31:58 +0900316
317 var olds []oldVar
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +0900318 if rule.vars != nil {
Shinichiro Hamaji4e9ab1a2015-04-12 01:31:58 +0900319 for k, v := range rule.vars {
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900320 olds = append(olds, newOldVar(ex.vars, k))
321 ex.vars[k] = v
Shinichiro Hamaji4e9ab1a2015-04-12 01:31:58 +0900322 }
323 defer func() {
324 for _, old := range olds {
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900325 old.restore(ex.vars)
Shinichiro Hamaji4e9ab1a2015-04-12 01:31:58 +0900326 }
327 }()
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +0900328 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900329
330 latest := int64(-1)
Shinichiro Hamaji57aff982015-04-02 02:15:38 +0900331 var actualInputs []string
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900332 Log("Building: %s inputs:%q", output, rule.inputs)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900333 for _, input := range rule.inputs {
Shinichiro Hamaji7b203b22015-04-01 03:44:57 +0900334 if len(rule.outputPatterns) > 0 {
335 if len(rule.outputPatterns) > 1 {
336 panic("TODO: multiple output pattern is not supported yet")
337 }
338 input = substPattern(rule.outputPatterns[0], input, output)
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900339 } else if rule.isSuffixRule {
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900340 input = replaceSuffix(output, input)
Shinichiro Hamaji7b203b22015-04-01 03:44:57 +0900341 }
Shinichiro Hamaji57aff982015-04-02 02:15:38 +0900342 actualInputs = append(actualInputs, input)
Shinichiro Hamaji7b203b22015-04-01 03:44:57 +0900343
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900344 ts, err := ex.build(input, output)
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900345 if err != nil {
346 return outputTs, err
347 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900348 if latest < ts {
349 latest = ts
350 }
351 }
352
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +0900353 for _, input := range rule.orderOnlyInputs {
Fumitoshi Ukaif04610d2015-04-07 00:03:03 +0900354 if exists(input) {
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +0900355 continue
356 }
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900357 ts, err := ex.build(input, output)
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +0900358 if err != nil {
359 return outputTs, err
360 }
361 if latest < ts {
362 latest = ts
363 }
364 }
365
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900366 if outputTs >= latest {
Shinichiro Hamaji61748ac2015-04-13 01:08:43 +0900367 ex.done[output] = outputTs
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900368 return outputTs, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900369 }
370
Shinichiro Hamaji110af332015-04-13 19:04:50 +0900371 // For automatic variables.
372 ex.currentOutput = output
373 ex.currentInputs = actualInputs
374
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900375 ev := newEvaluator(ex.vars)
Shinichiro Hamajie708a9d2015-04-03 14:34:35 +0900376 ev.filename = rule.filename
377 ev.lineno = rule.cmdLineno
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900378 var runners []runner
Fumitoshi Ukaif04610d2015-04-07 00:03:03 +0900379 Log("Building: %s cmds:%q", output, rule.cmds)
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900380 r := runner{
381 output: output,
382 echo: true,
383 dryRun: dryRunFlag,
Shinichiro Hamaji77353192015-04-13 16:04:15 +0900384 shell: ex.shell,
Fumitoshi Ukai3e5161e2015-04-01 22:42:10 +0900385 }
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900386 for _, cmd := range rule.cmds {
Shinichiro Hamaji973c69f2015-04-11 21:52:38 +0900387 for _, r := range evalCmd(ev, r, cmd) {
388 if len(r.cmd) != 0 {
389 runners = append(runners, r)
390 }
391 }
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900392 }
393 for _, r := range runners {
394 err := r.run()
395 if err != nil {
396 exit := exitStatus(err)
397 fmt.Printf("[%s] Error %d: %v\n", r.output, exit, err)
398 return outputTs, err
399 }
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900400 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900401
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900402 outputTs = getTimestamp(output)
403 if outputTs < 0 {
404 outputTs = time.Now().Unix()
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900405 }
Fumitoshi Ukai4b82f192015-04-07 11:36:42 +0900406 ex.done[output] = outputTs
407 Log("Building: %s done %d", output, outputTs)
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900408 return outputTs, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900409}
410
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900411func (ex *Executor) populateSuffixRule(rule *Rule, output string) bool {
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900412 if len(output) == 0 || output[0] != '.' {
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900413 return false
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900414 }
415 rest := output[1:]
416 dotIndex := strings.IndexByte(rest, '.')
417 // If there is only a single dot or the third dot, this is not a
418 // suffix rule.
419 if dotIndex < 0 || strings.IndexByte(rest[dotIndex+1:], '.') >= 0 {
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900420 return false
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900421 }
422
423 // This is a suffix rule.
424 inputSuffix := rest[:dotIndex]
425 outputSuffix := rest[dotIndex+1:]
426 r := &Rule{}
427 *r = *rule
428 r.inputs = []string{inputSuffix}
429 r.isSuffixRule = true
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900430 ex.suffixRules[outputSuffix] = append([]*Rule{r}, ex.suffixRules[outputSuffix]...)
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900431 return true
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900432}
433
Shinichiro Hamajid1bd3312015-04-13 18:21:08 +0900434func mergeRules(oldRule, rule *Rule, output string, isSuffixRule bool) *Rule {
Shinichiro Hamajifaeba682015-04-13 18:11:27 +0900435 if oldRule.vars != nil || rule.vars != nil {
436 oldRule.isDoubleColon = rule.isDoubleColon
437 switch {
438 case rule.vars == nil && oldRule.vars != nil:
439 rule.vars = oldRule.vars
440 case rule.vars != nil && oldRule.vars == nil:
441 case rule.vars != nil && oldRule.vars != nil:
442 // parent would be the same vars?
443 oldRule.vars.Merge(rule.vars)
444 rule.vars = oldRule.vars
445 }
446 }
447
Shinichiro Hamajid1bd3312015-04-13 18:21:08 +0900448 if oldRule.isDoubleColon != rule.isDoubleColon {
449 Error(rule.filename, rule.lineno, "*** target file %q has both : and :: entries.", output)
450 }
451 if len(oldRule.cmds) > 0 && len(rule.cmds) > 0 && !isSuffixRule && !rule.isDoubleColon {
452 Warn(rule.filename, rule.cmdLineno, "overriding commands for target %q", output)
453 Warn(oldRule.filename, oldRule.cmdLineno, "ignoring old commands for target %q", output)
454 }
455
Shinichiro Hamajifaeba682015-04-13 18:11:27 +0900456 r := &Rule{}
457 *r = *rule
458 if rule.isDoubleColon {
459 r.cmds = append(oldRule.cmds, r.cmds...)
460 } else if len(oldRule.cmds) > 0 && len(rule.cmds) == 0 {
461 r.cmds = oldRule.cmds
462 }
463 // If the latter rule has a command (regardless of the
464 // commands in oldRule), inputs in the latter rule has a
465 // priority.
466 if len(rule.cmds) > 0 {
467 r.inputs = append(r.inputs, oldRule.inputs...)
468 r.orderOnlyInputs = append(r.orderOnlyInputs, oldRule.orderOnlyInputs...)
469 } else {
470 r.inputs = append(oldRule.inputs, r.inputs...)
471 r.orderOnlyInputs = append(oldRule.orderOnlyInputs, r.orderOnlyInputs...)
472 }
473 r.outputPatterns = append(r.outputPatterns, oldRule.outputPatterns...)
474 return r
475}
476
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900477func (ex *Executor) populateExplicitRule(rule *Rule) {
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900478 // It seems rules with no outputs are siliently ignored.
479 if len(rule.outputs) == 0 {
480 return
481 }
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900482 for _, output := range rule.outputs {
Fumitoshi Ukaie1e34442015-04-08 13:10:05 +0900483 output = filepath.Clean(output)
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900484
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900485 isSuffixRule := ex.populateSuffixRule(rule, output)
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900486
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900487 if oldRule, present := ex.rules[output]; present {
Shinichiro Hamajid1bd3312015-04-13 18:21:08 +0900488 r := mergeRules(oldRule, rule, output, isSuffixRule)
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900489 ex.rules[output] = r
490 } else {
491 ex.rules[output] = rule
Shinichiro Hamaji4a1cfc22015-04-11 13:54:46 +0900492 if ex.firstRule == nil && !strings.HasPrefix(output, ".") {
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900493 ex.firstRule = rule
494 }
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900495 }
496 }
497}
498
499func (ex *Executor) populateImplicitRule(rule *Rule) {
500 for _, outputPattern := range rule.outputPatterns {
501 r := &Rule{}
502 *r = *rule
503 r.outputPatterns = []string{outputPattern}
504 ex.implicitRules = append(ex.implicitRules, r)
505 }
506}
507
508func (ex *Executor) populateRules(er *EvalResult) {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900509 for _, rule := range er.rules {
Fumitoshi Ukaibac3ccf2015-04-08 13:41:22 +0900510 for i, input := range rule.inputs {
511 rule.inputs[i] = filepath.Clean(input)
512 }
513 for i, orderOnlyInput := range rule.orderOnlyInputs {
514 rule.orderOnlyInputs[i] = filepath.Clean(orderOnlyInput)
515 }
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900516 ex.populateExplicitRule(rule)
517
518 if len(rule.outputs) == 0 {
519 ex.populateImplicitRule(rule)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900520 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900521 }
522
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900523 // Reverse the implicit rule for easier lookup.
524 for i, r := range ex.implicitRules {
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900525 if i >= len(ex.implicitRules)/2 {
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900526 break
527 }
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900528 j := len(ex.implicitRules) - i - 1
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900529 ex.implicitRules[i] = ex.implicitRules[j]
530 ex.implicitRules[j] = r
531 }
532}
533
Shinichiro Hamaji8843a052015-04-13 16:46:56 +0900534func NewExecutor(er *EvalResult, vars Vars) *Executor {
535 ex := newExecutor(vars)
Shinichiro Hamaji89551c92015-04-11 19:33:03 +0900536 // TODO: We should move this to somewhere around evalCmd so that
537 // we can handle SHELL in target specific variables.
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900538 shellVar := ex.vars.Lookup("SHELL")
Shinichiro Hamaji89551c92015-04-11 19:33:03 +0900539 ex.shell = shellVar.String()
540
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900541 ex.populateRules(er)
Shinichiro Hamaji8843a052015-04-13 16:46:56 +0900542 return ex
543}
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900544
Shinichiro Hamaji8843a052015-04-13 16:46:56 +0900545func (ex *Executor) Exec(targets []string) error {
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900546 if len(targets) == 0 {
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900547 if ex.firstRule == nil {
548 ErrorNoLocation("*** No targets.")
549 }
550 targets = append(targets, ex.firstRule.outputs[0])
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900551 }
552
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900553 LogStats("%d variables", len(ex.vars))
Shinichiro Hamaji750988e2015-04-12 10:14:32 +0900554 LogStats("%d explicit rules", len(ex.rules))
555 LogStats("%d implicit rules", len(ex.implicitRules))
556 LogStats("%d suffix rules", len(ex.suffixRules))
557
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900558 for _, target := range targets {
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900559 _, err := ex.build(target, "")
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900560 if err != nil {
561 return err
562 }
563 }
564 return nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900565}