androidbp: handle suffix props, conditionals, map assignments
Change-Id: I6aec388e72d960d80943620024c2d16d51a0b095
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
bpparser "github.com/google/blueprint/parser"
|
||||
@@ -13,11 +14,13 @@ import (
|
||||
type androidMkWriter struct {
|
||||
*bufio.Writer
|
||||
|
||||
file *bpparser.File
|
||||
path string
|
||||
blueprint *bpparser.File
|
||||
path string
|
||||
|
||||
mapScope map[string][]*bpparser.Property
|
||||
}
|
||||
|
||||
func (w *androidMkWriter) valueToString(value bpparser.Value) string {
|
||||
func valueToString(value bpparser.Value) string {
|
||||
if value.Variable != "" {
|
||||
return fmt.Sprintf("$(%s)", value.Variable)
|
||||
} else {
|
||||
@@ -25,90 +28,216 @@ func (w *androidMkWriter) valueToString(value bpparser.Value) string {
|
||||
case bpparser.Bool:
|
||||
return fmt.Sprintf(`"%t"`, value.BoolValue)
|
||||
case bpparser.String:
|
||||
return fmt.Sprintf(`"%s"`, value.StringValue)
|
||||
return fmt.Sprintf(`"%s"`, processWildcards(value.StringValue))
|
||||
case bpparser.List:
|
||||
return fmt.Sprintf("\\\n%s\n", w.listToMkString(value.ListValue))
|
||||
return fmt.Sprintf("\\\n%s\n", listToMkString(value.ListValue))
|
||||
case bpparser.Map:
|
||||
w.errorf("maps not supported in assignment")
|
||||
return "ERROR: unsupported type map in assignment"
|
||||
return fmt.Sprintf("ERROR can't convert map to string")
|
||||
default:
|
||||
return fmt.Sprintf("ERROR: unsupported type %d", value.Type)
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (w *androidMkWriter) listToMkString(list []bpparser.Value) string {
|
||||
// TODO: handle non-recursive wildcards?
|
||||
func processWildcards(s string) string {
|
||||
re := regexp.MustCompile("(.*)/\\*\\*/(.*)")
|
||||
submatches := re.FindAllStringSubmatch(s, -1)
|
||||
if submatches != nil && len(submatches[0]) > 2 {
|
||||
// Found a wildcard rule
|
||||
return fmt.Sprintf("$(call find-files-in-subdirs, $(LOCAL_PATH), %s, %s)",
|
||||
submatches[0][2], submatches[0][1])
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func listToMkString(list []bpparser.Value) string {
|
||||
lines := make([]string, 0, len(list))
|
||||
for _, tok := range list {
|
||||
lines = append(lines, fmt.Sprintf("\t\"%s\"", tok.StringValue))
|
||||
if tok.Type == bpparser.String {
|
||||
lines = append(lines, fmt.Sprintf("\t\"%s\"", processWildcards(tok.StringValue)))
|
||||
} else {
|
||||
lines = append(lines, fmt.Sprintf("# ERROR: unsupported type %s in list",
|
||||
tok.Type.String()))
|
||||
}
|
||||
}
|
||||
|
||||
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 translateTargetConditionals(props []*bpparser.Property,
|
||||
disabledBuilds map[string]bool, isHostRule bool) (computedProps []string) {
|
||||
for _, target := range props {
|
||||
conditionals := targetScopedPropertyConditionals
|
||||
if isHostRule {
|
||||
conditionals = hostScopedPropertyConditionals
|
||||
}
|
||||
|
||||
conditional, ok := conditionals[target.Name.Name]
|
||||
if !ok {
|
||||
// not found
|
||||
conditional = fmt.Sprintf(
|
||||
"ifeq(true, true) # ERROR: unsupported conditional host [%s]",
|
||||
target.Name.Name)
|
||||
}
|
||||
|
||||
var scopedProps []string
|
||||
for _, targetScopedProp := range target.Value.MapValue {
|
||||
if mkProp, ok := standardProperties[targetScopedProp.Name.Name]; ok {
|
||||
scopedProps = append(scopedProps, fmt.Sprintf("%s += %s",
|
||||
mkProp.string, valueToString(targetScopedProp.Value)))
|
||||
} else if "disabled" == targetScopedProp.Name.Name {
|
||||
if targetScopedProp.Value.BoolValue {
|
||||
disabledBuilds[target.Name.Name] = true
|
||||
} else {
|
||||
delete(disabledBuilds, target.Name.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(scopedProps) > 0 {
|
||||
computedProps = append(computedProps, conditional)
|
||||
computedProps = append(computedProps, scopedProps...)
|
||||
computedProps = append(computedProps, "endif")
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func translateSuffixProperties(suffixProps []*bpparser.Property,
|
||||
suffixMap map[string]string) (computedProps []string) {
|
||||
for _, suffixProp := range suffixProps {
|
||||
if suffix, ok := suffixMap[suffixProp.Name.Name]; ok {
|
||||
for _, stdProp := range suffixProp.Value.MapValue {
|
||||
if mkProp, ok := standardProperties[stdProp.Name.Name]; ok {
|
||||
computedProps = append(computedProps, fmt.Sprintf("%s_%s := %s", mkProp.string, suffix, valueToString(stdProp.Value)))
|
||||
} else {
|
||||
computedProps = append(computedProps, fmt.Sprintf("# ERROR: unsupported property %s", stdProp.Name.Name))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
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) handleComment(comment *bpparser.Comment) {
|
||||
for _, c := range comment.Comment {
|
||||
mkComment := strings.Replace(c, "//", "#", 1)
|
||||
// TODO: handle /* comments?
|
||||
fmt.Fprintf(w, "%s\n", mkComment)
|
||||
fmt.Fprintf(w, "#%s\n", c)
|
||||
}
|
||||
}
|
||||
|
||||
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)))
|
||||
}
|
||||
func (w *androidMkWriter) writeModule(moduleRule string, props []string,
|
||||
disabledBuilds map[string]bool, isHostRule bool) {
|
||||
disabledConditionals := disabledTargetConditionals
|
||||
if isHostRule {
|
||||
disabledConditionals = disabledHostConditionals
|
||||
}
|
||||
for build, _ := range disabledBuilds {
|
||||
if conditional, ok := disabledConditionals[build]; ok {
|
||||
fmt.Fprintf(w, "%s\n", conditional)
|
||||
defer fmt.Fprintf(w, "endif\n")
|
||||
}
|
||||
}
|
||||
|
||||
mkModule := strings.Join(standardProps, "\n")
|
||||
w.WriteString(mkModule)
|
||||
fmt.Fprintf(w, "include $(CLEAR_VARS)\n")
|
||||
fmt.Fprintf(w, "%s\n", strings.Join(props, "\n"))
|
||||
fmt.Fprintf(w, "include $(%s)\n\n", moduleRule)
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "include $(%s)\n\n", moduleName)
|
||||
} else {
|
||||
w.errorf("Unsupported module %s", module.Type.Name)
|
||||
func (w *androidMkWriter) handleModule(module *bpparser.Module) {
|
||||
moduleRule := fmt.Sprintf(module.Type.Name)
|
||||
if translation, ok := moduleTypeToRule[module.Type.Name]; ok {
|
||||
moduleRule = translation
|
||||
}
|
||||
|
||||
isHostRule := strings.Contains(moduleRule, "HOST")
|
||||
hostSupported := false
|
||||
standardProps := make([]string, 0, len(module.Properties))
|
||||
disabledBuilds := make(map[string]bool)
|
||||
for _, prop := range module.Properties {
|
||||
if mkProp, ok := standardProperties[prop.Name.Name]; ok {
|
||||
standardProps = append(standardProps, fmt.Sprintf("%s := %s", mkProp.string, valueToString(prop.Value)))
|
||||
} else if suffixMap, ok := suffixProperties[prop.Name.Name]; ok {
|
||||
suffixProps := w.lookupMap(prop.Value)
|
||||
standardProps = append(standardProps, translateSuffixProperties(suffixProps, suffixMap)...)
|
||||
} else if "target" == prop.Name.Name {
|
||||
props := w.lookupMap(prop.Value)
|
||||
standardProps = append(standardProps, translateTargetConditionals(props, disabledBuilds, isHostRule)...)
|
||||
} else if "host_supported" == prop.Name.Name {
|
||||
hostSupported = prop.Value.BoolValue
|
||||
} else {
|
||||
standardProps = append(standardProps, fmt.Sprintf("# ERROR: Unsupported property %s", prop.Name.Name))
|
||||
}
|
||||
}
|
||||
|
||||
// write out target build
|
||||
w.writeModule(moduleRule, standardProps, disabledBuilds, isHostRule)
|
||||
if hostSupported {
|
||||
hostModuleRule := "NO CORRESPONDING HOST RULE" + moduleRule
|
||||
if trans, ok := targetToHostModuleRule[moduleRule]; ok {
|
||||
hostModuleRule = trans
|
||||
}
|
||||
w.writeModule(hostModuleRule, standardProps,
|
||||
disabledBuilds, true)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *androidMkWriter) handleSubdirs(value bpparser.Value) {
|
||||
switch value.Type {
|
||||
case bpparser.String:
|
||||
fmt.Fprintf(w, "$(call all-makefiles-under, %s)\n", value.StringValue)
|
||||
case bpparser.List:
|
||||
for _, tok := range value.ListValue {
|
||||
fmt.Fprintf(w, "$(call all-makefiles-under, %s)\n", tok.StringValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (w *androidMkWriter) handleAssignment(assignment *bpparser.Assignment) {
|
||||
assigner := ":="
|
||||
if assignment.Assigner != "=" {
|
||||
assigner = assignment.Assigner
|
||||
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
|
||||
}
|
||||
fmt.Fprintf(w, "%s %s %s\n", assignment.Name.Name, assigner,
|
||||
valueToString(assignment.OrigValue))
|
||||
}
|
||||
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))
|
||||
ch := make(chan interface{}, len(w.blueprint.Comments)+len(w.blueprint.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]
|
||||
for defsIdx < len(w.blueprint.Defs) || commIdx < len(w.blueprint.Comments) {
|
||||
if defsIdx == len(w.blueprint.Defs) {
|
||||
ch <- w.blueprint.Comments[commIdx]
|
||||
commIdx++
|
||||
} else if commIdx == len(w.file.Comments) {
|
||||
ch <- w.file.Defs[defsIdx]
|
||||
} else if commIdx == len(w.blueprint.Comments) {
|
||||
ch <- w.blueprint.Defs[defsIdx]
|
||||
defsIdx++
|
||||
} else {
|
||||
commentsPos := 0
|
||||
defsPos := 0
|
||||
|
||||
def := w.file.Defs[defsIdx]
|
||||
def := w.blueprint.Defs[defsIdx]
|
||||
switch def := def.(type) {
|
||||
case *bpparser.Module:
|
||||
defsPos = def.LbracePos.Line
|
||||
@@ -116,7 +245,7 @@ func (w *androidMkWriter) iter() <-chan interface{} {
|
||||
defsPos = def.Pos.Line
|
||||
}
|
||||
|
||||
comment := w.file.Comments[commIdx]
|
||||
comment := w.blueprint.Comments[commIdx]
|
||||
commentsPos = comment.Pos.Line
|
||||
|
||||
if commentsPos < defsPos {
|
||||
@@ -134,7 +263,7 @@ func (w *androidMkWriter) iter() <-chan interface{} {
|
||||
}
|
||||
|
||||
func (w *androidMkWriter) write() {
|
||||
outFilePath := fmt.Sprintf("%s/Android.mk.out", w.path)
|
||||
outFilePath := fmt.Sprintf("%s/Androidbp.mk", w.path)
|
||||
fmt.Printf("Writing %s\n", outFilePath)
|
||||
|
||||
f, err := os.Create(outFilePath)
|
||||
@@ -142,14 +271,12 @@ func (w *androidMkWriter) write() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := f.Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
defer f.Close()
|
||||
|
||||
w.Writer = bufio.NewWriter(f)
|
||||
|
||||
w.WriteString("LOCAL_PATH := $(call my-dir)\n")
|
||||
|
||||
for block := range w.iter() {
|
||||
switch block := block.(type) {
|
||||
case *bpparser.Module:
|
||||
@@ -179,7 +306,7 @@ func main() {
|
||||
}
|
||||
|
||||
scope := bpparser.NewScope(nil)
|
||||
file, errs := bpparser.Parse(os.Args[1], reader, scope)
|
||||
blueprint, 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)
|
||||
@@ -187,8 +314,9 @@ func main() {
|
||||
}
|
||||
|
||||
writer := &androidMkWriter{
|
||||
file: file,
|
||||
path: path.Dir(os.Args[1]),
|
||||
blueprint: blueprint,
|
||||
path: path.Dir(os.Args[1]),
|
||||
mapScope: make(map[string][]*bpparser.Property),
|
||||
}
|
||||
|
||||
writer.write()
|
||||
|
@@ -19,6 +19,7 @@ var standardProperties = map[string]struct {
|
||||
"manifest": {"LOCAL_JAR_MANIFEST", bpparser.String},
|
||||
"jarjar_rules": {"LOCAL_JARJAR_RULES", bpparser.String},
|
||||
"certificate": {"LOCAL_CERTIFICATE", bpparser.String},
|
||||
"suffix": {"LOCAL_MODULE_SUFFIX", bpparser.String},
|
||||
//"name": "LOCAL_PACKAGE_NAME", TODO
|
||||
|
||||
// ==== LIST PROPERTIES ====
|
||||
@@ -62,7 +63,7 @@ var standardProperties = map[string]struct {
|
||||
"export_package_resources": {"LOCAL_EXPORT_PACKAGE_RESOURCES", bpparser.Bool},
|
||||
}
|
||||
|
||||
var moduleTypes = map[string]string{
|
||||
var moduleTypeToRule = map[string]string{
|
||||
"cc_library_shared": "BUILD_SHARED_LIBRARY",
|
||||
"cc_library_static": "BUILD_STATIC_LIBRARY",
|
||||
"cc_library_host_shared": "BUILD_HOST_SHARED_LIBRARY",
|
||||
@@ -80,3 +81,50 @@ var moduleTypes = map[string]string{
|
||||
"android_app": "BUILD_PACKAGE",
|
||||
"prebuilt": "BUILD_PREBUILT",
|
||||
}
|
||||
|
||||
var suffixProperties = map[string]map[string]string{
|
||||
"multilib": {"lib32": "32", "lib64": "64"},
|
||||
"arch": {"arm": "arm", "arm64": "arm64", "mips": "mips", "mips64": "mips64",
|
||||
"x86": "x86", "x86_64": "x86_64"},
|
||||
}
|
||||
|
||||
var hostScopedPropertyConditionals = map[string]string{
|
||||
"darwin": "ifeq ($(HOST_OS), darwin)",
|
||||
"not_darwin": "ifneq($(HOST_OS), darwin)",
|
||||
"windows": "ifeq ($(HOST_OS), windows)",
|
||||
"not_windows": "ifneq($(HOST_OS), windows)",
|
||||
"linux": "ifeq ($(HOST_OS), linux)",
|
||||
"not_linux": "ifneq($(HOST_OS), linux)",
|
||||
}
|
||||
|
||||
// TODO: host target?
|
||||
var targetScopedPropertyConditionals = map[string]string{
|
||||
"android32": "ifeq($(TARGET_IS_64_BIT), false)",
|
||||
"not_android32": "ifeq($(TARGET_IS_64_BIT), true)",
|
||||
"android64": "ifeq($(TARGET_IS_64_BIT), true)",
|
||||
"not_android64": "ifeq($(TARGET_IS_64_BIT), false)",
|
||||
}
|
||||
|
||||
var disabledHostConditionals = map[string]string{
|
||||
"darwin": "ifneq ($(HOST_OS), darwin)",
|
||||
"not_darwin": "ifeq($(HOST_OS), darwin)",
|
||||
"windows": "ifneq ($(HOST_OS), windows)",
|
||||
"not_windows": "ifeq($(HOST_OS), windows)",
|
||||
"linux": "ifneq ($(HOST_OS), linux)",
|
||||
"not_linux": "ifeq($(HOST_OS), linux)",
|
||||
}
|
||||
|
||||
var disabledTargetConditionals = map[string]string{
|
||||
"android32": "ifeq($(TARGET_IS_64_BIT), true)",
|
||||
"not_android32": "ifeq($(TARGET_IS_64_BIT), false)",
|
||||
"android64": "ifeq($(TARGET_IS_64_BIT), false)",
|
||||
"not_android64": "ifeq($(TARGET_IS_64_BIT), true)",
|
||||
}
|
||||
|
||||
var targetToHostModuleRule = map[string]string{
|
||||
"BUILD_SHARED_LIBRARY": "BUILD_HOST_SHARED_LIBRARY",
|
||||
"BUILD_STATIC_LIBRARY": "BUILD_HOST_STATIC_LIBRARY",
|
||||
"BUILD_EXECUTABLE": "BUILD_HOST_EXECUTABLE",
|
||||
"BUILD_NATIVE_TEST": "BUILD_HOST_NATIVE_TEST",
|
||||
"BUILD_JAVA_LIBRARY": "BUILD_HOST_JAVA_LIBRARY",
|
||||
}
|
||||
|
Reference in New Issue
Block a user