blob: 0ec02a61426f93509196d559ce1b409ce66b9ed2 [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
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +090019 vars Vars
Fumitoshi Ukai4b82f192015-04-07 11:36:42 +090020
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
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090024}
25
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +090026func newExecutor(vars Vars) *Executor {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090027 return &Executor{
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +090028 rules: make(map[string]*Rule),
Shinichiro Hamaji20a43762015-04-02 02:42:25 +090029 suffixRules: make(map[string][]*Rule),
Fumitoshi Ukai4b82f192015-04-07 11:36:42 +090030 done: make(map[string]int64),
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +090031 vars: vars,
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090032 }
33}
34
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +090035// TODO(ukai): use time.Time?
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090036func getTimestamp(filename string) int64 {
37 st, err := os.Stat(filename)
38 if err != nil {
39 return -2
40 }
41 return st.ModTime().Unix()
42}
43
Fumitoshi Ukai6b378832015-04-06 16:54:37 +090044func (ex *Executor) exists(target string) bool {
Fumitoshi Ukaif04610d2015-04-07 00:03:03 +090045 _, present := ex.rules[target]
46 if present {
47 return true
48 }
Fumitoshi Ukai6b378832015-04-06 16:54:37 +090049 rule, present := ex.rules[".PHONY"]
50 if present {
51 for _, input := range rule.inputs {
52 if target == input {
53 return true
54 }
55 }
56 }
57 return exists(target)
58}
59
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +090060type runner struct {
61 output string
62 cmd string
63 echo bool
64 dryRun bool
65 ignoreError bool
Shinichiro Hamaji89551c92015-04-11 19:33:03 +090066 shell string
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +090067}
68
Shinichiro Hamaji973c69f2015-04-11 21:52:38 +090069func evalCmd(ev *Evaluator, r runner, s string) []runner {
70 r = newRunner(r, s)
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +090071 if strings.IndexByte(r.cmd, '$') < 0 {
72 // fast path
73 return []runner{r}
74 }
75 cmds := ev.evalExpr(r.cmd)
76 var runners []runner
77 for _, cmd := range strings.Split(cmds, "\n") {
Shinichiro Hamaji973c69f2015-04-11 21:52:38 +090078 runners = append(runners, newRunner(r, cmd))
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +090079 }
80 return runners
81}
82
Shinichiro Hamaji973c69f2015-04-11 21:52:38 +090083func newRunner(r runner, s string) runner {
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +090084 for {
Shinichiro Hamajic88618f2015-04-11 19:58:06 +090085 s = trimLeftSpace(s)
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +090086 if s == "" {
87 return runner{}
Fumitoshi Ukai772fe1a2015-04-01 23:28:26 +090088 }
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +090089 switch s[0] {
90 case '@':
91 if !r.dryRun {
92 r.echo = false
93 }
94 s = s[1:]
95 continue
96 case '-':
97 r.ignoreError = true
98 s = s[1:]
Shinichiro Hamaji07e146b2015-04-02 16:17:24 +090099 continue
100 }
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900101 break
102 }
103 r.cmd = s
104 return r
105}
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900106
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900107func (r runner) run() error {
108 if r.echo {
109 fmt.Printf("%s\n", r.cmd)
110 }
111 if r.dryRun {
112 return nil
113 }
Shinichiro Hamaji89551c92015-04-11 19:33:03 +0900114 args := []string{r.shell, "-c", r.cmd}
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900115 cmd := exec.Cmd{
116 Path: args[0],
117 Args: args,
118 }
119 out, err := cmd.CombinedOutput()
120 fmt.Printf("%s", out)
121 exit := exitStatus(err)
122 if r.ignoreError && exit != 0 {
123 fmt.Printf("[%s] Error %d (ignored)\n", r.output, exit)
124 err = nil
125 }
126 return err
127}
128
129func exitStatus(err error) int {
130 if err == nil {
131 return 0
132 }
133 exit := 1
134 if err, ok := err.(*exec.ExitError); ok {
135 if w, ok := err.ProcessState.Sys().(syscall.WaitStatus); ok {
136 return w.ExitStatus()
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900137 }
138 }
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900139 return exit
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900140}
141
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900142func replaceSuffix(s string, newsuf string) string {
143 // TODO: Factor out the logic around suffix rules and use
144 // it from substitution references.
145 // http://www.gnu.org/software/make/manual/make.html#Substitution-Refs
Shinichiro Hamaji5e2c3c72015-04-03 15:04:54 +0900146 return fmt.Sprintf("%s.%s", stripExt(s), newsuf)
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900147}
148
Shinichiro Hamaji0d0af5b2015-04-02 05:17:23 +0900149func (ex *Executor) canPickImplicitRule(rule *Rule, output string) bool {
150 outputPattern := rule.outputPatterns[0]
151 if !matchPattern(outputPattern, output) {
152 return false
153 }
154 for _, input := range rule.inputs {
155 input = substPattern(outputPattern, input, output)
Fumitoshi Ukai6b378832015-04-06 16:54:37 +0900156 if !ex.exists(input) {
Shinichiro Hamaji0d0af5b2015-04-02 05:17:23 +0900157 return false
158 }
159 }
160 return true
161}
162
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900163func (ex *Executor) pickRule(output string) (*Rule, bool) {
164 rule, present := ex.rules[output]
165 if present {
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900166 if len(rule.cmds) > 0 {
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900167 return rule, true
168 }
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900169 // If none of the explicit rules for a target has commands,
170 // then `make' searches for an applicable implicit rule to
171 // find some commands.
172 }
173
174 for _, irule := range ex.implicitRules {
175 if !ex.canPickImplicitRule(irule, output) {
176 continue
177 }
178 if rule != nil {
179 r := &Rule{}
180 *r = *rule
181 r.outputPatterns = irule.outputPatterns
182 // implicit rule's prerequisites will be used for $<
183 r.inputs = append(irule.inputs, r.inputs...)
184 if irule.vars != nil {
Shinichiro Hamaji63a77d42015-04-12 01:04:07 +0900185 r.vars = NewVars(rule.vars)
186 r.vars.Merge(irule.vars)
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900187 }
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...)
Shinichiro Hamaji63a77d42015-04-12 01:04:07 +0900217 r.vars = NewVars(rule.vars)
218 r.vars.Merge(irule.vars)
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900219 r.cmds = irule.cmds
220 // TODO(ukai): filename, lineno?
221 r.cmdLineno = irule.cmdLineno
222 return r, true
223 }
224 // TODO(ukai): check len(irule.cmd) ?
225 return irule, true
226 }
227 return rule, rule != nil
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900228}
229
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900230func (ex *Executor) build(output string, neededBy string) (int64, error) {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900231 Log("Building: %s", output)
Fumitoshi Ukai4b82f192015-04-07 11:36:42 +0900232 outputTs, ok := ex.done[output]
233 if ok {
Shinichiro Hamaji940bb6c2015-04-13 00:35:59 +0900234 if outputTs < 0 {
235 fmt.Printf("Circular %s <- %s dependency dropped.\n", neededBy, output)
236 }
Fumitoshi Ukaibac3ccf2015-04-08 13:41:22 +0900237 Log("Building: %s already done: %d", output, outputTs)
Fumitoshi Ukai4b82f192015-04-07 11:36:42 +0900238 return outputTs, nil
239 }
Shinichiro Hamaji940bb6c2015-04-13 00:35:59 +0900240 ex.done[output] = -1
Fumitoshi Ukai4b82f192015-04-07 11:36:42 +0900241 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 }
Shinichiro Hamajieb4da7f2015-04-11 20:28:54 +0900248 if neededBy == "" {
249 ErrorNoLocation("*** No rule to make target %q.", output)
250 } else {
251 ErrorNoLocation("*** No rule to make target %q, needed by %q.", output, neededBy)
252 }
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900253 return outputTs, fmt.Errorf("no rule to make target %q", output)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900254 }
Shinichiro Hamaji4e9ab1a2015-04-12 01:31:58 +0900255
256 var olds []oldVar
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +0900257 if rule.vars != nil {
Shinichiro Hamaji4e9ab1a2015-04-12 01:31:58 +0900258 for k, v := range rule.vars {
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900259 olds = append(olds, newOldVar(ex.vars, k))
260 ex.vars[k] = v
Shinichiro Hamaji4e9ab1a2015-04-12 01:31:58 +0900261 }
262 defer func() {
263 for _, old := range olds {
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900264 old.restore(ex.vars)
Shinichiro Hamaji4e9ab1a2015-04-12 01:31:58 +0900265 }
266 }()
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +0900267 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900268
269 latest := int64(-1)
Shinichiro Hamaji57aff982015-04-02 02:15:38 +0900270 var actualInputs []string
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900271 Log("Building: %s inputs:%q", output, rule.inputs)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900272 for _, input := range rule.inputs {
Shinichiro Hamaji7b203b22015-04-01 03:44:57 +0900273 if len(rule.outputPatterns) > 0 {
274 if len(rule.outputPatterns) > 1 {
275 panic("TODO: multiple output pattern is not supported yet")
276 }
277 input = substPattern(rule.outputPatterns[0], input, output)
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900278 } else if rule.isSuffixRule {
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900279 input = replaceSuffix(output, input)
Shinichiro Hamaji7b203b22015-04-01 03:44:57 +0900280 }
Shinichiro Hamaji57aff982015-04-02 02:15:38 +0900281 actualInputs = append(actualInputs, input)
Shinichiro Hamaji7b203b22015-04-01 03:44:57 +0900282
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900283 ts, err := ex.build(input, output)
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900284 if err != nil {
285 return outputTs, err
286 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900287 if latest < ts {
288 latest = ts
289 }
290 }
291
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +0900292 for _, input := range rule.orderOnlyInputs {
Fumitoshi Ukaif04610d2015-04-07 00:03:03 +0900293 if exists(input) {
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +0900294 continue
295 }
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900296 ts, err := ex.build(input, output)
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +0900297 if err != nil {
298 return outputTs, err
299 }
300 if latest < ts {
301 latest = ts
302 }
303 }
304
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900305 if outputTs >= latest {
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900306 return outputTs, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900307 }
308
Fumitoshi Ukai3e5161e2015-04-01 22:42:10 +0900309 // automatic variables.
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900310 ex.vars["@"] = SimpleVar{value: []byte(output), origin: "automatic"}
Shinichiro Hamaji57aff982015-04-02 02:15:38 +0900311 if len(actualInputs) > 0 {
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900312 ex.vars["<"] = SimpleVar{
Shinichiro Hamaji39728f12015-04-11 20:12:23 +0900313 value: []byte(actualInputs[0]),
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900314 origin: "automatic",
Shinichiro Hamajia9e72692015-04-12 01:14:08 +0900315 }
Shinichiro Hamaji63a77d42015-04-12 01:04:07 +0900316 } else {
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900317 ex.vars["<"] = SimpleVar{
Shinichiro Hamaji63a77d42015-04-12 01:04:07 +0900318 value: []byte{},
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900319 origin: "automatic",
Shinichiro Hamajia9e72692015-04-12 01:14:08 +0900320 }
Shinichiro Hamaji57aff982015-04-02 02:15:38 +0900321 }
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900322 ex.vars["^"] = SimpleVar{
Shinichiro Hamaji63a77d42015-04-12 01:04:07 +0900323 value: []byte(strings.Join(actualInputs, " ")),
324 origin: "automatic",
Shinichiro Hamajia9e72692015-04-12 01:14:08 +0900325 }
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900326 ev := newEvaluator(ex.vars)
Shinichiro Hamajie708a9d2015-04-03 14:34:35 +0900327 ev.filename = rule.filename
328 ev.lineno = rule.cmdLineno
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900329 var runners []runner
Fumitoshi Ukaif04610d2015-04-07 00:03:03 +0900330 Log("Building: %s cmds:%q", output, rule.cmds)
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900331 r := runner{
332 output: output,
333 echo: true,
334 dryRun: dryRunFlag,
Shinichiro Hamaji973c69f2015-04-11 21:52:38 +0900335 shell: ex.shell,
Fumitoshi Ukai3e5161e2015-04-01 22:42:10 +0900336 }
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900337 for _, cmd := range rule.cmds {
Shinichiro Hamaji973c69f2015-04-11 21:52:38 +0900338 for _, r := range evalCmd(ev, r, cmd) {
339 if len(r.cmd) != 0 {
340 runners = append(runners, r)
341 }
342 }
Fumitoshi Ukai457e7ba2015-04-08 11:24:57 +0900343 }
344 for _, r := range runners {
345 err := r.run()
346 if err != nil {
347 exit := exitStatus(err)
348 fmt.Printf("[%s] Error %d: %v\n", r.output, exit, err)
349 return outputTs, err
350 }
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900351 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900352
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900353 outputTs = getTimestamp(output)
354 if outputTs < 0 {
355 outputTs = time.Now().Unix()
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900356 }
Fumitoshi Ukai4b82f192015-04-07 11:36:42 +0900357 ex.done[output] = outputTs
358 Log("Building: %s done %d", output, outputTs)
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900359 return outputTs, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900360}
361
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900362func (ex *Executor) populateSuffixRule(rule *Rule, output string) bool {
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900363 if len(output) == 0 || output[0] != '.' {
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900364 return false
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900365 }
366 rest := output[1:]
367 dotIndex := strings.IndexByte(rest, '.')
368 // If there is only a single dot or the third dot, this is not a
369 // suffix rule.
370 if dotIndex < 0 || strings.IndexByte(rest[dotIndex+1:], '.') >= 0 {
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900371 return false
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900372 }
373
374 // This is a suffix rule.
375 inputSuffix := rest[:dotIndex]
376 outputSuffix := rest[dotIndex+1:]
377 r := &Rule{}
378 *r = *rule
379 r.inputs = []string{inputSuffix}
380 r.isSuffixRule = true
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900381 ex.suffixRules[outputSuffix] = append([]*Rule{r}, ex.suffixRules[outputSuffix]...)
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900382 return true
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900383}
384
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900385func (ex *Executor) populateExplicitRule(rule *Rule) {
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900386 // It seems rules with no outputs are siliently ignored.
387 if len(rule.outputs) == 0 {
388 return
389 }
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900390 for _, output := range rule.outputs {
Fumitoshi Ukaie1e34442015-04-08 13:10:05 +0900391 output = filepath.Clean(output)
Shinichiro Hamaji0b93c862015-04-07 06:15:15 +0900392
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900393 isSuffixRule := ex.populateSuffixRule(rule, output)
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900394
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900395 if oldRule, present := ex.rules[output]; present {
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +0900396 if oldRule.vars != nil || rule.vars != nil {
397 oldRule.isDoubleColon = rule.isDoubleColon
398 switch {
399 case rule.vars == nil && oldRule.vars != nil:
400 rule.vars = oldRule.vars
401 case rule.vars != nil && oldRule.vars == nil:
402 case rule.vars != nil && oldRule.vars != nil:
403 // parent would be the same vars?
Shinichiro Hamaji63a77d42015-04-12 01:04:07 +0900404 oldRule.vars.Merge(rule.vars)
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +0900405 rule.vars = oldRule.vars
406 }
407 }
Shinichiro Hamajicc3abc32015-04-02 04:46:49 +0900408 if oldRule.isDoubleColon != rule.isDoubleColon {
409 Error(rule.filename, rule.lineno, "*** target file %q has both : and :: entries.", output)
410 }
411 if len(oldRule.cmds) > 0 && len(rule.cmds) > 0 && !isSuffixRule && !rule.isDoubleColon {
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900412 Warn(rule.filename, rule.cmdLineno, "overriding commands for target %q", output)
413 Warn(oldRule.filename, oldRule.cmdLineno, "ignoring old commands for target %q", output)
414 }
415 r := &Rule{}
416 *r = *rule
Shinichiro Hamajicc3abc32015-04-02 04:46:49 +0900417 if rule.isDoubleColon {
418 r.cmds = append(oldRule.cmds, r.cmds...)
Fumitoshi Ukaic97f49c2015-04-07 00:16:38 +0900419 } else if len(oldRule.cmds) > 0 && len(rule.cmds) == 0 {
420 r.cmds = oldRule.cmds
Shinichiro Hamajicc3abc32015-04-02 04:46:49 +0900421 }
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900422 r.inputs = append(r.inputs, oldRule.inputs...)
Shinichiro Hamaji58370c12015-04-11 21:41:01 +0900423 r.outputPatterns = append(r.outputPatterns, oldRule.outputPatterns...)
Fumitoshi Ukai79fcf972015-04-07 11:10:29 +0900424 r.orderOnlyInputs = append(r.orderOnlyInputs, oldRule.orderOnlyInputs...)
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900425 ex.rules[output] = r
426 } else {
427 ex.rules[output] = rule
Shinichiro Hamaji4a1cfc22015-04-11 13:54:46 +0900428 if ex.firstRule == nil && !strings.HasPrefix(output, ".") {
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900429 ex.firstRule = rule
430 }
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900431 }
432 }
433}
434
435func (ex *Executor) populateImplicitRule(rule *Rule) {
436 for _, outputPattern := range rule.outputPatterns {
437 r := &Rule{}
438 *r = *rule
439 r.outputPatterns = []string{outputPattern}
440 ex.implicitRules = append(ex.implicitRules, r)
441 }
442}
443
444func (ex *Executor) populateRules(er *EvalResult) {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900445 for _, rule := range er.rules {
Fumitoshi Ukaibac3ccf2015-04-08 13:41:22 +0900446 for i, input := range rule.inputs {
447 rule.inputs[i] = filepath.Clean(input)
448 }
449 for i, orderOnlyInput := range rule.orderOnlyInputs {
450 rule.orderOnlyInputs[i] = filepath.Clean(orderOnlyInput)
451 }
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900452 ex.populateExplicitRule(rule)
453
454 if len(rule.outputs) == 0 {
455 ex.populateImplicitRule(rule)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900456 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900457 }
458
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900459 // Reverse the implicit rule for easier lookup.
460 for i, r := range ex.implicitRules {
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900461 if i >= len(ex.implicitRules)/2 {
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900462 break
463 }
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900464 j := len(ex.implicitRules) - i - 1
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900465 ex.implicitRules[i] = ex.implicitRules[j]
466 ex.implicitRules[j] = r
467 }
468}
469
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900470func (ex *Executor) exec(er *EvalResult, targets []string) error {
Shinichiro Hamaji89551c92015-04-11 19:33:03 +0900471 // TODO: We should move this to somewhere around evalCmd so that
472 // we can handle SHELL in target specific variables.
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900473 shellVar := ex.vars.Lookup("SHELL")
Shinichiro Hamaji89551c92015-04-11 19:33:03 +0900474 ex.shell = shellVar.String()
475
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900476 ex.populateRules(er)
477
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900478 if len(targets) == 0 {
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900479 if ex.firstRule == nil {
480 ErrorNoLocation("*** No targets.")
481 }
482 targets = append(targets, ex.firstRule.outputs[0])
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900483 }
484
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900485 LogStats("%d variables", len(ex.vars))
Shinichiro Hamaji750988e2015-04-12 10:14:32 +0900486 LogStats("%d explicit rules", len(ex.rules))
487 LogStats("%d implicit rules", len(ex.implicitRules))
488 LogStats("%d suffix rules", len(ex.suffixRules))
489
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900490 for _, target := range targets {
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900491 _, err := ex.build(target, "")
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900492 if err != nil {
493 return err
494 }
495 }
496 return nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900497}
498
Shinichiro Hamaji63a77d42015-04-12 01:04:07 +0900499func Exec(er *EvalResult, targets []string, vars Vars) error {
Shinichiro Hamajide4d3e42015-04-12 23:14:35 +0900500 ex := newExecutor(vars)
501 return ex.exec(er, targets)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900502}