// Copyright 2018 Google Inc. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package makedeps import ( "bytes" "fmt" "io" "strings" "android/soong/androidmk/parser" ) type Deps struct { Output string Inputs []string } func Parse(filename string, r io.Reader) (*Deps, error) { p := parser.NewParser(filename, r) nodes, errs := p.Parse() if len(errs) == 1 { return nil, errs[0] } else if len(errs) > 1 { return nil, fmt.Errorf("many errors: %v", errs) } pos := func(node parser.Node) string { return p.Unpack(node.Pos()).String() + ": " } ret := &Deps{} for _, node := range nodes { switch x := node.(type) { case *parser.Comment: // Do nothing case *parser.Rule: if x.Recipe != "" { return nil, fmt.Errorf("%sunexpected recipe in rule: %v", pos(node), x) } if !x.Target.Const() { return nil, fmt.Errorf("%sunsupported variable expansion: %v", pos(node), x.Target.Dump()) } outputs := x.Target.Words() if len(outputs) > 0 { ret.Output = outputs[0].Value(nil) } else { // TODO(b/141372861): put this back //return nil, fmt.Errorf("%smissing output: %v", pos(node), x) } if !x.Prerequisites.Const() { return nil, fmt.Errorf("%sunsupported variable expansion: %v", pos(node), x.Prerequisites.Dump()) } for _, input := range x.Prerequisites.Words() { ret.Inputs = append(ret.Inputs, input.Value(nil)) } default: return nil, fmt.Errorf("%sunexpected line: %#v", pos(node), node) } } return ret, nil } func (d *Deps) Print() []byte { // We don't really have to escape every \, but it's simpler, // and ninja will handle it. replacer := strings.NewReplacer(" ", "\\ ", ":", "\\:", "#", "\\#", "$", "$$", "\\", "\\\\") b := &bytes.Buffer{} fmt.Fprintf(b, "%s:", replacer.Replace(d.Output)) for _, input := range d.Inputs { fmt.Fprintf(b, " %s", replacer.Replace(input)) } fmt.Fprintln(b) return b.Bytes() }