blob: 356f50445c7c2b225661be3f789f3b16e281870a [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
Shinichiro Hamaji894bb822015-04-01 00:54:46 +090036func (ex *Executor) runCommands(cmds []string, output string) error {
Fumitoshi Ukai772fe1a2015-04-01 23:28:26 +090037Loop:
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090038 for _, cmd := range cmds {
Fumitoshi Ukai772fe1a2015-04-01 23:28:26 +090039 echo := true
40 ignoreErr := false
41 for {
42 if cmd == "" {
43 continue Loop
44 }
45 switch cmd[0] {
46 case '@':
47 echo = false
48 cmd = cmd[1:]
49 continue
50 case '-':
51 ignoreErr = true
52 cmd = cmd[1:]
53 continue
54 }
55 break
56 }
57 if echo {
58 fmt.Printf("%s\n", cmd)
59 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090060
61 args := []string{"/bin/sh", "-c", cmd}
62 cmd := exec.Cmd{
63 Path: args[0],
64 Args: args,
65 }
66 out, err := cmd.CombinedOutput()
Fumitoshi Ukai772fe1a2015-04-01 23:28:26 +090067 exit := 0
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090068 if err != nil {
Fumitoshi Ukai772fe1a2015-04-01 23:28:26 +090069 exit = 1
70 if err, ok := err.(*exec.ExitError); ok {
71 if w, ok := err.ProcessState.Sys().(syscall.WaitStatus); ok {
72 exit = w.ExitStatus()
73 }
74 } else {
75 return err
76 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090077 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090078 fmt.Printf("%s", out)
Fumitoshi Ukai772fe1a2015-04-01 23:28:26 +090079 if exit != 0 {
80 if ignoreErr {
81 fmt.Printf("[%s] Error %d (ignored)\n", output, exit)
82 continue
83 }
84 return fmt.Errorf("command failed: %q. Error %d", cmd, exit)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090085 }
86 }
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +090087 return nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090088}
89
Shinichiro Hamaji20a43762015-04-02 02:42:25 +090090func replaceSuffix(s string, newsuf string) string {
91 // TODO: Factor out the logic around suffix rules and use
92 // it from substitution references.
93 // http://www.gnu.org/software/make/manual/make.html#Substitution-Refs
94 oldsuf := filepath.Ext(s)
95 return fmt.Sprintf("%s.%s", s[:len(s)-len(oldsuf)], newsuf)
96}
97
Shinichiro Hamaji0d0af5b2015-04-02 05:17:23 +090098func (ex *Executor) canPickImplicitRule(rule *Rule, output string) bool {
99 outputPattern := rule.outputPatterns[0]
100 if !matchPattern(outputPattern, output) {
101 return false
102 }
103 for _, input := range rule.inputs {
104 input = substPattern(outputPattern, input, output)
105 if !exists(input) {
106 return false
107 }
108 }
109 return true
110}
111
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900112func (ex *Executor) pickRule(output string) (*Rule, bool) {
113 rule, present := ex.rules[output]
114 if present {
115 return rule, true
116 }
117
118 for _, rule := range ex.implicitRules {
Shinichiro Hamaji0d0af5b2015-04-02 05:17:23 +0900119 if ex.canPickImplicitRule(rule, output) {
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900120 return rule, true
121 }
122 }
123
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900124 outputSuffix := filepath.Ext(output)
125 if len(outputSuffix) > 0 && outputSuffix[0] == '.' {
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900126 rules, present := ex.suffixRules[outputSuffix[1:]]
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900127 if present {
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900128 for _, rule := range rules {
129 if len(rule.inputs) != 1 {
130 panic(fmt.Sprintf("unexpected number of input for a suffix rule (%d)", len(rule.inputs)))
131 }
132 if exists(replaceSuffix(output, rule.inputs[0])) {
133 return rule, true
134 }
135 }
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900136 }
137 }
138
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900139 return nil, false
140}
141
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900142func (ex *Executor) build(vars *VarTab, output string) (int64, error) {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900143 Log("Building: %s", output)
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900144 outputTs := getTimestamp(output)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900145
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900146 rule, present := ex.pickRule(output)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900147 if !present {
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900148 if outputTs >= 0 {
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900149 return outputTs, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900150 }
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900151 return outputTs, fmt.Errorf("no rule to make target %q", output)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900152 }
153
154 latest := int64(-1)
Shinichiro Hamaji57aff982015-04-02 02:15:38 +0900155 var actualInputs []string
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900156 for _, input := range rule.inputs {
Shinichiro Hamaji7b203b22015-04-01 03:44:57 +0900157 if len(rule.outputPatterns) > 0 {
158 if len(rule.outputPatterns) > 1 {
159 panic("TODO: multiple output pattern is not supported yet")
160 }
161 input = substPattern(rule.outputPatterns[0], input, output)
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900162 } else if rule.isSuffixRule {
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900163 input = replaceSuffix(output, input)
Shinichiro Hamaji7b203b22015-04-01 03:44:57 +0900164 }
Shinichiro Hamaji57aff982015-04-02 02:15:38 +0900165 actualInputs = append(actualInputs, input)
Shinichiro Hamaji7b203b22015-04-01 03:44:57 +0900166
Fumitoshi Ukai3e5161e2015-04-01 22:42:10 +0900167 ts, err := ex.build(vars, input)
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900168 if err != nil {
169 return outputTs, err
170 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900171 if latest < ts {
172 latest = ts
173 }
174 }
175
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +0900176 for _, input := range rule.orderOnlyInputs {
177 if exists(input) {
178 continue
179 }
180 ts, err := ex.build(vars, input)
181 if err != nil {
182 return outputTs, err
183 }
184 if latest < ts {
185 latest = ts
186 }
187 }
188
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900189 if outputTs >= latest {
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900190 return outputTs, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900191 }
192
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900193 localVars := NewVarTab(vars)
Fumitoshi Ukai3e5161e2015-04-01 22:42:10 +0900194 // automatic variables.
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900195 localVars.Assign("@", SimpleVar{value: output, origin: "automatic"})
Shinichiro Hamaji57aff982015-04-02 02:15:38 +0900196 if len(actualInputs) > 0 {
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900197 localVars.Assign("<", SimpleVar{
198 value: actualInputs[0],
199 origin: "automatic",
200 })
201 localVars.Assign("^", SimpleVar{
202 value: strings.Join(actualInputs, " "),
203 origin: "automatic",
204 })
Shinichiro Hamaji57aff982015-04-02 02:15:38 +0900205 }
Fumitoshi Ukai3e5161e2015-04-01 22:42:10 +0900206 ev := newEvaluator(localVars)
207 var cmds []string
208 for _, cmd := range rule.cmds {
209 if strings.IndexByte(cmd, '$') < 0 {
210 // fast path.
211 cmds = append(cmds, cmd)
212 continue
213 }
214 ecmd := ev.evalExpr(cmd)
215 Log("build eval:%q => %q", cmd, ecmd)
216 cmds = append(cmds, strings.Split(ecmd, "\n")...)
217 }
218
219 err := ex.runCommands(cmds, output)
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900220 if err != nil {
221 return outputTs, err
222 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900223
Fumitoshi Ukaicf2b0382015-03-30 17:48:54 +0900224 outputTs = getTimestamp(output)
225 if outputTs < 0 {
226 outputTs = time.Now().Unix()
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900227 }
Fumitoshi Ukaif8efa0a2015-03-30 18:10:11 +0900228 return outputTs, nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900229}
230
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900231func (ex *Executor) populateSuffixRule(rule *Rule, output string) bool {
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900232 if len(output) == 0 || output[0] != '.' {
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900233 return false
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900234 }
235 rest := output[1:]
236 dotIndex := strings.IndexByte(rest, '.')
237 // If there is only a single dot or the third dot, this is not a
238 // suffix rule.
239 if dotIndex < 0 || strings.IndexByte(rest[dotIndex+1:], '.') >= 0 {
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900240 return false
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900241 }
242
243 // This is a suffix rule.
244 inputSuffix := rest[:dotIndex]
245 outputSuffix := rest[dotIndex+1:]
246 r := &Rule{}
247 *r = *rule
248 r.inputs = []string{inputSuffix}
249 r.isSuffixRule = true
Shinichiro Hamaji20a43762015-04-02 02:42:25 +0900250 ex.suffixRules[outputSuffix] = append([]*Rule{r}, ex.suffixRules[outputSuffix]...)
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900251 return true
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900252}
253
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900254func (ex *Executor) populateExplicitRule(rule *Rule) {
255 for _, output := range rule.outputs {
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900256 isSuffixRule := ex.populateSuffixRule(rule, output)
Shinichiro Hamajiabc80d22015-04-02 01:56:32 +0900257
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900258 if oldRule, present := ex.rules[output]; present {
Shinichiro Hamajicc3abc32015-04-02 04:46:49 +0900259 if oldRule.isDoubleColon != rule.isDoubleColon {
260 Error(rule.filename, rule.lineno, "*** target file %q has both : and :: entries.", output)
261 }
262 if len(oldRule.cmds) > 0 && len(rule.cmds) > 0 && !isSuffixRule && !rule.isDoubleColon {
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900263 Warn(rule.filename, rule.cmdLineno, "overriding commands for target %q", output)
264 Warn(oldRule.filename, oldRule.cmdLineno, "ignoring old commands for target %q", output)
265 }
266 r := &Rule{}
267 *r = *rule
Shinichiro Hamajicc3abc32015-04-02 04:46:49 +0900268 if rule.isDoubleColon {
269 r.cmds = append(oldRule.cmds, r.cmds...)
270 }
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900271 r.inputs = append(r.inputs, oldRule.inputs...)
272 ex.rules[output] = r
273 } else {
274 ex.rules[output] = rule
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900275 if ex.firstRule == nil && !isSuffixRule {
276 ex.firstRule = rule
277 }
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900278 }
279 }
280}
281
282func (ex *Executor) populateImplicitRule(rule *Rule) {
283 for _, outputPattern := range rule.outputPatterns {
284 r := &Rule{}
285 *r = *rule
286 r.outputPatterns = []string{outputPattern}
287 ex.implicitRules = append(ex.implicitRules, r)
288 }
289}
290
291func (ex *Executor) populateRules(er *EvalResult) {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900292 for _, rule := range er.rules {
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900293 ex.populateExplicitRule(rule)
294
295 if len(rule.outputs) == 0 {
296 ex.populateImplicitRule(rule)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900297 }
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900298 }
299
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900300 // Reverse the implicit rule for easier lookup.
301 for i, r := range ex.implicitRules {
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900302 if i >= len(ex.implicitRules)/2 {
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900303 break
304 }
Fumitoshi Ukai8edcb792015-04-02 11:23:23 +0900305 j := len(ex.implicitRules) - i - 1
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900306 ex.implicitRules[i] = ex.implicitRules[j]
307 ex.implicitRules[j] = r
308 }
309}
310
311func (ex *Executor) exec(er *EvalResult, targets []string) error {
312 ex.populateRules(er)
313
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900314 if len(targets) == 0 {
Shinichiro Hamaji26fe9572015-04-02 02:31:32 +0900315 if ex.firstRule == nil {
316 ErrorNoLocation("*** No targets.")
317 }
318 targets = append(targets, ex.firstRule.outputs[0])
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900319 }
320
321 for _, target := range targets {
Fumitoshi Ukai3e5161e2015-04-01 22:42:10 +0900322 _, err := ex.build(er.vars, target)
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900323 if err != nil {
324 return err
325 }
326 }
327 return nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900328}
329
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900330func Exec(er *EvalResult, targets []string) error {
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900331 ex := newExecutor()
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900332 return ex.exec(er, targets)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900333}