From da8706fed819d600e49de497e6d2172d73f9f8d5 Mon Sep 17 00:00:00 2001 From: Andres Morales Date: Wed, 29 Apr 2015 12:46:49 -0700 Subject: [PATCH] Initial androidbp translator. Translates Android.bp files back to Android.mk Change-Id: Ib4bd1e0abc58ab514a7dd4a01008af645d6a3d13 --- Blueprints | 11 +++ androidbp/cmd/androidbp.go | 195 +++++++++++++++++++++++++++++++++++++ androidbp/cmd/soong.go | 80 +++++++++++++++ build.ninja.in | 33 ++++++- 4 files changed, 315 insertions(+), 4 deletions(-) create mode 100644 androidbp/cmd/androidbp.go create mode 100644 androidbp/cmd/soong.go diff --git a/Blueprints b/Blueprints index 958c79e42..0a66b431c 100644 --- a/Blueprints +++ b/Blueprints @@ -182,6 +182,17 @@ bootstrap_go_package { ], } +bootstrap_go_binary { + name: "androidbp", + srcs: [ + "androidbp/cmd/androidbp.go", + "androidbp/cmd/soong.go", + ], + deps: [ + "blueprint-parser", + ], +} + // // C static libraries extracted from the gcc toolchain // diff --git a/androidbp/cmd/androidbp.go b/androidbp/cmd/androidbp.go new file mode 100644 index 000000000..dbca35a8f --- /dev/null +++ b/androidbp/cmd/androidbp.go @@ -0,0 +1,195 @@ +package main + +import ( + "bufio" + "fmt" + "os" + "path" + "strings" + + bpparser "github.com/google/blueprint/parser" +) + +type androidMkWriter struct { + *bufio.Writer + + file *bpparser.File + path string +} + +func (w *androidMkWriter) valueToString(value bpparser.Value) string { + if value.Variable != "" { + return fmt.Sprintf("$(%s)", value.Variable) + } else { + switch value.Type { + case bpparser.Bool: + return fmt.Sprintf(`"%t"`, value.BoolValue) + case bpparser.String: + return fmt.Sprintf(`"%s"`, value.StringValue) + case bpparser.List: + return fmt.Sprintf("\\\n%s\n", w.listToMkString(value.ListValue)) + case bpparser.Map: + w.errorf("maps not supported in assignment") + return "ERROR: unsupported type map in assignment" + } + } + + return "" +} + +func (w *androidMkWriter) listToMkString(list []bpparser.Value) string { + lines := make([]string, 0, len(list)) + for _, tok := range list { + lines = append(lines, fmt.Sprintf("\t\"%s\"", tok.StringValue)) + } + + return strings.Join(lines, " \\\n") +} + +func (w *androidMkWriter) errorf(format string, values ...interface{}) { + s := fmt.Sprintf(format, values) + w.WriteString("# ANDROIDBP ERROR:\n") + for _, line := range strings.Split(s, "\n") { + fmt.Fprintf(w, "# %s\n", line) + } +} + +func (w *androidMkWriter) handleComment(comment *bpparser.Comment) { + for _, c := range comment.Comment { + mkComment := strings.Replace(c, "//", "#", 1) + // TODO: handle /* comments? + fmt.Fprintf(w, "%s\n", mkComment) + } +} + +func (w *androidMkWriter) handleModule(module *bpparser.Module) { + if moduleName, ok := moduleTypes[module.Type.Name]; ok { + w.WriteString("include $(CLEAR_VARS)\n") + standardProps := make([]string, 0, len(module.Properties)) + //condProps := make([]string, len(module.Properties)) + for _, prop := range module.Properties { + if mkProp, ok := standardProperties[prop.Name.Name]; ok { + standardProps = append(standardProps, fmt.Sprintf("%s := %s", mkProp.string, + w.valueToString(prop.Value))) + } + } + + mkModule := strings.Join(standardProps, "\n") + w.WriteString(mkModule) + + fmt.Fprintf(w, "include $(%s)\n\n", moduleName) + } else { + w.errorf("Unsupported module %s", module.Type.Name) + } +} + +func (w *androidMkWriter) handleAssignment(assignment *bpparser.Assignment) { + assigner := ":=" + if assignment.Assigner != "=" { + assigner = assignment.Assigner + } + fmt.Fprintf(w, "%s %s %s\n", assignment.Name.Name, assigner, + w.valueToString(assignment.OrigValue)) +} + +func (w *androidMkWriter) iter() <-chan interface{} { + ch := make(chan interface{}, len(w.file.Comments)+len(w.file.Defs)) + go func() { + commIdx := 0 + defsIdx := 0 + for defsIdx < len(w.file.Defs) || commIdx < len(w.file.Comments) { + if defsIdx == len(w.file.Defs) { + ch <- w.file.Comments[commIdx] + commIdx++ + } else if commIdx == len(w.file.Comments) { + ch <- w.file.Defs[defsIdx] + defsIdx++ + } else { + commentsPos := 0 + defsPos := 0 + + def := w.file.Defs[defsIdx] + switch def := def.(type) { + case *bpparser.Module: + defsPos = def.LbracePos.Line + case *bpparser.Assignment: + defsPos = def.Pos.Line + } + + comment := w.file.Comments[commIdx] + commentsPos = comment.Pos.Line + + if commentsPos < defsPos { + commIdx++ + ch <- comment + } else { + defsIdx++ + ch <- def + } + } + } + close(ch) + }() + return ch +} + +func (w *androidMkWriter) write() { + outFilePath := fmt.Sprintf("%s/Android.mk.out", w.path) + fmt.Printf("Writing %s\n", outFilePath) + + f, err := os.Create(outFilePath) + if err != nil { + panic(err) + } + + defer func() { + if err := f.Close(); err != nil { + panic(err) + } + }() + + w.Writer = bufio.NewWriter(f) + + for block := range w.iter() { + switch block := block.(type) { + case *bpparser.Module: + w.handleModule(block) + case *bpparser.Assignment: + w.handleAssignment(block) + case bpparser.Comment: + w.handleComment(&block) + } + } + + if err = w.Flush(); err != nil { + panic(err) + } +} + +func main() { + if len(os.Args) < 2 { + fmt.Println("No filename supplied") + return + } + + reader, err := os.Open(os.Args[1]) + if err != nil { + fmt.Println(err.Error()) + return + } + + scope := bpparser.NewScope(nil) + file, errs := bpparser.Parse(os.Args[1], reader, scope) + if len(errs) > 0 { + fmt.Println("%d errors parsing %s", len(errs), os.Args[1]) + fmt.Println(errs) + return + } + + writer := &androidMkWriter{ + file: file, + path: path.Dir(os.Args[1]), + } + + writer.write() +} diff --git a/androidbp/cmd/soong.go b/androidbp/cmd/soong.go new file mode 100644 index 000000000..488390fec --- /dev/null +++ b/androidbp/cmd/soong.go @@ -0,0 +1,80 @@ +package main + +import bpparser "github.com/google/blueprint/parser" + +var standardProperties = map[string]struct { + string + bpparser.ValueType +}{ + // ==== STRING PROPERTIES ==== + "name": {"LOCAL_MODULE", bpparser.String}, + "stem": {"LOCAL_MODULE_STEM", bpparser.String}, + "class": {"LOCAL_MODULE_CLASS", bpparser.String}, + "stl": {"LOCAL_CXX_STL", bpparser.String}, + "strip": {"LOCAL_STRIP_MODULE", bpparser.String}, + "compile_multilib": {"LOCAL_MULTILIB", bpparser.String}, + "instruction_set": {"LOCAL_ARM_MODE_HACK", bpparser.String}, + "sdk_version": {"LOCAL_SDK_VERSION", bpparser.String}, + //"stl": "LOCAL_NDK_STL_VARIANT", TODO + "manifest": {"LOCAL_JAR_MANIFEST", bpparser.String}, + "jarjar_rules": {"LOCAL_JARJAR_RULES", bpparser.String}, + "certificate": {"LOCAL_CERTIFICATE", bpparser.String}, + //"name": "LOCAL_PACKAGE_NAME", TODO + + // ==== LIST PROPERTIES ==== + "srcs": {"LOCAL_SRC_FILES", bpparser.List}, + "shared_libs": {"LOCAL_SHARED_LIBRARIES", bpparser.List}, + "static_libs": {"LOCAL_STATIC_LIBRARIES", bpparser.List}, + "whole_static_libs": {"LOCAL_WHOLE_STATIC_LIBRARIES", bpparser.List}, + "system_shared_libs": {"LOCAL_SYSTEM_SHARED_LIBRARIES", bpparser.List}, + "include_dirs": {"LOCAL_C_INCLUDES", bpparser.List}, + "export_include_dirs": {"LOCAL_EXPORT_C_INCLUDE_DIRS", bpparser.List}, + "asflags": {"LOCAL_ASFLAGS", bpparser.List}, + "clang_asflags": {"LOCAL_CLANG_ASFLAGS", bpparser.List}, + "cflags": {"LOCAL_CFLAGS", bpparser.List}, + "conlyflags": {"LOCAL_CONLYFLAGS", bpparser.List}, + "cppflags": {"LOCAL_CPPFLAGS", bpparser.List}, + "ldflags": {"LOCAL_LDFLAGS", bpparser.List}, + "required": {"LOCAL_REQUIRED_MODULES", bpparser.List}, + "tags": {"LOCAL_MODULE_TAGS", bpparser.List}, + "host_ldlibs": {"LOCAL_LDLIBS", bpparser.List}, + "clang_cflags": {"LOCAL_CLANG_CFLAGS", bpparser.List}, + "yaccflags": {"LOCAL_YACCFLAGS", bpparser.List}, + "java_resource_dirs": {"LOCAL_JAVA_RESOURCE_DIRS", bpparser.List}, + "javacflags": {"LOCAL_JAVACFLAGS", bpparser.List}, + "dxflags": {"LOCAL_DX_FLAGS", bpparser.List}, + "java_libs": {"LOCAL_JAVA_LIBRARIES", bpparser.List}, + "java_static_libs": {"LOCAL_STATIC_JAVA_LIBRARIES", bpparser.List}, + "aidl_includes": {"LOCAL_AIDL_INCLUDES", bpparser.List}, + "aaptflags": {"LOCAL_AAPT_FLAGS", bpparser.List}, + "package_splits": {"LOCAL_PACKAGE_SPLITS", bpparser.List}, + + // ==== BOOL PROPERTIES ==== + "host": {"LOCAL_IS_HOST_MODULE", bpparser.Bool}, + "clang": {"LOCAL_CLANG", bpparser.Bool}, + "static": {"LOCAL_FORCE_STATIC_EXECUTABLE", bpparser.Bool}, + "asan": {"LOCAL_ADDRESS_SANITIZER", bpparser.Bool}, + "native_coverage": {"LOCAL_NATIVE_COVERAGE", bpparser.Bool}, + "nocrt": {"LOCAL_NO_CRT", bpparser.Bool}, + "allow_undefined_symbols": {"LOCAL_ALLOW_UNDEFINED_SYMBOLS", bpparser.Bool}, + "rtti": {"LOCAL_RTTI_FLAG", bpparser.Bool}, + "no_standard_libraries": {"LOCAL_NO_STANDARD_LIBRARIES", bpparser.Bool}, + "export_package_resources": {"LOCAL_EXPORT_PACKAGE_RESOURCES", bpparser.Bool}, +} + +var moduleTypes = map[string]string{ + "cc_library_shared": "BUILD_SHARED_LIBRARY", + "cc_library_static": "BUILD_STATIC_LIBRARY", + "cc_library_host_shared": "BUILD_HOST_SHARED_LIBRARY", + "cc_library_host_static": "BUILD_HOST_STATIC_LIBRARY", + "cc_binary": "BUILD_EXECUTABLE", + "cc_binary_host": "BUILD_HOST_EXECUTABLE", + "cc_test": "BUILD_NATIVE_TEST", + "cc_test_host": "BUILD_HOST_NATIVE_TEST", + "java_library": "BUILD_JAVA_LIBRARY", + "java_library_static": "BUILD_STATIC_JAVA_LIBRARY", + "java_library_host": "BUILD_HOST_JAVA_LIBRARY", + "java_library_host_dalvik": "BUILD_HOST_DALVIK_JAVA_LIBRARY", + "android_app": "BUILD_PACKAGE", + "prebuilt": "BUILD_PREBUILT", +} diff --git a/build.ninja.in b/build.ninja.in index f579c576b..f9aef06c9 100644 --- a/build.ninja.in +++ b/build.ninja.in @@ -48,6 +48,30 @@ rule g.bootstrap.link command = GOROOT='${g.bootstrap.goRoot}' ${g.bootstrap.linkCmd} -o ${out} ${libDirFlags} ${in} description = ${g.bootstrap.goChar}l ${out} +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# Module: androidbp +# Variant: +# Type: bootstrap_go_binary +# Factory: github.com/google/blueprint/bootstrap.newGoBinaryModule +# Defined: build/soong/Blueprints:183:1 + +build .bootstrap/androidbp/obj/androidbp.a: g.bootstrap.gc $ + ${g.bootstrap.srcDir}/build/soong/androidbp/cmd/androidbp.go $ + ${g.bootstrap.srcDir}/build/soong/androidbp/cmd/soong.go | $ + ${g.bootstrap.gcCmd} $ + .bootstrap/blueprint-parser/pkg/github.com/google/blueprint/parser.a + incFlags = -I .bootstrap/blueprint-parser/pkg + pkgPath = androidbp +default .bootstrap/androidbp/obj/androidbp.a + +build .bootstrap/androidbp/obj/a.out: g.bootstrap.link $ + .bootstrap/androidbp/obj/androidbp.a | ${g.bootstrap.linkCmd} + libDirFlags = -L .bootstrap/blueprint-parser/pkg +default .bootstrap/androidbp/obj/a.out + +build .bootstrap/bin/androidbp: g.bootstrap.cp .bootstrap/androidbp/obj/a.out +default .bootstrap/bin/androidbp + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Module: androidmk # Variant: @@ -565,10 +589,11 @@ rule s.bootstrap.minibp generator = true build .bootstrap/main.ninja.in: s.bootstrap.bigbp $ - ${g.bootstrap.srcDir}/Blueprints | .bootstrap/bin/androidmk $ - .bootstrap/bin/bpfmt .bootstrap/bin/bpmodify .bootstrap/bin/minibp $ - .bootstrap/bin/soong_build .bootstrap/bin/soong_env $ - .bootstrap/bin/soong_glob .bootstrap/bin/soong_jar + ${g.bootstrap.srcDir}/Blueprints | .bootstrap/bin/androidbp $ + .bootstrap/bin/androidmk .bootstrap/bin/bpfmt .bootstrap/bin/bpmodify $ + .bootstrap/bin/minibp .bootstrap/bin/soong_build $ + .bootstrap/bin/soong_env .bootstrap/bin/soong_glob $ + .bootstrap/bin/soong_jar default .bootstrap/main.ninja.in build .bootstrap/notAFile: phony default .bootstrap/notAFile