blob: fa0528d0e5a79194c0f98d745eec38df9a311881 [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
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090018}
19
20func newExecutor() *Executor {
21 return &Executor{
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +090022 rules: make(map[string]*Rule),
Shinichiro Hamaji20a43762015-04-02 02:42:25 +090023 suffixRules: make(map[string][]*Rule),
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090024 }
25}
26
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +090027// TODO(ukai): use time.Time?
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090028func getTimestamp(filename string) int64 {
29 st, err := os.Stat(filename)
30 if err != nil {
31 return -2
32 }
33 return st.ModTime().Unix()
34}
35
Fumitoshi Ukai6b378832015-04-06 16:54:37 +090036func (ex *Executor) exists(target string) bool {
Fumitoshi Ukaif04610d2015-04-07 00:03:03 +090037 _, present := ex.rules[target]
38 if present {
39 return true
40 }
Fumitoshi Ukai6b378832015-04-06 16:54:37 +090041 rule, present := ex.rules[".PHONY"]
42 if present {
43 for _, input := range rule.inputs {
44 if target == input {
45 return true
46 }
47 }
48 }
49 return exists(target)
50}
51
Shinichiro Hamaji894bb822015-04-01 00:54:46 +090052func (ex *Executor) runCommands(cmds []string, output string) error {
Fumitoshi Ukai772fe1a2015-04-01 23:28:26 +090053Loop:
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090054 for _, cmd := range cmds {
Fumitoshi Ukai772fe1a2015-04-01 23:28:26 +090055 echo := true
56 ignoreErr := false
57 for {
Fumitoshi Ukaieb34a7d2015-04-05 23:56:43 +090058 cmd = strings.TrimLeft(cmd, " \t")
Fumitoshi Ukai772fe1a2015-04-01 23:28:26 +090059 if cmd == "" {
60 continue Loop
61 }
62 switch cmd[0] {
63 case '@':
64 echo = false
65 cmd = cmd[1:]
66 continue
67 case '-':
68 ignoreErr = true
69 cmd = cmd[1:]
70 continue
71 }
72 break
73 }
74 if echo {
75 fmt.Printf("%s\n", cmd)
76 }
Shinichiro Hamaji07e146b2015-04-02 16:17:24 +090077 if dryRunFlag {
78 continue
79 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090080
81 args := []string{"/bin/sh", "-c", cmd}
82 cmd := exec.Cmd{
83 Path: args[0],
84 Args: args,
85 }
86 out, err := cmd.CombinedOutput()
Fumitoshi Ukai772fe1a2015-04-01 23:28:26 +090087 exit := 0
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090088 if err != nil {
Fumitoshi Ukai772fe1a2015-04-01 23:28:26 +090089 exit = 1
90 if err, ok := err.(*exec.ExitError); ok {
91 if w, ok := err.ProcessState.Sys().(syscall.WaitStatus); ok {
92 exit = w.ExitStatus()
93 }
94 } else {
95 return err
96 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090097 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090098 fmt.Printf("%s", out)
Fumitoshi Ukai772fe1a2015-04-01 23:28:26 +090099 if exit != 0 {
100 if ignoreErr {
101 fmt.Printf("[%s] Error %d (ignored)\n", output, exit)
102 continue
103 }
104 return fmt.Errorf("command failed: %q. Error %d", cmd, exit)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900105 }
106 }
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900107 return nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900108}
109
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900110func replaceSuffix(s string, newsuf string) string {
111 // TODO: Factor out the logic around suffix rules and use
112 // it from substitution references.
113 // http://www.gnu.org/software/make/manual/make.html#Substitution-Refs
Shinichiro Hamaji5e2c3c72015-04-03 15:04:54 +0900114 return fmt.Sprintf("%s.%s", stripExt(s), newsuf)
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900115}
116
Shinichiro Hamaji0d0af5b2015-04-02 05:17:23 +0900117func (ex *Executor) canPickImplicitRule(rule *Rule, output string) bool {
118 outputPattern := rule.outputPatterns[0]
119 if !matchPattern(outputPattern, output) {
120 return false
121 }
122 for _, input := range rule.inputs {
123 input = substPattern(outputPattern, input, output)
Fumitoshi Ukai6b378832015-04-06 16:54:37 +0900124 if !ex.exists(input) {
Shinichiro Hamaji0d0af5b2015-04-02 05:17:23 +0900125 return false
126 }
127 }
128 return true
129}
130
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900131func (ex *Executor) pickRule(output string) (*Rule, bool) {
132 rule, present := ex.rules[output]
133 if present {
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900134 if len(rule.cmds) > 0 {
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900135 return rule, true
136 }
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900137 // If none of the explicit rules for a target has commands,
138 // then `make' searches for an applicable implicit rule to
139 // find some commands.
140 }
141
142 for _, irule := range ex.implicitRules {
143 if !ex.canPickImplicitRule(irule, output) {
144 continue
145 }
146 if rule != nil {
147 r := &Rule{}
148 *r = *rule
149 r.outputPatterns = irule.outputPatterns
150 // implicit rule's prerequisites will be used for $<
151 r.inputs = append(irule.inputs, r.inputs...)
152 if irule.vars != nil {
153 r.vars = NewVarTab(rule.vars)
154 for k, v := range irule.vars.m {
155 r.vars.Assign(k, v)
156 }
157 }
158 r.cmds = irule.cmds
159 // TODO(ukai): filename, lineno?
160 r.cmdLineno = irule.cmdLineno
161 return r, true
162 }
163 // TODO(ukai): check len(irule.cmd) ?
164 return irule, true
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900165 }
166
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900167 outputSuffix := filepath.Ext(output)
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900168 if !strings.HasPrefix(outputSuffix, ".") {
169 return rule, rule != nil
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900170 }
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900171 rules, present := ex.suffixRules[outputSuffix[1:]]
172 if !present {
173 return rule, rule != nil
174 }
175 for _, irule := range rules {
176 if len(irule.inputs) != 1 {
177 panic(fmt.Sprintf("unexpected number of input for a suffix rule (%d)", len(irule.inputs)))
178 }
Fumitoshi Ukai6b378832015-04-06 16:54:37 +0900179 if !ex.exists(replaceSuffix(output, irule.inputs[0])) {
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900180 continue
181 }
182 if rule != nil {
183 r := &Rule{}
184 *r = *rule
185 // TODO(ukai): input order is correct?
186 r.inputs = append([]string{replaceSuffix(output, irule.inputs[0])}, r.inputs...)
187 r.vars = NewVarTab(rule.vars)
Fumitoshi Ukai6b378832015-04-06 16:54:37 +0900188 if irule.vars != nil {
189 for k, v := range irule.vars.m {
190 r.vars.Assign(k, v)
191 }
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900192 }
193 r.cmds = irule.cmds
194 // TODO(ukai): filename, lineno?
195 r.cmdLineno = irule.cmdLineno
196 return r, true
197 }
198 // TODO(ukai): check len(irule.cmd) ?
199 return irule, true
200 }
201 return rule, rule != nil
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900202}
203
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900204func (ex *Executor) build(vars *VarTab, output string) (int64, error) {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900205 Log("Building: %s", output)
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900206 outputTs := getTimestamp(output)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900207
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900208 rule, present := ex.pickRule(output)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900209 if !present {
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900210 if outputTs >= 0 {
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900211 return outputTs, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900212 }
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900213 return outputTs, fmt.Errorf("no rule to make target %q", output)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900214 }
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +0900215 if rule.vars != nil {
216 vars = NewVarTab(vars)
217 for k, v := range rule.vars.m {
218 vars.Assign(k, v)
219 }
220 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900221
222 latest := int64(-1)
Shinichiro Hamaji57aff982015-04-02 02:15:38 +0900223 var actualInputs []string
Fumitoshi Ukaid92c4872015-04-06 16:17:31 +0900224 Log("Building: %s inputs:%q", output, rule.inputs)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900225 for _, input := range rule.inputs {
Shinichiro Hamaji7b203b22015-04-01 03:44:57 +0900226 if len(rule.outputPatterns) > 0 {
227 if len(rule.outputPatterns) > 1 {
228 panic("TODO: multiple output pattern is not supported yet")
229 }
230 input = substPattern(rule.outputPatterns[0], input, output)
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900231 } else if rule.isSuffixRule {
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900232 input = replaceSuffix(output, input)
Shinichiro Hamaji7b203b22015-04-01 03:44:57 +0900233 }
Shinichiro Hamaji57aff982015-04-02 02:15:38 +0900234 actualInputs = append(actualInputs, input)
Shinichiro Hamaji7b203b22015-04-01 03:44:57 +0900235
Fumitoshi Ukai3e5161e2015-04-01 22:42:10 +0900236 ts, err := ex.build(vars, input)
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900237 if err != nil {
238 return outputTs, err
239 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900240 if latest < ts {
241 latest = ts
242 }
243 }
244
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +0900245 for _, input := range rule.orderOnlyInputs {
Fumitoshi Ukaif04610d2015-04-07 00:03:03 +0900246 if exists(input) {
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +0900247 continue
248 }
249 ts, err := ex.build(vars, input)
250 if err != nil {
251 return outputTs, err
252 }
253 if latest < ts {
254 latest = ts
255 }
256 }
257
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900258 if outputTs >= latest {
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900259 return outputTs, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900260 }
261
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900262 localVars := NewVarTab(vars)
Fumitoshi Ukai3e5161e2015-04-01 22:42:10 +0900263 // automatic variables.
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900264 localVars.Assign("@", SimpleVar{value: output, origin: "automatic"})
Shinichiro Hamaji57aff982015-04-02 02:15:38 +0900265 if len(actualInputs) > 0 {
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900266 localVars.Assign("<", SimpleVar{
267 value: actualInputs[0],
268 origin: "automatic",
269 })
270 localVars.Assign("^", SimpleVar{
271 value: strings.Join(actualInputs, " "),
272 origin: "automatic",
273 })
Shinichiro Hamaji57aff982015-04-02 02:15:38 +0900274 }
Fumitoshi Ukai3e5161e2015-04-01 22:42:10 +0900275 ev := newEvaluator(localVars)
Shinichiro Hamajie708a9d2015-04-03 14:34:35 +0900276 ev.filename = rule.filename
277 ev.lineno = rule.cmdLineno
Fumitoshi Ukai3e5161e2015-04-01 22:42:10 +0900278 var cmds []string
Fumitoshi Ukaif04610d2015-04-07 00:03:03 +0900279 Log("Building: %s cmds:%q", output, rule.cmds)
Fumitoshi Ukai3e5161e2015-04-01 22:42:10 +0900280 for _, cmd := range rule.cmds {
281 if strings.IndexByte(cmd, '$') < 0 {
282 // fast path.
283 cmds = append(cmds, cmd)
284 continue
285 }
286 ecmd := ev.evalExpr(cmd)
287 Log("build eval:%q => %q", cmd, ecmd)
288 cmds = append(cmds, strings.Split(ecmd, "\n")...)
289 }
290
291 err := ex.runCommands(cmds, output)
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900292 if err != nil {
293 return outputTs, err
294 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900295
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900296 outputTs = getTimestamp(output)
297 if outputTs < 0 {
298 outputTs = time.Now().Unix()
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900299 }
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900300 return outputTs, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900301}
302
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900303func (ex *Executor) populateSuffixRule(rule *Rule, output string) bool {
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900304 if len(output) == 0 || output[0] != '.' {
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900305 return false
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900306 }
307 rest := output[1:]
308 dotIndex := strings.IndexByte(rest, '.')
309 // If there is only a single dot or the third dot, this is not a
310 // suffix rule.
311 if dotIndex < 0 || strings.IndexByte(rest[dotIndex+1:], '.') >= 0 {
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900312 return false
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900313 }
314
315 // This is a suffix rule.
316 inputSuffix := rest[:dotIndex]
317 outputSuffix := rest[dotIndex+1:]
318 r := &Rule{}
319 *r = *rule
320 r.inputs = []string{inputSuffix}
321 r.isSuffixRule = true
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900322 ex.suffixRules[outputSuffix] = append([]*Rule{r}, ex.suffixRules[outputSuffix]...)
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900323 return true
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900324}
325
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900326func (ex *Executor) populateExplicitRule(rule *Rule) {
327 for _, output := range rule.outputs {
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900328 isSuffixRule := ex.populateSuffixRule(rule, output)
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900329
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900330 if oldRule, present := ex.rules[output]; present {
Fumitoshi Ukai953ce6f2015-04-04 00:38:53 +0900331 if oldRule.vars != nil || rule.vars != nil {
332 oldRule.isDoubleColon = rule.isDoubleColon
333 switch {
334 case rule.vars == nil && oldRule.vars != nil:
335 rule.vars = oldRule.vars
336 case rule.vars != nil && oldRule.vars == nil:
337 case rule.vars != nil && oldRule.vars != nil:
338 // parent would be the same vars?
339 for k, v := range rule.vars.m {
340 oldRule.vars.m[k] = v
341 }
342 rule.vars = oldRule.vars
343 }
344 }
Shinichiro Hamajicc3abc32015-04-02 04:46:49 +0900345 if oldRule.isDoubleColon != rule.isDoubleColon {
346 Error(rule.filename, rule.lineno, "*** target file %q has both : and :: entries.", output)
347 }
348 if len(oldRule.cmds) > 0 && len(rule.cmds) > 0 && !isSuffixRule && !rule.isDoubleColon {
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900349 Warn(rule.filename, rule.cmdLineno, "overriding commands for target %q", output)
350 Warn(oldRule.filename, oldRule.cmdLineno, "ignoring old commands for target %q", output)
351 }
352 r := &Rule{}
353 *r = *rule
Shinichiro Hamajicc3abc32015-04-02 04:46:49 +0900354 if rule.isDoubleColon {
355 r.cmds = append(oldRule.cmds, r.cmds...)
Fumitoshi Ukaic97f49c2015-04-07 00:16:38 +0900356 } else if len(oldRule.cmds) > 0 && len(rule.cmds) == 0 {
357 r.cmds = oldRule.cmds
Shinichiro Hamajicc3abc32015-04-02 04:46:49 +0900358 }
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900359 r.inputs = append(r.inputs, oldRule.inputs...)
360 ex.rules[output] = r
361 } else {
362 ex.rules[output] = rule
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900363 if ex.firstRule == nil && !isSuffixRule {
364 ex.firstRule = rule
365 }
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900366 }
367 }
368}
369
370func (ex *Executor) populateImplicitRule(rule *Rule) {
371 for _, outputPattern := range rule.outputPatterns {
372 r := &Rule{}
373 *r = *rule
374 r.outputPatterns = []string{outputPattern}
375 ex.implicitRules = append(ex.implicitRules, r)
376 }
377}
378
379func (ex *Executor) populateRules(er *EvalResult) {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900380 for _, rule := range er.rules {
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900381 ex.populateExplicitRule(rule)
382
383 if len(rule.outputs) == 0 {
384 ex.populateImplicitRule(rule)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900385 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900386 }
387
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900388 // Reverse the implicit rule for easier lookup.
389 for i, r := range ex.implicitRules {
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900390 if i >= len(ex.implicitRules)/2 {
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900391 break
392 }
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900393 j := len(ex.implicitRules) - i - 1
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900394 ex.implicitRules[i] = ex.implicitRules[j]
395 ex.implicitRules[j] = r
396 }
397}
398
Shinichiro Hamaji574a4ef2015-04-06 15:20:28 +0900399func (ex *Executor) exec(er *EvalResult, targets []string, vars *VarTab) error {
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900400 ex.populateRules(er)
401
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900402 if len(targets) == 0 {
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900403 if ex.firstRule == nil {
404 ErrorNoLocation("*** No targets.")
405 }
406 targets = append(targets, ex.firstRule.outputs[0])
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900407 }
408
409 for _, target := range targets {
Shinichiro Hamaji574a4ef2015-04-06 15:20:28 +0900410 _, err := ex.build(vars, target)
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900411 if err != nil {
412 return err
413 }
414 }
415 return nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900416}
417
Shinichiro Hamaji574a4ef2015-04-06 15:20:28 +0900418func Exec(er *EvalResult, targets []string, vars *VarTab) error {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900419 ex := newExecutor()
Shinichiro Hamaji574a4ef2015-04-06 15:20:28 +0900420 return ex.exec(er, targets, vars)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900421}