blob: b0edda01f930e10951ea8b5694086293002723b5 [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 Hamaji973c69f2015-04-11 21:52:38 +090066func evalCmd(ev *Evaluator, r runner, s string) []runner {
67 r = newRunner(r, s)
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 Hamaji973c69f2015-04-11 21:52:38 +090075 runners = append(runners, newRunner(r, cmd))
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +090076 }
77 return runners
78}
79
Shinichiro Hamaji973c69f2015-04-11 21:52:38 +090080func newRunner(r runner, s string) runner {
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +090081 for {
Shinichiro Hamajic88618f2015-04-11 19:58:06 +090082 s = trimLeftSpace(s)
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +090083 if s == "" {
84 return runner{}
Fumitoshi Ukai772fe1a2015-04-01 23:28:26 +090085 }
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +090086 switch s[0] {
87 case '@':
88 if !r.dryRun {
89 r.echo = false
90 }
91 s = s[1:]
92 continue
93 case '-':
94 r.ignoreError = true
95 s = s[1:]
Shinichiro Hamaji07e146b2015-04-02 16:17:24 +090096 continue
97 }
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +090098 break
99 }
100 r.cmd = s
101 return r
102}
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900103
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900104func (r runner) run() error {
105 if r.echo {
106 fmt.Printf("%s\n", r.cmd)
107 }
108 if r.dryRun {
109 return nil
110 }
Shinichiro Hamaji89551c92015-04-11 19:33:03 +0900111 args := []string{r.shell, "-c", r.cmd}
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900112 cmd := exec.Cmd{
113 Path: args[0],
114 Args: args,
115 }
116 out, err := cmd.CombinedOutput()
117 fmt.Printf("%s", out)
118 exit := exitStatus(err)
119 if r.ignoreError && exit != 0 {
120 fmt.Printf("[%s] Error %d (ignored)\n", r.output, exit)
121 err = nil
122 }
123 return err
124}
125
126func exitStatus(err error) int {
127 if err == nil {
128 return 0
129 }
130 exit := 1
131 if err, ok := err.(*exec.ExitError); ok {
132 if w, ok := err.ProcessState.Sys().(syscall.WaitStatus); ok {
133 return w.ExitStatus()
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900134 }
135 }
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900136 return exit
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900137}
138
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900139func replaceSuffix(s string, newsuf string) string {
140 // TODO: Factor out the logic around suffix rules and use
141 // it from substitution references.
142 // http://www.gnu.org/software/make/manual/make.html#Substitution-Refs
Shinichiro Hamaji5e2c3c72015-04-03 15:04:54 +0900143 return fmt.Sprintf("%s.%s", stripExt(s), newsuf)
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900144}
145
Shinichiro Hamaji0d0af5b2015-04-02 05:17:23 +0900146func (ex *Executor) canPickImplicitRule(rule *Rule, output string) bool {
147 outputPattern := rule.outputPatterns[0]
148 if !matchPattern(outputPattern, output) {
149 return false
150 }
151 for _, input := range rule.inputs {
152 input = substPattern(outputPattern, input, output)
Fumitoshi Ukai6b378832015-04-06 16:54:37 +0900153 if !ex.exists(input) {
Shinichiro Hamaji0d0af5b2015-04-02 05:17:23 +0900154 return false
155 }
156 }
157 return true
158}
159
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900160func (ex *Executor) pickRule(output string) (*Rule, bool) {
161 rule, present := ex.rules[output]
162 if present {
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900163 if len(rule.cmds) > 0 {
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900164 return rule, true
165 }
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900166 // If none of the explicit rules for a target has commands,
167 // then `make' searches for an applicable implicit rule to
168 // find some commands.
169 }
170
171 for _, irule := range ex.implicitRules {
172 if !ex.canPickImplicitRule(irule, output) {
173 continue
174 }
175 if rule != nil {
176 r := &Rule{}
177 *r = *rule
178 r.outputPatterns = irule.outputPatterns
179 // implicit rule's prerequisites will be used for $<
180 r.inputs = append(irule.inputs, r.inputs...)
181 if irule.vars != nil {
Shinichiro Hamaji63a77d42015-04-12 01:04:07 +0900182 r.vars = NewVars(rule.vars)
183 r.vars.Merge(irule.vars)
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900184 }
185 r.cmds = irule.cmds
186 // TODO(ukai): filename, lineno?
187 r.cmdLineno = irule.cmdLineno
188 return r, true
189 }
190 // TODO(ukai): check len(irule.cmd) ?
191 return irule, true
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900192 }
193
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900194 outputSuffix := filepath.Ext(output)
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900195 if !strings.HasPrefix(outputSuffix, ".") {
196 return rule, rule != nil
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900197 }
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900198 rules, present := ex.suffixRules[outputSuffix[1:]]
199 if !present {
200 return rule, rule != nil
201 }
202 for _, irule := range rules {
203 if len(irule.inputs) != 1 {
204 panic(fmt.Sprintf("unexpected number of input for a suffix rule (%d)", len(irule.inputs)))
205 }
Fumitoshi Ukai6b378832015-04-06 16:54:37 +0900206 if !ex.exists(replaceSuffix(output, irule.inputs[0])) {
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900207 continue
208 }
209 if rule != nil {
210 r := &Rule{}
211 *r = *rule
212 // TODO(ukai): input order is correct?
213 r.inputs = append([]string{replaceSuffix(output, irule.inputs[0])}, r.inputs...)
Shinichiro Hamaji63a77d42015-04-12 01:04:07 +0900214 r.vars = NewVars(rule.vars)
215 r.vars.Merge(irule.vars)
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900216 r.cmds = irule.cmds
217 // TODO(ukai): filename, lineno?
218 r.cmdLineno = irule.cmdLineno
219 return r, true
220 }
221 // TODO(ukai): check len(irule.cmd) ?
222 return irule, true
223 }
224 return rule, rule != nil
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900225}
226
Shinichiro Hamaji63a77d42015-04-12 01:04:07 +0900227func (ex *Executor) build(vars Vars, output string, neededBy string) (int64, error) {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900228 Log("Building: %s", output)
Fumitoshi Ukai4b82f192015-04-07 11:36:42 +0900229 outputTs, ok := ex.done[output]
230 if ok {
Fumitoshi Ukaibac3ccf2015-04-08 13:41:22 +0900231 Log("Building: %s already done: %d", output, outputTs)
Fumitoshi Ukai4b82f192015-04-07 11:36:42 +0900232 return outputTs, nil
233 }
234 outputTs = getTimestamp(output)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900235
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900236 rule, present := ex.pickRule(output)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900237 if !present {
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900238 if outputTs >= 0 {
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900239 return outputTs, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900240 }
Shinichiro Hamajieb4da7f2015-04-11 20:28:54 +0900241 if neededBy == "" {
242 ErrorNoLocation("*** No rule to make target %q.", output)
243 } else {
244 ErrorNoLocation("*** No rule to make target %q, needed by %q.", output, neededBy)
245 }
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900246 return outputTs, fmt.Errorf("no rule to make target %q", output)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900247 }
Shinichiro Hamaji4e9ab1a2015-04-12 01:31:58 +0900248
249 var olds []oldVar
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +0900250 if rule.vars != nil {
Shinichiro Hamaji4e9ab1a2015-04-12 01:31:58 +0900251 for k, v := range rule.vars {
252 olds = append(olds, newOldVar(vars, k))
253 vars[k] = v
254 }
255 defer func() {
256 for _, old := range olds {
257 old.restore(vars)
258 }
259 }()
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +0900260 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900261
262 latest := int64(-1)
Shinichiro Hamaji57aff982015-04-02 02:15:38 +0900263 var actualInputs []string
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900264 Log("Building: %s inputs:%q", output, rule.inputs)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900265 for _, input := range rule.inputs {
Shinichiro Hamaji7b203b22015-04-01 03:44:57 +0900266 if len(rule.outputPatterns) > 0 {
267 if len(rule.outputPatterns) > 1 {
268 panic("TODO: multiple output pattern is not supported yet")
269 }
270 input = substPattern(rule.outputPatterns[0], input, output)
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900271 } else if rule.isSuffixRule {
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900272 input = replaceSuffix(output, input)
Shinichiro Hamaji7b203b22015-04-01 03:44:57 +0900273 }
Shinichiro Hamaji57aff982015-04-02 02:15:38 +0900274 actualInputs = append(actualInputs, input)
Shinichiro Hamaji7b203b22015-04-01 03:44:57 +0900275
Shinichiro Hamajieb4da7f2015-04-11 20:28:54 +0900276 ts, err := ex.build(vars, input, output)
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900277 if err != nil {
278 return outputTs, err
279 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900280 if latest < ts {
281 latest = ts
282 }
283 }
284
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +0900285 for _, input := range rule.orderOnlyInputs {
Fumitoshi Ukaif04610d2015-04-07 00:03:03 +0900286 if exists(input) {
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +0900287 continue
288 }
Shinichiro Hamajieb4da7f2015-04-11 20:28:54 +0900289 ts, err := ex.build(vars, input, output)
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +0900290 if err != nil {
291 return outputTs, err
292 }
293 if latest < ts {
294 latest = ts
295 }
296 }
297
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900298 if outputTs >= latest {
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900299 return outputTs, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900300 }
301
Shinichiro Hamaji63a77d42015-04-12 01:04:07 +0900302 localVars := vars
Fumitoshi Ukai3e5161e2015-04-01 22:42:10 +0900303 // automatic variables.
Shinichiro Hamajia9e72692015-04-12 01:14:08 +0900304 localVars["@"] = SimpleVar{value: []byte(output), origin: "automatic"}
Shinichiro Hamaji57aff982015-04-02 02:15:38 +0900305 if len(actualInputs) > 0 {
Shinichiro Hamajia9e72692015-04-12 01:14:08 +0900306 localVars["<"] = SimpleVar{
Shinichiro Hamaji39728f12015-04-11 20:12:23 +0900307 value: []byte(actualInputs[0]),
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900308 origin: "automatic",
Shinichiro Hamajia9e72692015-04-12 01:14:08 +0900309 }
Shinichiro Hamaji63a77d42015-04-12 01:04:07 +0900310 } else {
Shinichiro Hamajia9e72692015-04-12 01:14:08 +0900311 localVars["<"] = SimpleVar{
Shinichiro Hamaji63a77d42015-04-12 01:04:07 +0900312 value: []byte{},
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900313 origin: "automatic",
Shinichiro Hamajia9e72692015-04-12 01:14:08 +0900314 }
Shinichiro Hamaji57aff982015-04-02 02:15:38 +0900315 }
Shinichiro Hamajia9e72692015-04-12 01:14:08 +0900316 localVars["^"] = SimpleVar{
Shinichiro Hamaji63a77d42015-04-12 01:04:07 +0900317 value: []byte(strings.Join(actualInputs, " ")),
318 origin: "automatic",
Shinichiro Hamajia9e72692015-04-12 01:14:08 +0900319 }
Shinichiro Hamaji63a77d42015-04-12 01:04:07 +0900320 ev := newEvaluator(localVars)
Shinichiro Hamajie708a9d2015-04-03 14:34:35 +0900321 ev.filename = rule.filename
322 ev.lineno = rule.cmdLineno
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900323 var runners []runner
Fumitoshi Ukaif04610d2015-04-07 00:03:03 +0900324 Log("Building: %s cmds:%q", output, rule.cmds)
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900325 r := runner{
326 output: output,
327 echo: true,
328 dryRun: dryRunFlag,
Shinichiro Hamaji973c69f2015-04-11 21:52:38 +0900329 shell: ex.shell,
Fumitoshi Ukai3e5161e2015-04-01 22:42:10 +0900330 }
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900331 for _, cmd := range rule.cmds {
Shinichiro Hamaji973c69f2015-04-11 21:52:38 +0900332 for _, r := range evalCmd(ev, r, cmd) {
333 if len(r.cmd) != 0 {
334 runners = append(runners, r)
335 }
336 }
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900337 }
338 for _, r := range runners {
339 err := r.run()
340 if err != nil {
341 exit := exitStatus(err)
342 fmt.Printf("[%s] Error %d: %v\n", r.output, exit, err)
343 return outputTs, err
344 }
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900345 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900346
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900347 outputTs = getTimestamp(output)
348 if outputTs < 0 {
349 outputTs = time.Now().Unix()
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900350 }
Fumitoshi Ukai4b82f192015-04-07 11:36:42 +0900351 ex.done[output] = outputTs
352 Log("Building: %s done %d", output, outputTs)
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900353 return outputTs, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900354}
355
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900356func (ex *Executor) populateSuffixRule(rule *Rule, output string) bool {
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900357 if len(output) == 0 || output[0] != '.' {
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900358 return false
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900359 }
360 rest := output[1:]
361 dotIndex := strings.IndexByte(rest, '.')
362 // If there is only a single dot or the third dot, this is not a
363 // suffix rule.
364 if dotIndex < 0 || strings.IndexByte(rest[dotIndex+1:], '.') >= 0 {
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900365 return false
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900366 }
367
368 // This is a suffix rule.
369 inputSuffix := rest[:dotIndex]
370 outputSuffix := rest[dotIndex+1:]
371 r := &Rule{}
372 *r = *rule
373 r.inputs = []string{inputSuffix}
374 r.isSuffixRule = true
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900375 ex.suffixRules[outputSuffix] = append([]*Rule{r}, ex.suffixRules[outputSuffix]...)
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900376 return true
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900377}
378
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900379func (ex *Executor) populateExplicitRule(rule *Rule) {
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900380 // It seems rules with no outputs are siliently ignored.
381 if len(rule.outputs) == 0 {
382 return
383 }
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900384 for _, output := range rule.outputs {
Fumitoshi Ukaie1e34442015-04-08 13:10:05 +0900385 output = filepath.Clean(output)
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900386
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900387 isSuffixRule := ex.populateSuffixRule(rule, output)
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900388
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900389 if oldRule, present := ex.rules[output]; present {
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +0900390 if oldRule.vars != nil || rule.vars != nil {
391 oldRule.isDoubleColon = rule.isDoubleColon
392 switch {
393 case rule.vars == nil && oldRule.vars != nil:
394 rule.vars = oldRule.vars
395 case rule.vars != nil && oldRule.vars == nil:
396 case rule.vars != nil && oldRule.vars != nil:
397 // parent would be the same vars?
Shinichiro Hamaji63a77d42015-04-12 01:04:07 +0900398 oldRule.vars.Merge(rule.vars)
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +0900399 rule.vars = oldRule.vars
400 }
401 }
Shinichiro Hamajicc3abc32015-04-02 04:46:49 +0900402 if oldRule.isDoubleColon != rule.isDoubleColon {
403 Error(rule.filename, rule.lineno, "*** target file %q has both : and :: entries.", output)
404 }
405 if len(oldRule.cmds) > 0 && len(rule.cmds) > 0 && !isSuffixRule && !rule.isDoubleColon {
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900406 Warn(rule.filename, rule.cmdLineno, "overriding commands for target %q", output)
407 Warn(oldRule.filename, oldRule.cmdLineno, "ignoring old commands for target %q", output)
408 }
409 r := &Rule{}
410 *r = *rule
Shinichiro Hamajicc3abc32015-04-02 04:46:49 +0900411 if rule.isDoubleColon {
412 r.cmds = append(oldRule.cmds, r.cmds...)
Fumitoshi Ukaic97f49c2015-04-07 00:16:38 +0900413 } else if len(oldRule.cmds) > 0 && len(rule.cmds) == 0 {
414 r.cmds = oldRule.cmds
Shinichiro Hamajicc3abc32015-04-02 04:46:49 +0900415 }
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900416 r.inputs = append(r.inputs, oldRule.inputs...)
Shinichiro Hamaji58370c12015-04-11 21:41:01 +0900417 r.outputPatterns = append(r.outputPatterns, oldRule.outputPatterns...)
Fumitoshi Ukai79fcf972015-04-07 11:10:29 +0900418 r.orderOnlyInputs = append(r.orderOnlyInputs, oldRule.orderOnlyInputs...)
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900419 ex.rules[output] = r
420 } else {
421 ex.rules[output] = rule
Shinichiro Hamaji4a1cfc22015-04-11 13:54:46 +0900422 if ex.firstRule == nil && !strings.HasPrefix(output, ".") {
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900423 ex.firstRule = rule
424 }
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900425 }
426 }
427}
428
429func (ex *Executor) populateImplicitRule(rule *Rule) {
430 for _, outputPattern := range rule.outputPatterns {
431 r := &Rule{}
432 *r = *rule
433 r.outputPatterns = []string{outputPattern}
434 ex.implicitRules = append(ex.implicitRules, r)
435 }
436}
437
438func (ex *Executor) populateRules(er *EvalResult) {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900439 for _, rule := range er.rules {
Fumitoshi Ukaibac3ccf2015-04-08 13:41:22 +0900440 for i, input := range rule.inputs {
441 rule.inputs[i] = filepath.Clean(input)
442 }
443 for i, orderOnlyInput := range rule.orderOnlyInputs {
444 rule.orderOnlyInputs[i] = filepath.Clean(orderOnlyInput)
445 }
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900446 ex.populateExplicitRule(rule)
447
448 if len(rule.outputs) == 0 {
449 ex.populateImplicitRule(rule)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900450 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900451 }
452
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900453 // Reverse the implicit rule for easier lookup.
454 for i, r := range ex.implicitRules {
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900455 if i >= len(ex.implicitRules)/2 {
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900456 break
457 }
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900458 j := len(ex.implicitRules) - i - 1
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900459 ex.implicitRules[i] = ex.implicitRules[j]
460 ex.implicitRules[j] = r
461 }
462}
463
Shinichiro Hamaji63a77d42015-04-12 01:04:07 +0900464func (ex *Executor) exec(er *EvalResult, targets []string, vars Vars) error {
Shinichiro Hamaji89551c92015-04-11 19:33:03 +0900465 // TODO: We should move this to somewhere around evalCmd so that
466 // we can handle SHELL in target specific variables.
467 shellVar := vars.Lookup("SHELL")
468 ex.shell = shellVar.String()
469
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900470 ex.populateRules(er)
471
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900472 if len(targets) == 0 {
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900473 if ex.firstRule == nil {
474 ErrorNoLocation("*** No targets.")
475 }
476 targets = append(targets, ex.firstRule.outputs[0])
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900477 }
478
Shinichiro Hamaji750988e2015-04-12 10:14:32 +0900479 LogStats("%d variables", len(vars))
480 LogStats("%d explicit rules", len(ex.rules))
481 LogStats("%d implicit rules", len(ex.implicitRules))
482 LogStats("%d suffix rules", len(ex.suffixRules))
483
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900484 for _, target := range targets {
Shinichiro Hamajieb4da7f2015-04-11 20:28:54 +0900485 _, err := ex.build(vars, target, "")
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900486 if err != nil {
487 return err
488 }
489 }
490 return nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900491}
492
Shinichiro Hamaji63a77d42015-04-12 01:04:07 +0900493func Exec(er *EvalResult, targets []string, vars Vars) error {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900494 ex := newExecutor()
Shinichiro Hamaji574a4ef2015-04-06 15:20:28 +0900495 return ex.exec(er, targets, vars)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900496}