androidbp: simplify translation by evaluating all expressions in Blueprint
Translation is getting complicated because the expressions supported by Blueprint are difficult to support in Make. Modify androidbp to use context aware parsing so it can evaluate all expressions at parse time, so it only needs to deal with constant values. Change-Id: I57047645fb48475baecd0361f78a93ec0a26011e
This commit is contained in:
parent
70a5f07663
commit
b3245e9cf6
|
@ -198,6 +198,7 @@ bootstrap_go_binary {
|
||||||
"androidbp/cmd/androidbp_test.go",
|
"androidbp/cmd/androidbp_test.go",
|
||||||
],
|
],
|
||||||
deps: [
|
deps: [
|
||||||
|
"blueprint",
|
||||||
"blueprint-parser",
|
"blueprint-parser",
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"text/scanner"
|
"text/scanner"
|
||||||
|
|
||||||
|
"github.com/google/blueprint"
|
||||||
bpparser "github.com/google/blueprint/parser"
|
bpparser "github.com/google/blueprint/parser"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -59,10 +60,6 @@ type androidMkWriter struct {
|
||||||
|
|
||||||
blueprint *bpparser.File
|
blueprint *bpparser.File
|
||||||
path string
|
path string
|
||||||
|
|
||||||
printedLocalPath bool
|
|
||||||
|
|
||||||
mapScope map[string][]*bpparser.Property
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *androidMkWriter) WriteString(s string) (int, error) {
|
func (w *androidMkWriter) WriteString(s string) (int, error) {
|
||||||
|
@ -70,38 +67,21 @@ func (w *androidMkWriter) WriteString(s string) (int, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func valueToString(value bpparser.Value) (string, error) {
|
func valueToString(value bpparser.Value) (string, error) {
|
||||||
if value.Variable != "" {
|
switch value.Type {
|
||||||
return fmt.Sprintf("$(%s)", value.Variable), nil
|
case bpparser.Bool:
|
||||||
} else if value.Expression != nil {
|
return fmt.Sprintf("%t", value.BoolValue), nil
|
||||||
if value.Expression.Operator != '+' {
|
case bpparser.String:
|
||||||
return "", fmt.Errorf("unexpected operator '%c'", value.Expression.Operator)
|
return fmt.Sprintf("%s", processWildcards(value.StringValue)), nil
|
||||||
}
|
case bpparser.List:
|
||||||
val1, err := valueToString(value.Expression.Args[0])
|
val, err := listToMkString(value.ListValue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
val2, err := valueToString(value.Expression.Args[1])
|
return fmt.Sprintf("\\\n%s", val), nil
|
||||||
if err != nil {
|
case bpparser.Map:
|
||||||
return "", err
|
return "", fmt.Errorf("Can't convert map to string")
|
||||||
}
|
default:
|
||||||
return fmt.Sprintf("%s%s", val1, val2), nil
|
return "", fmt.Errorf("ERROR: unsupported type %d", value.Type)
|
||||||
} else {
|
|
||||||
switch value.Type {
|
|
||||||
case bpparser.Bool:
|
|
||||||
return fmt.Sprintf("%t", value.BoolValue), nil
|
|
||||||
case bpparser.String:
|
|
||||||
return fmt.Sprintf("%s", processWildcards(value.StringValue)), nil
|
|
||||||
case bpparser.List:
|
|
||||||
val, err := listToMkString(value.ListValue)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("\\\n%s", val), nil
|
|
||||||
case bpparser.Map:
|
|
||||||
return "", fmt.Errorf("Can't convert map to string")
|
|
||||||
default:
|
|
||||||
return "", fmt.Errorf("ERROR: unsupported type %d", value.Type)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,15 +253,6 @@ func modulePropBool(module *bpparser.Module, name string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *androidMkWriter) lookupMap(parent bpparser.Value) (mapValue []*bpparser.Property) {
|
|
||||||
if parent.Variable != "" {
|
|
||||||
mapValue = w.mapScope[parent.Variable]
|
|
||||||
} else {
|
|
||||||
mapValue = parent.MapValue
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *androidMkWriter) writeModule(moduleRule string, props []string,
|
func (w *androidMkWriter) writeModule(moduleRule string, props []string,
|
||||||
disabledBuilds map[string]bool, isHostRule bool) {
|
disabledBuilds map[string]bool, isHostRule bool) {
|
||||||
disabledConditionals := disabledTargetConditionals
|
disabledConditionals := disabledTargetConditionals
|
||||||
|
@ -317,15 +288,13 @@ func (w *androidMkWriter) parsePropsAndWriteModule(module *Module) error {
|
||||||
}
|
}
|
||||||
standardProps = append(standardProps, props...)
|
standardProps = append(standardProps, props...)
|
||||||
} else if suffixMap, ok := suffixProperties[prop.Name.Name]; ok {
|
} else if suffixMap, ok := suffixProperties[prop.Name.Name]; ok {
|
||||||
suffixProps := w.lookupMap(prop.Value)
|
props, err := translateSuffixProperties(prop.Value.MapValue, suffixMap)
|
||||||
props, err := translateSuffixProperties(suffixProps, suffixMap)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
standardProps = append(standardProps, props...)
|
standardProps = append(standardProps, props...)
|
||||||
} else if "target" == prop.Name.Name {
|
} else if "target" == prop.Name.Name {
|
||||||
suffixProps := w.lookupMap(prop.Value)
|
props, err := translateTargetConditionals(prop.Value.MapValue, disabledBuilds, module.isHostRule)
|
||||||
props, err := translateTargetConditionals(suffixProps, disabledBuilds, module.isHostRule)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -415,58 +384,8 @@ func (w *androidMkWriter) handleSubdirs(value bpparser.Value) {
|
||||||
fmt.Fprintf(w, "# include $(wildcard $(addsuffix $(LOCAL_PATH)/%s/, Android.mk))\n", strings.Join(subdirs, " "))
|
fmt.Fprintf(w, "# include $(wildcard $(addsuffix $(LOCAL_PATH)/%s/, Android.mk))\n", strings.Join(subdirs, " "))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *androidMkWriter) handleAssignment(assignment *bpparser.Assignment) error {
|
|
||||||
comment := w.getCommentBlock(assignment.Name.Pos)
|
|
||||||
if translation, translated, err := getCommentTranslation(comment); err != nil {
|
|
||||||
return err
|
|
||||||
} else if translated {
|
|
||||||
w.WriteString(translation)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if "subdirs" == assignment.Name.Name {
|
|
||||||
w.handleSubdirs(assignment.OrigValue)
|
|
||||||
} else if assignment.OrigValue.Type == bpparser.Map {
|
|
||||||
// maps may be assigned in Soong, but can only be translated to .mk
|
|
||||||
// in the context of the module
|
|
||||||
w.mapScope[assignment.Name.Name] = assignment.OrigValue.MapValue
|
|
||||||
} else {
|
|
||||||
assigner := ":="
|
|
||||||
if assignment.Assigner != "=" {
|
|
||||||
assigner = assignment.Assigner
|
|
||||||
}
|
|
||||||
val, err := valueToString(assignment.OrigValue)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Fprintf(w, "%s %s %s\n", assignment.Name.Name, assigner, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *androidMkWriter) handleLocalPath() error {
|
func (w *androidMkWriter) handleLocalPath() error {
|
||||||
if w.printedLocalPath {
|
w.WriteString("LOCAL_PATH := " + w.path + "\n")
|
||||||
return nil
|
|
||||||
}
|
|
||||||
w.printedLocalPath = true
|
|
||||||
|
|
||||||
localPath, err := filepath.Abs(w.path)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
top, err := getTopOfAndroidTree(localPath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
rel, err := filepath.Rel(top, localPath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
w.WriteString("LOCAL_PATH := " + rel + "\n")
|
|
||||||
w.WriteString("LOCAL_MODULE_MAKEFILE := $(lastword $(MAKEFILE_LIST))\n\n")
|
w.WriteString("LOCAL_MODULE_MAKEFILE := $(lastword $(MAKEFILE_LIST))\n\n")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -568,7 +487,7 @@ func (w *androidMkWriter) write(writer io.Writer) (err error) {
|
||||||
case *bpparser.Module:
|
case *bpparser.Module:
|
||||||
err = w.handleModule(block)
|
err = w.handleModule(block)
|
||||||
case *bpparser.Assignment:
|
case *bpparser.Assignment:
|
||||||
err = w.handleAssignment(block)
|
// Nothing
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("Unhandled def %v", block)
|
return fmt.Errorf("Unhandled def %v", block)
|
||||||
}
|
}
|
||||||
|
@ -580,27 +499,33 @@ func (w *androidMkWriter) write(writer io.Writer) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func translate(androidBp, androidMk string) error {
|
func translate(rootFile, androidBp, androidMk string) error {
|
||||||
reader, err := os.Open(androidBp)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
scope := bpparser.NewScope(nil)
|
ctx := blueprint.NewContext()
|
||||||
blueprint, errs := bpparser.Parse(androidBp, reader, scope)
|
|
||||||
|
var blueprintFile *bpparser.File
|
||||||
|
|
||||||
|
_, errs := ctx.WalkBlueprintsFiles(rootFile, func(file *bpparser.File) {
|
||||||
|
if file.Name == androidBp {
|
||||||
|
blueprintFile = file
|
||||||
|
}
|
||||||
|
})
|
||||||
if len(errs) > 0 {
|
if len(errs) > 0 {
|
||||||
return errs[0]
|
return errs[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if blueprintFile == nil {
|
||||||
|
return fmt.Errorf("File %q wasn't parsed from %q", androidBp, rootFile)
|
||||||
|
}
|
||||||
|
|
||||||
writer := &androidMkWriter{
|
writer := &androidMkWriter{
|
||||||
blueprint: blueprint,
|
blueprint: blueprintFile,
|
||||||
path: path.Dir(androidBp),
|
path: path.Dir(androidBp),
|
||||||
mapScope: make(map[string][]*bpparser.Property),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := &bytes.Buffer{}
|
buf := &bytes.Buffer{}
|
||||||
|
|
||||||
err = writer.write(buf)
|
err := writer.write(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
os.Remove(androidMk)
|
os.Remove(androidMk)
|
||||||
return err
|
return err
|
||||||
|
@ -618,16 +543,21 @@ func translate(androidBp, androidMk string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if len(os.Args) < 3 {
|
if len(os.Args) < 4 {
|
||||||
fmt.Fprintln(os.Stderr, "Expected input and output filename arguments")
|
fmt.Fprintln(os.Stderr, "Expected root Android.bp, input and output filename arguments")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
androidBp := os.Args[1]
|
rootFile := os.Args[1]
|
||||||
androidMk := os.Args[2]
|
androidBp, err := filepath.Rel(filepath.Dir(rootFile), os.Args[2])
|
||||||
|
if err != nil {
|
||||||
err := translate(androidBp, androidMk)
|
fmt.Fprintf(os.Stderr, "Android.bp file %q is not relative to %q: %s\n",
|
||||||
|
os.Args[2], rootFile, err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
androidMk := os.Args[3]
|
||||||
|
|
||||||
|
err = translate(rootFile, androidBp, androidMk)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Error translating %s: %s\n", androidBp, err.Error())
|
fmt.Fprintf(os.Stderr, "Error translating %s: %s\n", androidBp, err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
|
|
@ -17,10 +17,6 @@ var valueTestCases = []struct {
|
||||||
blueprint: `test = false`,
|
blueprint: `test = false`,
|
||||||
expected: `false`,
|
expected: `false`,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
blueprint: `test = Variable`,
|
|
||||||
expected: `$(Variable)`,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
blueprint: `test = "string"`,
|
blueprint: `test = "string"`,
|
||||||
expected: `string`,
|
expected: `string`,
|
||||||
|
@ -28,18 +24,9 @@ var valueTestCases = []struct {
|
||||||
{
|
{
|
||||||
blueprint: `test = ["a", "b"]`,
|
blueprint: `test = ["a", "b"]`,
|
||||||
expected: `\
|
expected: `\
|
||||||
a \
|
a \
|
||||||
b`,
|
b
|
||||||
},
|
`,
|
||||||
{
|
|
||||||
blueprint: `test = Var + "b"`,
|
|
||||||
expected: `$(Var)b`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
blueprint: `test = ["a"] + ["b"]`,
|
|
||||||
expected: `\
|
|
||||||
a\
|
|
||||||
b`,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,7 +131,6 @@ func TestModules(t *testing.T) {
|
||||||
writer := &androidMkWriter{
|
writer := &androidMkWriter{
|
||||||
blueprint: blueprint,
|
blueprint: blueprint,
|
||||||
path: "",
|
path: "",
|
||||||
mapScope: make(map[string][]*bpparser.Property),
|
|
||||||
Writer: buf,
|
Writer: buf,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,8 +70,11 @@ build .bootstrap/androidbp/test/androidbp.a: g.bootstrap.gc $
|
||||||
${g.bootstrap.srcDir}/build/soong/androidbp/cmd/soong.go $
|
${g.bootstrap.srcDir}/build/soong/androidbp/cmd/soong.go $
|
||||||
${g.bootstrap.srcDir}/build/soong/androidbp/cmd/androidbp_test.go | $
|
${g.bootstrap.srcDir}/build/soong/androidbp/cmd/androidbp_test.go | $
|
||||||
${g.bootstrap.gcCmd} $
|
${g.bootstrap.gcCmd} $
|
||||||
.bootstrap/blueprint-parser/pkg/github.com/google/blueprint/parser.a
|
.bootstrap/blueprint-parser/pkg/github.com/google/blueprint/parser.a $
|
||||||
incFlags = -I .bootstrap/blueprint-parser/pkg
|
.bootstrap/blueprint-pathtools/pkg/github.com/google/blueprint/pathtools.a $
|
||||||
|
.bootstrap/blueprint-proptools/pkg/github.com/google/blueprint/proptools.a $
|
||||||
|
.bootstrap/blueprint/pkg/github.com/google/blueprint.a
|
||||||
|
incFlags = -I .bootstrap/blueprint-parser/pkg -I .bootstrap/blueprint-pathtools/pkg -I .bootstrap/blueprint-proptools/pkg -I .bootstrap/blueprint/pkg
|
||||||
pkgPath = androidbp
|
pkgPath = androidbp
|
||||||
default .bootstrap/androidbp/test/androidbp.a
|
default .bootstrap/androidbp/test/androidbp.a
|
||||||
|
|
||||||
|
@ -90,7 +93,7 @@ default .bootstrap/androidbp/test/test.a
|
||||||
|
|
||||||
build .bootstrap/androidbp/test/test: g.bootstrap.link $
|
build .bootstrap/androidbp/test/test: g.bootstrap.link $
|
||||||
.bootstrap/androidbp/test/test.a | ${g.bootstrap.linkCmd}
|
.bootstrap/androidbp/test/test.a | ${g.bootstrap.linkCmd}
|
||||||
libDirFlags = -L .bootstrap/androidbp/test -L .bootstrap/blueprint-parser/pkg
|
libDirFlags = -L .bootstrap/androidbp/test -L .bootstrap/blueprint-parser/pkg -L .bootstrap/blueprint-pathtools/pkg -L .bootstrap/blueprint-proptools/pkg -L .bootstrap/blueprint/pkg
|
||||||
default .bootstrap/androidbp/test/test
|
default .bootstrap/androidbp/test/test
|
||||||
|
|
||||||
build .bootstrap/androidbp/test/test.passed: g.bootstrap.test $
|
build .bootstrap/androidbp/test/test.passed: g.bootstrap.test $
|
||||||
|
@ -104,14 +107,17 @@ build .bootstrap/androidbp/obj/androidbp.a: g.bootstrap.gc $
|
||||||
${g.bootstrap.srcDir}/build/soong/androidbp/cmd/soong.go | $
|
${g.bootstrap.srcDir}/build/soong/androidbp/cmd/soong.go | $
|
||||||
${g.bootstrap.gcCmd} $
|
${g.bootstrap.gcCmd} $
|
||||||
.bootstrap/blueprint-parser/pkg/github.com/google/blueprint/parser.a $
|
.bootstrap/blueprint-parser/pkg/github.com/google/blueprint/parser.a $
|
||||||
|| .bootstrap/androidbp/test/test.passed
|
.bootstrap/blueprint-pathtools/pkg/github.com/google/blueprint/pathtools.a $
|
||||||
incFlags = -I .bootstrap/blueprint-parser/pkg
|
.bootstrap/blueprint-proptools/pkg/github.com/google/blueprint/proptools.a $
|
||||||
|
.bootstrap/blueprint/pkg/github.com/google/blueprint.a || $
|
||||||
|
.bootstrap/androidbp/test/test.passed
|
||||||
|
incFlags = -I .bootstrap/blueprint-parser/pkg -I .bootstrap/blueprint-pathtools/pkg -I .bootstrap/blueprint-proptools/pkg -I .bootstrap/blueprint/pkg
|
||||||
pkgPath = androidbp
|
pkgPath = androidbp
|
||||||
default .bootstrap/androidbp/obj/androidbp.a
|
default .bootstrap/androidbp/obj/androidbp.a
|
||||||
|
|
||||||
build .bootstrap/androidbp/obj/a.out: g.bootstrap.link $
|
build .bootstrap/androidbp/obj/a.out: g.bootstrap.link $
|
||||||
.bootstrap/androidbp/obj/androidbp.a | ${g.bootstrap.linkCmd}
|
.bootstrap/androidbp/obj/androidbp.a | ${g.bootstrap.linkCmd}
|
||||||
libDirFlags = -L .bootstrap/blueprint-parser/pkg
|
libDirFlags = -L .bootstrap/blueprint-parser/pkg -L .bootstrap/blueprint-pathtools/pkg -L .bootstrap/blueprint-proptools/pkg -L .bootstrap/blueprint/pkg
|
||||||
default .bootstrap/androidbp/obj/a.out
|
default .bootstrap/androidbp/obj/a.out
|
||||||
|
|
||||||
build .bootstrap/bin/androidbp: g.bootstrap.cp .bootstrap/androidbp/obj/a.out
|
build .bootstrap/bin/androidbp: g.bootstrap.cp .bootstrap/androidbp/obj/a.out
|
||||||
|
|
|
@ -27,10 +27,12 @@ var (
|
||||||
cpPreserveSymlinks = pctx.VariableConfigMethod("cpPreserveSymlinks",
|
cpPreserveSymlinks = pctx.VariableConfigMethod("cpPreserveSymlinks",
|
||||||
Config.CpPreserveSymlinksFlags)
|
Config.CpPreserveSymlinksFlags)
|
||||||
|
|
||||||
|
srcDir = pctx.VariableConfigMethod("srcDir", Config.SrcDir)
|
||||||
|
|
||||||
androidbpCmd = filepath.Join(bootstrap.BinDir, "androidbp")
|
androidbpCmd = filepath.Join(bootstrap.BinDir, "androidbp")
|
||||||
androidbp = pctx.StaticRule("androidbp",
|
androidbp = pctx.StaticRule("androidbp",
|
||||||
blueprint.RuleParams{
|
blueprint.RuleParams{
|
||||||
Command: androidbpCmd + " $in $out",
|
Command: androidbpCmd + " ${srcDir}/Android.bp $in $out",
|
||||||
Description: "androidbp $out",
|
Description: "androidbp $out",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue