blob: 2c9870d28abf29d217fc0220a35a924580b8afcd [file] [log] [blame]
Shinichiro Hamajib69bf8a2015-06-10 14:52:06 +09001// Copyright 2015 Google Inc. All rights reserved
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090015package kati
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +090016
17import (
18 "fmt"
19 "path/filepath"
Fumitoshi Ukaib79b2902015-07-16 16:40:09 +090020 "sort"
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +090021 "strings"
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +090022
23 "github.com/golang/glog"
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +090024)
25
Fumitoshi Ukai65c72332015-06-26 21:32:50 +090026// DepNode represents a makefile rule for an output.
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +090027type DepNode struct {
28 Output string
29 Cmds []string
30 Deps []*DepNode
Fumitoshi Ukaic916ea22015-06-30 09:52:13 +090031 OrderOnlys []*DepNode
Shinichiro Hamaji744b1392015-05-14 23:29:14 +090032 Parents []*DepNode
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +090033 HasRule bool
Fumitoshi Ukaiab431e22015-04-22 23:27:18 +090034 IsPhony bool
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +090035 ActualInputs []string
36 TargetSpecificVars Vars
37 Filename string
38 Lineno int
39}
40
41func (n *DepNode) String() string {
Fumitoshi Ukaic916ea22015-06-30 09:52:13 +090042 return fmt.Sprintf("Dep{output=%s cmds=%d deps=%d orders=%d hasRule=%t phony=%t filename=%s lineno=%d}",
43 n.Output, len(n.Cmds), len(n.Deps), len(n.OrderOnlys), n.HasRule, n.IsPhony, n.Filename, n.Lineno)
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +090044}
45
Fumitoshi Ukaic9ff91b2015-06-25 15:58:36 +090046type depBuilder struct {
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +090047 rules map[string]*rule
Fumitoshi Ukai72508a72015-05-08 13:41:31 +090048 ruleVars map[string]Vars
49
Fumitoshi Ukai914fed32015-07-02 15:50:16 +090050 implicitRules *ruleTrie
Fumitoshi Ukai72508a72015-05-08 13:41:31 +090051
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +090052 suffixRules map[string][]*rule
53 firstRule *rule
Fumitoshi Ukai72508a72015-05-08 13:41:31 +090054 vars Vars
Fumitoshi Ukaidd058ff2015-07-03 14:29:41 +090055 ev *Evaluator
Fumitoshi Ukai09fcd522015-07-15 14:31:50 +090056 vpaths searchPaths
Fumitoshi Ukai72508a72015-05-08 13:41:31 +090057 done map[string]*DepNode
58 phony map[string]bool
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +090059
60 trace []string
61 nodeCnt int
62 pickExplicitRuleCnt int
63 pickImplicitRuleCnt int
64 pickSuffixRuleCnt int
65 pickExplicitRuleWithoutCmdCnt int
66}
67
Fumitoshi Ukai914fed32015-07-02 15:50:16 +090068type ruleTrieEntry struct {
69 rule *rule
70 suffix string
71}
72
73type ruleTrie struct {
74 rules []ruleTrieEntry
75 children map[byte]*ruleTrie
76}
77
78func newRuleTrie() *ruleTrie {
79 return &ruleTrie{
80 children: make(map[byte]*ruleTrie),
81 }
82}
83
84func (rt *ruleTrie) add(name string, r *rule) {
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +090085 glog.V(1).Infof("rule trie: add %q %v %s", name, r.outputPatterns[0], r)
Fumitoshi Ukai914fed32015-07-02 15:50:16 +090086 if name == "" || name[0] == '%' {
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +090087 glog.V(1).Infof("rule trie: add entry %q %v %s", name, r.outputPatterns[0], r)
Fumitoshi Ukai914fed32015-07-02 15:50:16 +090088 rt.rules = append(rt.rules, ruleTrieEntry{
89 rule: r,
90 suffix: name,
91 })
92 return
93 }
94 c, found := rt.children[name[0]]
95 if !found {
96 c = newRuleTrie()
97 rt.children[name[0]] = c
98 }
99 c.add(name[1:], r)
100}
101
102func (rt *ruleTrie) lookup(name string) []*rule {
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +0900103 glog.V(1).Infof("rule trie: lookup %q", name)
Fumitoshi Ukai914fed32015-07-02 15:50:16 +0900104 if rt == nil {
105 return nil
106 }
107 var rules []*rule
108 for _, entry := range rt.rules {
109 if (entry.suffix == "" && name == "") || strings.HasSuffix(name, entry.suffix[1:]) {
110 rules = append(rules, entry.rule)
111 }
112 }
113 if name == "" {
114 return rules
115 }
116 rules = append(rules, rt.children[name[0]].lookup(name[1:])...)
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +0900117 glog.V(1).Infof("rule trie: lookup %q => %v", name, rules)
Fumitoshi Ukai914fed32015-07-02 15:50:16 +0900118 return rules
119}
120
121func (rt *ruleTrie) size() int {
122 if rt == nil {
123 return 0
124 }
125 size := len(rt.rules)
126 for _, c := range rt.children {
127 size += c.size()
128 }
129 return size
130}
131
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900132func replaceSuffix(s string, newsuf string) string {
133 // TODO: Factor out the logic around suffix rules and use
134 // it from substitution references.
135 // http://www.gnu.org/software/make/manual/make.html#Substitution-Refs
136 return fmt.Sprintf("%s.%s", stripExt(s), newsuf)
137}
138
Fumitoshi Ukaic9ff91b2015-06-25 15:58:36 +0900139func (db *depBuilder) exists(target string) bool {
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900140 _, present := db.rules[target]
141 if present {
142 return true
143 }
Fumitoshi Ukaiab431e22015-04-22 23:27:18 +0900144 if db.phony[target] {
145 return true
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900146 }
Fumitoshi Ukai09fcd522015-07-15 14:31:50 +0900147 _, ok := db.vpaths.exists(target)
Fumitoshi Ukaidd058ff2015-07-03 14:29:41 +0900148 return ok
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900149}
150
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +0900151func (db *depBuilder) canPickImplicitRule(r *rule, output string) bool {
152 outputPattern := r.outputPatterns[0]
Fumitoshi Ukai935de962015-04-28 17:08:20 +0900153 if !outputPattern.match(output) {
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900154 return false
155 }
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +0900156 for _, input := range r.inputs {
Fumitoshi Ukai935de962015-04-28 17:08:20 +0900157 input = outputPattern.subst(input, output)
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900158 if !db.exists(input) {
159 return false
160 }
161 }
162 return true
163}
164
Fumitoshi Ukaic9ff91b2015-06-25 15:58:36 +0900165func (db *depBuilder) mergeImplicitRuleVars(outputs []string, vars Vars) Vars {
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900166 if len(outputs) != 1 {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900167 // TODO(ukai): should return error?
168 panic(fmt.Sprintf("FIXME: Implicit rule should have only one output but %q", outputs))
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900169 }
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +0900170 glog.V(1).Infof("merge? %q", db.ruleVars)
171 glog.V(1).Infof("merge? %q", outputs[0])
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900172 ivars, present := db.ruleVars[outputs[0]]
173 if !present {
174 return vars
175 }
176 if vars == nil {
177 return ivars
178 }
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +0900179 glog.V(1).Info("merge!")
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900180 v := make(Vars)
181 v.Merge(ivars)
182 v.Merge(vars)
183 return v
184}
185
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +0900186func (db *depBuilder) pickRule(output string) (*rule, Vars, bool) {
187 r, present := db.rules[output]
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900188 vars := db.ruleVars[output]
189 if present {
190 db.pickExplicitRuleCnt++
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +0900191 if len(r.cmds) > 0 {
192 return r, vars, true
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900193 }
194 // If none of the explicit rules for a target has commands,
195 // then `make' searches for an applicable implicit rule to
196 // find some commands.
197 db.pickExplicitRuleWithoutCmdCnt++
198 }
199
Fumitoshi Ukai914fed32015-07-02 15:50:16 +0900200 irules := db.implicitRules.lookup(output)
201 for i := len(irules) - 1; i >= 0; i-- {
202 irule := irules[i]
203 if !db.canPickImplicitRule(irule, output) {
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +0900204 glog.Infof("ignore implicit rule %q %s", output, irule)
Fumitoshi Ukai914fed32015-07-02 15:50:16 +0900205 continue
206 }
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +0900207 glog.Infof("pick implicit rule %q => %q %s", output, irule.outputPatterns, irule)
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900208 db.pickImplicitRuleCnt++
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +0900209 if r != nil {
210 ir := &rule{}
211 *ir = *r
212 ir.outputPatterns = irule.outputPatterns
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900213 // implicit rule's prerequisites will be used for $<
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +0900214 ir.inputs = append(irule.inputs, ir.inputs...)
215 ir.cmds = irule.cmds
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900216 // TODO(ukai): filename, lineno?
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +0900217 ir.cmdLineno = irule.cmdLineno
218 return ir, vars, true
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900219 }
220 if vars != nil {
Fumitoshi Ukai935de962015-04-28 17:08:20 +0900221 var outputs []string
222 for _, op := range irule.outputPatterns {
223 outputs = append(outputs, op.String())
224 }
225 vars = db.mergeImplicitRuleVars(outputs, vars)
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900226 }
227 // TODO(ukai): check len(irule.cmd) ?
228 return irule, vars, true
229 }
230
231 outputSuffix := filepath.Ext(output)
232 if !strings.HasPrefix(outputSuffix, ".") {
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +0900233 return r, vars, r != nil
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900234 }
235 rules, present := db.suffixRules[outputSuffix[1:]]
236 if !present {
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +0900237 return r, vars, r != nil
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900238 }
239 for _, irule := range rules {
240 if len(irule.inputs) != 1 {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900241 // TODO(ukai): should return error?
242 panic(fmt.Sprintf("FIXME: unexpected number of input for a suffix rule (%d)", len(irule.inputs)))
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900243 }
244 if !db.exists(replaceSuffix(output, irule.inputs[0])) {
245 continue
246 }
247 db.pickSuffixRuleCnt++
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +0900248 if r != nil {
249 sr := &rule{}
250 *sr = *r
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900251 // TODO(ukai): input order is correct?
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +0900252 sr.inputs = append([]string{replaceSuffix(output, irule.inputs[0])}, r.inputs...)
253 sr.cmds = irule.cmds
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900254 // TODO(ukai): filename, lineno?
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +0900255 sr.cmdLineno = irule.cmdLineno
256 return sr, vars, true
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900257 }
258 if vars != nil {
259 vars = db.mergeImplicitRuleVars(irule.outputs, vars)
260 }
261 // TODO(ukai): check len(irule.cmd) ?
262 return irule, vars, true
263 }
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +0900264 return r, vars, r != nil
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900265}
266
Fumitoshi Ukai4ed0b062015-07-17 22:03:46 +0900267func expandInputs(rule *rule, output string) []string {
268 var inputs []string
269 for _, input := range rule.inputs {
270 if len(rule.outputPatterns) > 0 {
271 if len(rule.outputPatterns) != 1 {
272 panic(fmt.Sprintf("FIXME: multiple output pattern is not supported yet"))
273 }
274 input = intern(rule.outputPatterns[0].subst(input, output))
275 } else if rule.isSuffixRule {
276 input = intern(replaceSuffix(output, input))
277 }
278 inputs = append(inputs, input)
279 }
280 return inputs
281}
282
Fumitoshi Ukaic9ff91b2015-06-25 15:58:36 +0900283func (db *depBuilder) buildPlan(output string, neededBy string, tsvs Vars) (*DepNode, error) {
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +0900284 glog.V(1).Infof("Evaluating command: %s", output)
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900285 db.nodeCnt++
286 if db.nodeCnt%100 == 0 {
287 db.reportStats()
288 }
289
290 if n, present := db.done[output]; present {
291 return n, nil
292 }
Fumitoshi Ukaiab431e22015-04-22 23:27:18 +0900293
294 n := &DepNode{Output: output, IsPhony: db.phony[output]}
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900295 db.done[output] = n
296
Fumitoshi Ukaiab431e22015-04-22 23:27:18 +0900297 // create depnode for phony targets?
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900298 rule, vars, present := db.pickRule(output)
299 if !present {
300 return n, nil
301 }
302
303 var restores []func()
304 if vars != nil {
305 for name, v := range vars {
306 // TODO: Consider not updating db.vars.
Fumitoshi Ukai7bf992d2015-06-25 12:42:19 +0900307 tsv := v.(*targetSpecificVar)
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900308 restores = append(restores, db.vars.save(name))
309 restores = append(restores, tsvs.save(name))
310 switch tsv.op {
311 case ":=", "=":
312 db.vars[name] = tsv
313 tsvs[name] = v
314 case "+=":
315 oldVar, present := db.vars[name]
316 if !present || oldVar.String() == "" {
317 db.vars[name] = tsv
318 } else {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900319 var err error
Fumitoshi Ukaidd058ff2015-07-03 14:29:41 +0900320 v, err = oldVar.AppendVar(db.ev, tsv)
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900321 if err != nil {
322 return nil, err
323 }
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900324 db.vars[name] = v
325 }
326 tsvs[name] = v
327 case "?=":
328 if _, present := db.vars[name]; !present {
329 db.vars[name] = tsv
330 tsvs[name] = v
331 }
332 }
333 }
334 defer func() {
335 for _, restore := range restores {
336 restore()
337 }
338 }()
339 }
340
Fumitoshi Ukai4ed0b062015-07-17 22:03:46 +0900341 inputs := expandInputs(rule, output)
342 glog.Infof("Evaluating command: %s inputs:%q => %q", output, rule.inputs, inputs)
343 for _, input := range inputs {
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900344 db.trace = append(db.trace, input)
Fumitoshi Ukaic916ea22015-06-30 09:52:13 +0900345 ni, err := db.buildPlan(input, output, tsvs)
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900346 db.trace = db.trace[0 : len(db.trace)-1]
347 if err != nil {
348 return nil, err
349 }
Fumitoshi Ukaic916ea22015-06-30 09:52:13 +0900350 if ni != nil {
351 n.Deps = append(n.Deps, ni)
352 ni.Parents = append(ni.Parents, n)
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900353 }
354 }
355
356 for _, input := range rule.orderOnlyInputs {
357 db.trace = append(db.trace, input)
Fumitoshi Ukaic916ea22015-06-30 09:52:13 +0900358 ni, err := db.buildPlan(input, output, tsvs)
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900359 db.trace = db.trace[0 : len(db.trace)-1]
360 if err != nil {
361 return nil, err
362 }
363 if n != nil {
Fumitoshi Ukaic916ea22015-06-30 09:52:13 +0900364 n.OrderOnlys = append(n.OrderOnlys, ni)
365 ni.Parents = append(ni.Parents, n)
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900366 }
367 }
368
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900369 n.HasRule = true
370 n.Cmds = rule.cmds
Fumitoshi Ukai4ed0b062015-07-17 22:03:46 +0900371 n.ActualInputs = inputs
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900372 n.TargetSpecificVars = make(Vars)
373 for k, v := range tsvs {
Fumitoshi Ukai7fd162b2015-07-15 12:53:57 +0900374 if glog.V(1) {
375 glog.Infof("output=%s tsv %s=%s", output, k, v)
376 }
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900377 n.TargetSpecificVars[k] = v
378 }
379 n.Filename = rule.filename
380 if len(rule.cmds) > 0 {
Shinichiro Hamaji0483e642015-04-27 21:45:30 +0900381 if rule.cmdLineno > 0 {
382 n.Lineno = rule.cmdLineno
Shinichiro Hamaji5fa1b1e2015-04-27 22:51:52 +0900383 } else {
384 n.Lineno = rule.lineno
Shinichiro Hamaji0483e642015-04-27 21:45:30 +0900385 }
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900386 }
387 return n, nil
388}
389
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +0900390func (db *depBuilder) populateSuffixRule(r *rule, output string) bool {
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900391 if len(output) == 0 || output[0] != '.' {
392 return false
393 }
394 rest := output[1:]
395 dotIndex := strings.IndexByte(rest, '.')
396 // If there is only a single dot or the third dot, this is not a
397 // suffix rule.
398 if dotIndex < 0 || strings.IndexByte(rest[dotIndex+1:], '.') >= 0 {
399 return false
400 }
401
402 // This is a suffix rule.
403 inputSuffix := rest[:dotIndex]
404 outputSuffix := rest[dotIndex+1:]
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +0900405 sr := &rule{}
406 *sr = *r
407 sr.inputs = []string{inputSuffix}
408 sr.isSuffixRule = true
409 db.suffixRules[outputSuffix] = append([]*rule{sr}, db.suffixRules[outputSuffix]...)
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900410 return true
411}
412
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900413func mergeRules(oldRule, r *rule, output string, isSuffixRule bool) (*rule, error) {
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +0900414 if oldRule.isDoubleColon != r.isDoubleColon {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900415 return nil, r.errorf("*** target file %q has both : and :: entries.", output)
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900416 }
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +0900417 if len(oldRule.cmds) > 0 && len(r.cmds) > 0 && !isSuffixRule && !r.isDoubleColon {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900418 warn(r.cmdpos(), "overriding commands for target %q", output)
419 warn(oldRule.cmdpos(), "ignoring old commands for target %q", output)
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900420 }
421
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +0900422 mr := &rule{}
423 *mr = *r
424 if r.isDoubleColon {
425 mr.cmds = append(oldRule.cmds, mr.cmds...)
426 } else if len(oldRule.cmds) > 0 && len(r.cmds) == 0 {
427 mr.cmds = oldRule.cmds
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900428 }
429 // If the latter rule has a command (regardless of the
430 // commands in oldRule), inputs in the latter rule has a
431 // priority.
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +0900432 if len(r.cmds) > 0 {
433 mr.inputs = append(mr.inputs, oldRule.inputs...)
434 mr.orderOnlyInputs = append(mr.orderOnlyInputs, oldRule.orderOnlyInputs...)
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900435 } else {
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +0900436 mr.inputs = append(oldRule.inputs, mr.inputs...)
437 mr.orderOnlyInputs = append(oldRule.orderOnlyInputs, mr.orderOnlyInputs...)
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900438 }
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +0900439 mr.outputPatterns = append(mr.outputPatterns, oldRule.outputPatterns...)
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900440 return mr, nil
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900441}
442
Fumitoshi Ukai4ed0b062015-07-17 22:03:46 +0900443// expandPattern expands static pattern (target: target-pattern: prereq-pattern).
444
Fumitoshi Ukaib8b80502015-07-21 14:28:26 +0900445func expandPattern(r *rule) []*rule {
Fumitoshi Ukai4ed0b062015-07-17 22:03:46 +0900446 if len(r.outputs) == 0 {
Fumitoshi Ukaib8b80502015-07-21 14:28:26 +0900447 return []*rule{r}
Fumitoshi Ukai4ed0b062015-07-17 22:03:46 +0900448 }
449 if len(r.outputPatterns) != 1 {
Fumitoshi Ukaib8b80502015-07-21 14:28:26 +0900450 return []*rule{r}
Fumitoshi Ukai4ed0b062015-07-17 22:03:46 +0900451 }
Fumitoshi Ukaib8b80502015-07-21 14:28:26 +0900452 var rules []*rule
Fumitoshi Ukai4ed0b062015-07-17 22:03:46 +0900453 pat := r.outputPatterns[0]
Fumitoshi Ukai4ed0b062015-07-17 22:03:46 +0900454 for _, output := range r.outputs {
Fumitoshi Ukaib8b80502015-07-21 14:28:26 +0900455 nr := new(rule)
456 *nr = *r
457 nr.outputs = []string{output}
458 nr.outputPatterns = nil
459 nr.inputs = nil
Fumitoshi Ukai4ed0b062015-07-17 22:03:46 +0900460 for _, input := range r.inputs {
Fumitoshi Ukaib8b80502015-07-21 14:28:26 +0900461 nr.inputs = append(nr.inputs, intern(pat.subst(input, output)))
Fumitoshi Ukai4ed0b062015-07-17 22:03:46 +0900462 }
Fumitoshi Ukaib8b80502015-07-21 14:28:26 +0900463 rules = append(rules, nr)
Fumitoshi Ukai4ed0b062015-07-17 22:03:46 +0900464 }
Fumitoshi Ukaib8b80502015-07-21 14:28:26 +0900465 glog.V(1).Infof("expand static pattern: outputs=%q inputs=%q -> %q", r.outputs, r.inputs, rules)
466 return rules
Fumitoshi Ukai4ed0b062015-07-17 22:03:46 +0900467}
468
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900469func (db *depBuilder) populateExplicitRule(r *rule) error {
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900470 // It seems rules with no outputs are siliently ignored.
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +0900471 if len(r.outputs) == 0 {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900472 return nil
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900473 }
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +0900474 for _, output := range r.outputs {
Shinichiro Hamajidad80532015-04-21 17:55:50 +0900475 output = trimLeadingCurdir(output)
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900476
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +0900477 isSuffixRule := db.populateSuffixRule(r, output)
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900478
479 if oldRule, present := db.rules[output]; present {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900480 mr, err := mergeRules(oldRule, r, output, isSuffixRule)
481 if err != nil {
482 return err
483 }
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +0900484 db.rules[output] = mr
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900485 } else {
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +0900486 db.rules[output] = r
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900487 if db.firstRule == nil && !strings.HasPrefix(output, ".") {
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +0900488 db.firstRule = r
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900489 }
490 }
491 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900492 return nil
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900493}
494
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +0900495func (db *depBuilder) populateImplicitRule(r *rule) {
496 for _, outputPattern := range r.outputPatterns {
497 ir := &rule{}
498 *ir = *r
499 ir.outputPatterns = []pattern{outputPattern}
Fumitoshi Ukai914fed32015-07-02 15:50:16 +0900500 db.implicitRules.add(outputPattern.String(), ir)
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900501 }
502}
503
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900504func (db *depBuilder) populateRules(er *evalResult) error {
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +0900505 for _, r := range er.rules {
506 for i, input := range r.inputs {
507 r.inputs[i] = trimLeadingCurdir(input)
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900508 }
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +0900509 for i, orderOnlyInput := range r.orderOnlyInputs {
510 r.orderOnlyInputs[i] = trimLeadingCurdir(orderOnlyInput)
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900511 }
Fumitoshi Ukaib8b80502015-07-21 14:28:26 +0900512 for _, r := range expandPattern(r) {
513 err := db.populateExplicitRule(r)
514 if err != nil {
515 return err
516 }
517 if len(r.outputs) == 0 {
518 db.populateImplicitRule(r)
519 }
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900520 }
521 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900522 return nil
Fumitoshi Ukai72508a72015-05-08 13:41:31 +0900523}
524
Fumitoshi Ukaic9ff91b2015-06-25 15:58:36 +0900525func (db *depBuilder) reportStats() {
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +0900526 if !PeriodicStatsFlag {
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900527 return
528 }
529
Fumitoshi Ukai49599e52015-06-26 10:10:24 +0900530 logStats("node=%d explicit=%d implicit=%d suffix=%d explicitWOCmd=%d",
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900531 db.nodeCnt, db.pickExplicitRuleCnt, db.pickImplicitRuleCnt, db.pickSuffixRuleCnt, db.pickExplicitRuleWithoutCmdCnt)
532 if len(db.trace) > 1 {
Fumitoshi Ukai49599e52015-06-26 10:10:24 +0900533 logStats("trace=%q", db.trace)
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900534 }
535}
536
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900537func newDepBuilder(er *evalResult, vars Vars) (*depBuilder, error) {
Fumitoshi Ukaic9ff91b2015-06-25 15:58:36 +0900538 db := &depBuilder{
Fumitoshi Ukai914fed32015-07-02 15:50:16 +0900539 rules: make(map[string]*rule),
540 ruleVars: er.ruleVars,
541 implicitRules: newRuleTrie(),
542 suffixRules: make(map[string][]*rule),
543 vars: vars,
Fumitoshi Ukaidd058ff2015-07-03 14:29:41 +0900544 ev: NewEvaluator(vars),
Fumitoshi Ukai09fcd522015-07-15 14:31:50 +0900545 vpaths: er.vpaths,
Fumitoshi Ukai914fed32015-07-02 15:50:16 +0900546 done: make(map[string]*DepNode),
547 phony: make(map[string]bool),
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900548 }
549
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900550 err := db.populateRules(er)
551 if err != nil {
552 return nil, err
553 }
Fumitoshi Ukaiab431e22015-04-22 23:27:18 +0900554 rule, present := db.rules[".PHONY"]
555 if present {
556 for _, input := range rule.inputs {
557 db.phony[input] = true
558 }
559 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900560 return db, nil
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900561}
562
Fumitoshi Ukaic9ff91b2015-06-25 15:58:36 +0900563func (db *depBuilder) Eval(targets []string) ([]*DepNode, error) {
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900564 if len(targets) == 0 {
565 if db.firstRule == nil {
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900566 return nil, fmt.Errorf("*** No targets.")
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900567 }
568 targets = append(targets, db.firstRule.outputs[0])
Fumitoshi Ukaib79b2902015-07-16 16:40:09 +0900569 var phonys []string
570 for t := range db.phony {
571 phonys = append(phonys, t)
572 }
573 sort.Strings(phonys)
574 targets = append(targets, phonys...)
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900575 }
576
Fumitoshi Ukaid81f9b92015-07-21 17:07:08 +0900577 if StatsFlag {
578 logStats("%d variables", len(db.vars))
579 logStats("%d explicit rules", len(db.rules))
580 logStats("%d implicit rules", db.implicitRules.size())
581 logStats("%d suffix rules", len(db.suffixRules))
Fumitoshi Ukai0547db62015-07-29 16:20:59 +0900582 logStats("%d dirs %d files", fsCache.dirs(), fsCache.files())
Fumitoshi Ukaid81f9b92015-07-21 17:07:08 +0900583 }
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900584
585 var nodes []*DepNode
586 for _, target := range targets {
587 db.trace = []string{target}
588 n, err := db.buildPlan(target, "", make(Vars))
589 if err != nil {
590 return nil, err
591 }
592 nodes = append(nodes, n)
593 }
594 db.reportStats()
595 return nodes, nil
596}