blob: 90cb5ece35fa4debe84066d0ecc5215a7b8d66c6 [file] [log] [blame]
Fumitoshi Ukai119dc912015-03-30 16:52:41 +09001package main
2
3import (
4 "fmt"
5 "os"
6 "os/exec"
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +09007 "path/filepath"
Fumitoshi Ukai3e5161e2015-04-01 22:42:10 +09008 "strings"
Fumitoshi Ukai772fe1a2015-04-01 23:28:26 +09009 "syscall"
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090010 "time"
11)
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
Fumitoshi Ukai4b82f192015-04-07 11:36:42 +090019
20 // target -> timestamp
21 done map[string]int64
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090022}
23
24func newExecutor() *Executor {
25 return &Executor{
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +090026 rules: make(map[string]*Rule),
Shinichiro Hamaji20a43762015-04-02 02:42:25 +090027 suffixRules: make(map[string][]*Rule),
Fumitoshi Ukai4b82f192015-04-07 11:36:42 +090028 done: make(map[string]int64),
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090029 }
30}
31
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +090032// TODO(ukai): use time.Time?
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090033func getTimestamp(filename string) int64 {
34 st, err := os.Stat(filename)
35 if err != nil {
36 return -2
37 }
38 return st.ModTime().Unix()
39}
40
Fumitoshi Ukai6b378832015-04-06 16:54:37 +090041func (ex *Executor) exists(target string) bool {
Fumitoshi Ukaif04610d2015-04-07 00:03:03 +090042 _, present := ex.rules[target]
43 if present {
44 return true
45 }
Fumitoshi Ukai6b378832015-04-06 16:54:37 +090046 rule, present := ex.rules[".PHONY"]
47 if present {
48 for _, input := range rule.inputs {
49 if target == input {
50 return true
51 }
52 }
53 }
54 return exists(target)
55}
56
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +090057type runner struct {
58 output string
59 cmd string
60 echo bool
61 dryRun bool
62 ignoreError bool
Shinichiro Hamaji89551c92015-04-11 19:33:03 +090063 shell string
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +090064}
65
Shinichiro Hamaji89551c92015-04-11 19:33:03 +090066func evalCmd(ev *Evaluator, r runner, s string, shell string) []runner {
67 r = newRunner(r, s, shell)
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +090068 if strings.IndexByte(r.cmd, '$') < 0 {
69 // fast path
70 return []runner{r}
71 }
72 cmds := ev.evalExpr(r.cmd)
73 var runners []runner
74 for _, cmd := range strings.Split(cmds, "\n") {
Shinichiro Hamaji89551c92015-04-11 19:33:03 +090075 runners = append(runners, newRunner(r, cmd, shell))
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +090076 }
77 return runners
78}
79
Shinichiro Hamaji89551c92015-04-11 19:33:03 +090080func newRunner(r runner, s string, shell string) runner {
81 r.shell = shell
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +090082 for {
Shinichiro Hamajic88618f2015-04-11 19:58:06 +090083 s = trimLeftSpace(s)
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +090084 if s == "" {
85 return runner{}
Fumitoshi Ukai772fe1a2015-04-01 23:28:26 +090086 }
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +090087 switch s[0] {
88 case '@':
89 if !r.dryRun {
90 r.echo = false
91 }
92 s = s[1:]
93 continue
94 case '-':
95 r.ignoreError = true
96 s = s[1:]
Shinichiro Hamaji07e146b2015-04-02 16:17:24 +090097 continue
98 }
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +090099 break
100 }
101 r.cmd = s
102 return r
103}
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900104
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900105func (r runner) run() error {
106 if r.echo {
107 fmt.Printf("%s\n", r.cmd)
108 }
109 if r.dryRun {
110 return nil
111 }
Shinichiro Hamaji89551c92015-04-11 19:33:03 +0900112 args := []string{r.shell, "-c", r.cmd}
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900113 cmd := exec.Cmd{
114 Path: args[0],
115 Args: args,
116 }
117 out, err := cmd.CombinedOutput()
118 fmt.Printf("%s", out)
119 exit := exitStatus(err)
120 if r.ignoreError && exit != 0 {
121 fmt.Printf("[%s] Error %d (ignored)\n", r.output, exit)
122 err = nil
123 }
124 return err
125}
126
127func exitStatus(err error) int {
128 if err == nil {
129 return 0
130 }
131 exit := 1
132 if err, ok := err.(*exec.ExitError); ok {
133 if w, ok := err.ProcessState.Sys().(syscall.WaitStatus); ok {
134 return w.ExitStatus()
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900135 }
136 }
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900137 return exit
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900138}
139
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900140func replaceSuffix(s string, newsuf string) string {
141 // TODO: Factor out the logic around suffix rules and use
142 // it from substitution references.
143 // http://www.gnu.org/software/make/manual/make.html#Substitution-Refs
Shinichiro Hamaji5e2c3c72015-04-03 15:04:54 +0900144 return fmt.Sprintf("%s.%s", stripExt(s), newsuf)
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900145}
146
Shinichiro Hamaji0d0af5b2015-04-02 05:17:23 +0900147func (ex *Executor) canPickImplicitRule(rule *Rule, output string) bool {
148 outputPattern := rule.outputPatterns[0]
149 if !matchPattern(outputPattern, output) {
150 return false
151 }
152 for _, input := range rule.inputs {
153 input = substPattern(outputPattern, input, output)
Fumitoshi Ukai6b378832015-04-06 16:54:37 +0900154 if !ex.exists(input) {
Shinichiro Hamaji0d0af5b2015-04-02 05:17:23 +0900155 return false
156 }
157 }
158 return true
159}
160
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900161func (ex *Executor) pickRule(output string) (*Rule, bool) {
162 rule, present := ex.rules[output]
163 if present {
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900164 if len(rule.cmds) > 0 {
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900165 return rule, true
166 }
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900167 // If none of the explicit rules for a target has commands,
168 // then `make' searches for an applicable implicit rule to
169 // find some commands.
170 }
171
172 for _, irule := range ex.implicitRules {
173 if !ex.canPickImplicitRule(irule, output) {
174 continue
175 }
176 if rule != nil {
177 r := &Rule{}
178 *r = *rule
179 r.outputPatterns = irule.outputPatterns
180 // implicit rule's prerequisites will be used for $<
181 r.inputs = append(irule.inputs, r.inputs...)
182 if irule.vars != nil {
183 r.vars = NewVarTab(rule.vars)
184 for k, v := range irule.vars.m {
185 r.vars.Assign(k, v)
186 }
187 }
188 r.cmds = irule.cmds
189 // TODO(ukai): filename, lineno?
190 r.cmdLineno = irule.cmdLineno
191 return r, true
192 }
193 // TODO(ukai): check len(irule.cmd) ?
194 return irule, true
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900195 }
196
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900197 outputSuffix := filepath.Ext(output)
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900198 if !strings.HasPrefix(outputSuffix, ".") {
199 return rule, rule != nil
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900200 }
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900201 rules, present := ex.suffixRules[outputSuffix[1:]]
202 if !present {
203 return rule, rule != nil
204 }
205 for _, irule := range rules {
206 if len(irule.inputs) != 1 {
207 panic(fmt.Sprintf("unexpected number of input for a suffix rule (%d)", len(irule.inputs)))
208 }
Fumitoshi Ukai6b378832015-04-06 16:54:37 +0900209 if !ex.exists(replaceSuffix(output, irule.inputs[0])) {
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900210 continue
211 }
212 if rule != nil {
213 r := &Rule{}
214 *r = *rule
215 // TODO(ukai): input order is correct?
216 r.inputs = append([]string{replaceSuffix(output, irule.inputs[0])}, r.inputs...)
217 r.vars = NewVarTab(rule.vars)
Fumitoshi Ukai6b378832015-04-06 16:54:37 +0900218 if irule.vars != nil {
219 for k, v := range irule.vars.m {
220 r.vars.Assign(k, v)
221 }
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900222 }
223 r.cmds = irule.cmds
224 // TODO(ukai): filename, lineno?
225 r.cmdLineno = irule.cmdLineno
226 return r, true
227 }
228 // TODO(ukai): check len(irule.cmd) ?
229 return irule, true
230 }
231 return rule, rule != nil
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900232}
233
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900234func (ex *Executor) build(vars *VarTab, output string) (int64, error) {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900235 Log("Building: %s", output)
Fumitoshi Ukai4b82f192015-04-07 11:36:42 +0900236 outputTs, ok := ex.done[output]
237 if ok {
Fumitoshi Ukaibac3ccf2015-04-08 13:41:22 +0900238 Log("Building: %s already done: %d", output, outputTs)
Fumitoshi Ukai4b82f192015-04-07 11:36:42 +0900239 return outputTs, nil
240 }
241 outputTs = getTimestamp(output)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900242
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900243 rule, present := ex.pickRule(output)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900244 if !present {
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900245 if outputTs >= 0 {
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900246 return outputTs, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900247 }
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900248 return outputTs, fmt.Errorf("no rule to make target %q", output)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900249 }
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +0900250 if rule.vars != nil {
251 vars = NewVarTab(vars)
252 for k, v := range rule.vars.m {
253 vars.Assign(k, v)
254 }
255 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900256
257 latest := int64(-1)
Shinichiro Hamaji57aff982015-04-02 02:15:38 +0900258 var actualInputs []string
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900259 Log("Building: %s inputs:%q", output, rule.inputs)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900260 for _, input := range rule.inputs {
Shinichiro Hamaji7b203b22015-04-01 03:44:57 +0900261 if len(rule.outputPatterns) > 0 {
262 if len(rule.outputPatterns) > 1 {
263 panic("TODO: multiple output pattern is not supported yet")
264 }
265 input = substPattern(rule.outputPatterns[0], input, output)
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900266 } else if rule.isSuffixRule {
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900267 input = replaceSuffix(output, input)
Shinichiro Hamaji7b203b22015-04-01 03:44:57 +0900268 }
Shinichiro Hamaji57aff982015-04-02 02:15:38 +0900269 actualInputs = append(actualInputs, input)
Shinichiro Hamaji7b203b22015-04-01 03:44:57 +0900270
Fumitoshi Ukai3e5161e2015-04-01 22:42:10 +0900271 ts, err := ex.build(vars, input)
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900272 if err != nil {
273 return outputTs, err
274 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900275 if latest < ts {
276 latest = ts
277 }
278 }
279
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +0900280 for _, input := range rule.orderOnlyInputs {
Fumitoshi Ukaif04610d2015-04-07 00:03:03 +0900281 if exists(input) {
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +0900282 continue
283 }
284 ts, err := ex.build(vars, input)
285 if err != nil {
286 return outputTs, err
287 }
288 if latest < ts {
289 latest = ts
290 }
291 }
292
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900293 if outputTs >= latest {
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900294 return outputTs, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900295 }
296
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900297 localVars := NewVarTab(vars)
Fumitoshi Ukai3e5161e2015-04-01 22:42:10 +0900298 // automatic variables.
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900299 localVars.Assign("@", SimpleVar{value: output, origin: "automatic"})
Shinichiro Hamaji57aff982015-04-02 02:15:38 +0900300 if len(actualInputs) > 0 {
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900301 localVars.Assign("<", SimpleVar{
302 value: actualInputs[0],
303 origin: "automatic",
304 })
305 localVars.Assign("^", SimpleVar{
306 value: strings.Join(actualInputs, " "),
307 origin: "automatic",
308 })
Shinichiro Hamaji57aff982015-04-02 02:15:38 +0900309 }
Shinichiro Hamajicc919ae2015-04-09 17:23:30 +0900310 ev := newEvaluator(localVars.Vars())
Shinichiro Hamajie708a9d2015-04-03 14:34:35 +0900311 ev.filename = rule.filename
312 ev.lineno = rule.cmdLineno
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900313 var runners []runner
Fumitoshi Ukaif04610d2015-04-07 00:03:03 +0900314 Log("Building: %s cmds:%q", output, rule.cmds)
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900315 r := runner{
316 output: output,
317 echo: true,
318 dryRun: dryRunFlag,
Fumitoshi Ukai3e5161e2015-04-01 22:42:10 +0900319 }
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900320 for _, cmd := range rule.cmds {
Shinichiro Hamaji89551c92015-04-11 19:33:03 +0900321 runners = append(runners, evalCmd(ev, r, cmd, ex.shell)...)
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900322 }
323 for _, r := range runners {
324 err := r.run()
325 if err != nil {
326 exit := exitStatus(err)
327 fmt.Printf("[%s] Error %d: %v\n", r.output, exit, err)
328 return outputTs, err
329 }
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900330 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900331
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900332 outputTs = getTimestamp(output)
333 if outputTs < 0 {
334 outputTs = time.Now().Unix()
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900335 }
Fumitoshi Ukai4b82f192015-04-07 11:36:42 +0900336 ex.done[output] = outputTs
337 Log("Building: %s done %d", output, outputTs)
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900338 return outputTs, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900339}
340
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900341func (ex *Executor) populateSuffixRule(rule *Rule, output string) bool {
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900342 if len(output) == 0 || output[0] != '.' {
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900343 return false
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900344 }
345 rest := output[1:]
346 dotIndex := strings.IndexByte(rest, '.')
347 // If there is only a single dot or the third dot, this is not a
348 // suffix rule.
349 if dotIndex < 0 || strings.IndexByte(rest[dotIndex+1:], '.') >= 0 {
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900350 return false
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900351 }
352
353 // This is a suffix rule.
354 inputSuffix := rest[:dotIndex]
355 outputSuffix := rest[dotIndex+1:]
356 r := &Rule{}
357 *r = *rule
358 r.inputs = []string{inputSuffix}
359 r.isSuffixRule = true
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900360 ex.suffixRules[outputSuffix] = append([]*Rule{r}, ex.suffixRules[outputSuffix]...)
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900361 return true
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900362}
363
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900364func (ex *Executor) populateExplicitRule(rule *Rule) {
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900365 // It seems rules with no outputs are siliently ignored.
366 if len(rule.outputs) == 0 {
367 return
368 }
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900369 for _, output := range rule.outputs {
Fumitoshi Ukaie1e34442015-04-08 13:10:05 +0900370 output = filepath.Clean(output)
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900371
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900372 isSuffixRule := ex.populateSuffixRule(rule, output)
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900373
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900374 if oldRule, present := ex.rules[output]; present {
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +0900375 if oldRule.vars != nil || rule.vars != nil {
376 oldRule.isDoubleColon = rule.isDoubleColon
377 switch {
378 case rule.vars == nil && oldRule.vars != nil:
379 rule.vars = oldRule.vars
380 case rule.vars != nil && oldRule.vars == nil:
381 case rule.vars != nil && oldRule.vars != nil:
382 // parent would be the same vars?
383 for k, v := range rule.vars.m {
384 oldRule.vars.m[k] = v
385 }
386 rule.vars = oldRule.vars
387 }
388 }
Shinichiro Hamajicc3abc32015-04-02 04:46:49 +0900389 if oldRule.isDoubleColon != rule.isDoubleColon {
390 Error(rule.filename, rule.lineno, "*** target file %q has both : and :: entries.", output)
391 }
392 if len(oldRule.cmds) > 0 && len(rule.cmds) > 0 && !isSuffixRule && !rule.isDoubleColon {
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900393 Warn(rule.filename, rule.cmdLineno, "overriding commands for target %q", output)
394 Warn(oldRule.filename, oldRule.cmdLineno, "ignoring old commands for target %q", output)
395 }
396 r := &Rule{}
397 *r = *rule
Shinichiro Hamajicc3abc32015-04-02 04:46:49 +0900398 if rule.isDoubleColon {
399 r.cmds = append(oldRule.cmds, r.cmds...)
Fumitoshi Ukaic97f49c2015-04-07 00:16:38 +0900400 } else if len(oldRule.cmds) > 0 && len(rule.cmds) == 0 {
401 r.cmds = oldRule.cmds
Shinichiro Hamajicc3abc32015-04-02 04:46:49 +0900402 }
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900403 r.inputs = append(r.inputs, oldRule.inputs...)
Fumitoshi Ukai79fcf972015-04-07 11:10:29 +0900404 r.orderOnlyInputs = append(r.orderOnlyInputs, oldRule.orderOnlyInputs...)
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900405 ex.rules[output] = r
406 } else {
407 ex.rules[output] = rule
Shinichiro Hamaji4a1cfc22015-04-11 13:54:46 +0900408 if ex.firstRule == nil && !strings.HasPrefix(output, ".") {
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900409 ex.firstRule = rule
410 }
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900411 }
412 }
413}
414
415func (ex *Executor) populateImplicitRule(rule *Rule) {
416 for _, outputPattern := range rule.outputPatterns {
417 r := &Rule{}
418 *r = *rule
419 r.outputPatterns = []string{outputPattern}
420 ex.implicitRules = append(ex.implicitRules, r)
421 }
422}
423
424func (ex *Executor) populateRules(er *EvalResult) {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900425 for _, rule := range er.rules {
Fumitoshi Ukaibac3ccf2015-04-08 13:41:22 +0900426 for i, input := range rule.inputs {
427 rule.inputs[i] = filepath.Clean(input)
428 }
429 for i, orderOnlyInput := range rule.orderOnlyInputs {
430 rule.orderOnlyInputs[i] = filepath.Clean(orderOnlyInput)
431 }
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900432 ex.populateExplicitRule(rule)
433
434 if len(rule.outputs) == 0 {
435 ex.populateImplicitRule(rule)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900436 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900437 }
438
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900439 // Reverse the implicit rule for easier lookup.
440 for i, r := range ex.implicitRules {
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900441 if i >= len(ex.implicitRules)/2 {
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900442 break
443 }
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900444 j := len(ex.implicitRules) - i - 1
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900445 ex.implicitRules[i] = ex.implicitRules[j]
446 ex.implicitRules[j] = r
447 }
448}
449
Shinichiro Hamaji574a4ef2015-04-06 15:20:28 +0900450func (ex *Executor) exec(er *EvalResult, targets []string, vars *VarTab) error {
Shinichiro Hamaji89551c92015-04-11 19:33:03 +0900451 // TODO: We should move this to somewhere around evalCmd so that
452 // we can handle SHELL in target specific variables.
453 shellVar := vars.Lookup("SHELL")
454 ex.shell = shellVar.String()
455
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900456 ex.populateRules(er)
457
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900458 if len(targets) == 0 {
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900459 if ex.firstRule == nil {
460 ErrorNoLocation("*** No targets.")
461 }
462 targets = append(targets, ex.firstRule.outputs[0])
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900463 }
464
465 for _, target := range targets {
Shinichiro Hamaji574a4ef2015-04-06 15:20:28 +0900466 _, err := ex.build(vars, target)
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900467 if err != nil {
468 return err
469 }
470 }
471 return nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900472}
473
Shinichiro Hamaji574a4ef2015-04-06 15:20:28 +0900474func Exec(er *EvalResult, targets []string, vars *VarTab) error {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900475 ex := newExecutor()
Shinichiro Hamaji574a4ef2015-04-06 15:20:28 +0900476 return ex.exec(er, targets, vars)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900477}