1// Copyright 2018 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 15package makedeps 16 17import ( 18 "bytes" 19 "fmt" 20 "io" 21 "strings" 22 23 "android/soong/androidmk/parser" 24) 25 26type Deps struct { 27 Output string 28 Inputs []string 29} 30 31func Parse(filename string, r io.Reader) (*Deps, error) { 32 p := parser.NewParser(filename, r) 33 nodes, errs := p.Parse() 34 35 if len(errs) == 1 { 36 return nil, errs[0] 37 } else if len(errs) > 1 { 38 return nil, fmt.Errorf("many errors: %v", errs) 39 } 40 41 pos := func(node parser.Node) string { 42 return p.Unpack(node.Pos()).String() + ": " 43 } 44 45 ret := &Deps{} 46 47 for _, node := range nodes { 48 switch x := node.(type) { 49 case *parser.Comment: 50 // Do nothing 51 case *parser.Rule: 52 if x.Recipe != "" { 53 return nil, fmt.Errorf("%sunexpected recipe in rule: %v", pos(node), x) 54 } 55 56 if !x.Target.Const() { 57 return nil, fmt.Errorf("%sunsupported variable expansion: %v", pos(node), x.Target.Dump()) 58 } 59 outputs := x.Target.Words() 60 if len(outputs) > 0 { 61 ret.Output = outputs[0].Value(nil) 62 } else { 63 // TODO(b/141372861): put this back 64 //return nil, fmt.Errorf("%smissing output: %v", pos(node), x) 65 } 66 67 if !x.Prerequisites.Const() { 68 return nil, fmt.Errorf("%sunsupported variable expansion: %v", pos(node), x.Prerequisites.Dump()) 69 } 70 for _, input := range x.Prerequisites.Words() { 71 ret.Inputs = append(ret.Inputs, input.Value(nil)) 72 } 73 default: 74 return nil, fmt.Errorf("%sunexpected line: %#v", pos(node), node) 75 } 76 } 77 78 return ret, nil 79} 80 81func (d *Deps) Print() []byte { 82 // We don't really have to escape every \, but it's simpler, 83 // and ninja will handle it. 84 replacer := strings.NewReplacer(" ", "\\ ", 85 ":", "\\:", 86 "#", "\\#", 87 "$", "$$", 88 "\\", "\\\\") 89 90 b := &bytes.Buffer{} 91 fmt.Fprintf(b, "%s:", replacer.Replace(d.Output)) 92 for _, input := range d.Inputs { 93 fmt.Fprintf(b, " %s", replacer.Replace(input)) 94 } 95 fmt.Fprintln(b) 96 return b.Bytes() 97} 98