diff options
-rw-r--r-- | dep.go | 74 | ||||
-rw-r--r-- | rule_parser.go | 1 |
2 files changed, 57 insertions, 18 deletions
@@ -3,6 +3,7 @@ package main import ( "fmt" "path/filepath" + "sort" "strings" ) @@ -25,16 +26,17 @@ func (n *DepNode) String() string { } type DepBuilder struct { - rules map[string]*Rule - ruleVars map[string]Vars - implicitRules []*Rule - suffixRules map[string][]*Rule - firstRule *Rule - vars Vars - done map[string]*DepNode - phony map[string]bool + rules map[string]*Rule + ruleVars map[string]Vars + irules map[string][]*Rule // output -> implicitRules + suffixRules map[string][]*Rule + firstRule *Rule + vars Vars + done map[string]*DepNode + phony map[string]bool trace []string + nImplicitRules int nodeCnt int pickExplicitRuleCnt int pickImplicitRuleCnt int @@ -108,7 +110,7 @@ func (db *DepBuilder) pickRule(output string) (*Rule, Vars, bool) { db.pickExplicitRuleWithoutCmdCnt++ } - for _, irule := range db.implicitRules { + for _, irule := range db.irules[output] { if !db.canPickImplicitRule(irule, output) { continue } @@ -356,16 +358,18 @@ func (db *DepBuilder) populateExplicitRule(rule *Rule) { } } -func (db *DepBuilder) populateImplicitRule(rule *Rule) { +func (db *DepBuilder) populateImplicitRule(irules []*Rule, rule *Rule) []*Rule { for _, outputPattern := range rule.outputPatterns { r := &Rule{} *r = *rule r.outputPatterns = []pattern{outputPattern} - db.implicitRules = append(db.implicitRules, r) + irules = append(irules, r) } + return irules } func (db *DepBuilder) populateRules(er *EvalResult) { + var implicitRules []*Rule for _, rule := range er.rules { for i, input := range rule.inputs { rule.inputs[i] = trimLeadingCurdir(input) @@ -376,18 +380,51 @@ func (db *DepBuilder) populateRules(er *EvalResult) { db.populateExplicitRule(rule) if len(rule.outputs) == 0 { - db.populateImplicitRule(rule) + implicitRules = db.populateImplicitRule(implicitRules, rule) } } // Reverse the implicit rule for easier lookup. - for i, r := range db.implicitRules { - if i >= len(db.implicitRules)/2 { + for i, r := range implicitRules { + if i >= len(implicitRules)/2 { break } - j := len(db.implicitRules) - i - 1 - db.implicitRules[i] = db.implicitRules[j] - db.implicitRules[j] = r + j := len(implicitRules) - i - 1 + implicitRules[i] = implicitRules[j] + implicitRules[j] = r + } + db.nImplicitRules = len(implicitRules) + + var outputs []string + for output := range db.rules { + outputs = append(outputs, output) + } + sort.Strings(outputs) + for _, irule := range implicitRules { + pat := irule.outputPatterns[0] + if pat.prefix == "" && pat.suffix == "" { + // TODO(ukai): in android, it is used for turning off + // RCS / SCCS implicit rules of GNU make, so we could + // ignore such implicit rules(?) + for _, output := range outputs { + db.irules[output] = append(db.irules[output], irule) + } + continue + } + if pat.prefix != "" { + i := sort.SearchStrings(outputs, pat.prefix) + for i < len(outputs) && strings.HasPrefix(outputs[i], pat.prefix) { + if strings.HasSuffix(outputs[i], pat.suffix) { + db.irules[outputs[i]] = append(db.irules[outputs[i]], irule) + } + i++ + } + continue + } + if pat.suffix != "" { + // TODO(ukai): handle this. no such rule in android build? + panic(fmt.Sprintf("suffix rule found: %s at %s:%d", pat, irule.filename, irule.lineno)) + } } } @@ -407,6 +444,7 @@ func NewDepBuilder(er *EvalResult, vars Vars) *DepBuilder { db := &DepBuilder{ rules: make(map[string]*Rule), ruleVars: er.ruleVars, + irules: make(map[string][]*Rule), suffixRules: make(map[string][]*Rule), vars: vars, done: make(map[string]*DepNode), @@ -433,7 +471,7 @@ func (db *DepBuilder) Eval(targets []string) ([]*DepNode, error) { LogStats("%d variables", len(db.vars)) LogStats("%d explicit rules", len(db.rules)) - LogStats("%d implicit rules", len(db.implicitRules)) + LogStats("%d implicit rules", db.nImplicitRules) LogStats("%d suffix rules", len(db.suffixRules)) var nodes []*DepNode diff --git a/rule_parser.go b/rule_parser.go index 7a6a8f9..3b485af 100644 --- a/rule_parser.go +++ b/rule_parser.go @@ -55,6 +55,7 @@ type Rule struct { } func isPatternRule(s []byte) (pattern, bool) { + s = trimSpaceBytes(s) i := bytes.IndexByte(s, '%') if i < 0 { return pattern{}, false |