2015-04-29 21:46:49 +02:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2015-06-29 23:18:27 +02:00
|
|
|
"bytes"
|
2015-05-11 21:26:07 +02:00
|
|
|
"errors"
|
2015-04-29 21:46:49 +02:00
|
|
|
"fmt"
|
2015-06-29 23:18:27 +02:00
|
|
|
"io"
|
2015-04-29 21:46:49 +02:00
|
|
|
"os"
|
|
|
|
"path"
|
2015-05-11 21:26:07 +02:00
|
|
|
"path/filepath"
|
2015-04-30 21:14:34 +02:00
|
|
|
"regexp"
|
2015-04-29 21:46:49 +02:00
|
|
|
"strings"
|
2015-06-30 01:24:57 +02:00
|
|
|
"text/scanner"
|
2015-04-29 21:46:49 +02:00
|
|
|
|
2015-07-01 01:27:57 +02:00
|
|
|
"github.com/google/blueprint"
|
2015-04-29 21:46:49 +02:00
|
|
|
bpparser "github.com/google/blueprint/parser"
|
|
|
|
)
|
|
|
|
|
2015-05-11 21:26:07 +02:00
|
|
|
var recursiveSubdirRegex *regexp.Regexp = regexp.MustCompile("(.+)/\\*\\*/(.+)")
|
|
|
|
|
2015-04-29 21:46:49 +02:00
|
|
|
type androidMkWriter struct {
|
2015-06-29 23:18:27 +02:00
|
|
|
io.Writer
|
2015-04-29 21:46:49 +02:00
|
|
|
|
2015-04-30 21:14:34 +02:00
|
|
|
blueprint *bpparser.File
|
|
|
|
path string
|
2015-04-29 21:46:49 +02:00
|
|
|
}
|
|
|
|
|
2015-07-07 21:22:51 +02:00
|
|
|
type propAssignment struct {
|
|
|
|
name, assigner, value string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a propAssignment) assignmentWithSuffix(suffix string) string {
|
|
|
|
if suffix != "" {
|
|
|
|
a.name = a.name + "_" + suffix
|
|
|
|
}
|
|
|
|
return a.name + " " + a.assigner + " " + a.value
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a propAssignment) assignment() string {
|
|
|
|
return a.assignmentWithSuffix("")
|
|
|
|
}
|
|
|
|
|
2015-06-29 23:18:27 +02:00
|
|
|
func (w *androidMkWriter) WriteString(s string) (int, error) {
|
|
|
|
return io.WriteString(w.Writer, s)
|
|
|
|
}
|
|
|
|
|
|
|
|
func valueToString(value bpparser.Value) (string, error) {
|
2015-07-01 01:27:57 +02:00
|
|
|
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)
|
2015-06-29 23:18:27 +02:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
2015-07-01 01:27:57 +02:00
|
|
|
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)
|
2015-04-29 21:46:49 +02:00
|
|
|
}
|
2015-04-30 21:14:34 +02:00
|
|
|
}
|
|
|
|
|
2015-06-27 02:40:54 +02:00
|
|
|
func appendValueToValue(dest bpparser.Value, src bpparser.Value) (bpparser.Value, error) {
|
|
|
|
if src.Type != dest.Type {
|
|
|
|
return bpparser.Value{}, fmt.Errorf("ERROR: source and destination types don't match")
|
|
|
|
}
|
|
|
|
switch dest.Type {
|
|
|
|
case bpparser.List:
|
|
|
|
dest.ListValue = append(dest.ListValue, src.ListValue...)
|
|
|
|
return dest, nil
|
|
|
|
case bpparser.String:
|
|
|
|
dest.StringValue += src.StringValue
|
|
|
|
return dest, nil
|
|
|
|
default:
|
|
|
|
return bpparser.Value{}, fmt.Errorf("ERROR: unsupported append with type %s", dest.Type.String())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-11 21:26:07 +02:00
|
|
|
func getTopOfAndroidTree(wd string) (string, error) {
|
|
|
|
if !filepath.IsAbs(wd) {
|
|
|
|
return "", errors.New("path must be absolute: " + wd)
|
|
|
|
}
|
|
|
|
|
|
|
|
topfile := "build/soong/bootstrap.bash"
|
|
|
|
|
|
|
|
for "/" != wd {
|
|
|
|
expected := filepath.Join(wd, topfile)
|
|
|
|
|
|
|
|
if _, err := os.Stat(expected); err == nil {
|
|
|
|
// Found the top
|
|
|
|
return wd, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
wd = filepath.Join(wd, "..")
|
|
|
|
}
|
|
|
|
|
|
|
|
return "", errors.New("couldn't find top of tree from " + wd)
|
|
|
|
}
|
|
|
|
|
2015-04-30 21:14:34 +02:00
|
|
|
// TODO: handle non-recursive wildcards?
|
|
|
|
func processWildcards(s string) string {
|
2015-05-11 21:26:07 +02:00
|
|
|
submatches := recursiveSubdirRegex.FindStringSubmatch(s)
|
|
|
|
if len(submatches) > 2 {
|
2015-04-30 21:14:34 +02:00
|
|
|
// Found a wildcard rule
|
|
|
|
return fmt.Sprintf("$(call find-files-in-subdirs, $(LOCAL_PATH), %s, %s)",
|
2015-05-11 21:26:07 +02:00
|
|
|
submatches[2], submatches[1])
|
2015-04-30 21:14:34 +02:00
|
|
|
}
|
2015-04-29 21:46:49 +02:00
|
|
|
|
2015-04-30 21:14:34 +02:00
|
|
|
return s
|
2015-04-29 21:46:49 +02:00
|
|
|
}
|
|
|
|
|
2015-06-29 23:18:27 +02:00
|
|
|
func listToMkString(list []bpparser.Value) (string, error) {
|
2015-04-29 21:46:49 +02:00
|
|
|
lines := make([]string, 0, len(list))
|
|
|
|
for _, tok := range list {
|
2015-06-29 23:18:27 +02:00
|
|
|
val, err := valueToString(tok)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
lines = append(lines, fmt.Sprintf(" %s", val))
|
2015-04-29 21:46:49 +02:00
|
|
|
}
|
|
|
|
|
2015-06-29 23:18:27 +02:00
|
|
|
return strings.Join(lines, " \\\n"), nil
|
2015-04-29 21:46:49 +02:00
|
|
|
}
|
|
|
|
|
2015-04-30 21:14:34 +02:00
|
|
|
func translateTargetConditionals(props []*bpparser.Property,
|
2015-06-29 23:18:27 +02:00
|
|
|
disabledBuilds map[string]bool, isHostRule bool) (computedProps []string, err error) {
|
2015-04-30 21:14:34 +02:00
|
|
|
for _, target := range props {
|
|
|
|
conditionals := targetScopedPropertyConditionals
|
2015-06-11 23:05:01 +02:00
|
|
|
altConditionals := hostScopedPropertyConditionals
|
2015-04-30 21:14:34 +02:00
|
|
|
if isHostRule {
|
2015-06-11 23:05:01 +02:00
|
|
|
conditionals, altConditionals = altConditionals, conditionals
|
2015-04-30 21:14:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
conditional, ok := conditionals[target.Name.Name]
|
|
|
|
if !ok {
|
2015-06-11 23:05:01 +02:00
|
|
|
if _, ok := altConditionals[target.Name.Name]; ok {
|
|
|
|
// This is only for the other build type
|
|
|
|
continue
|
|
|
|
} else {
|
2015-06-29 23:18:27 +02:00
|
|
|
return nil, fmt.Errorf("Unsupported conditional %q", target.Name.Name)
|
2015-06-11 23:05:01 +02:00
|
|
|
}
|
2015-04-30 21:14:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
var scopedProps []string
|
|
|
|
for _, targetScopedProp := range target.Value.MapValue {
|
2015-07-07 21:22:51 +02:00
|
|
|
if assignment, ok, err := translateSingleProperty(targetScopedProp); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else if ok {
|
|
|
|
scopedProps = append(scopedProps, assignment.assignment())
|
2015-04-30 21:14:34 +02:00
|
|
|
} else if "disabled" == targetScopedProp.Name.Name {
|
|
|
|
if targetScopedProp.Value.BoolValue {
|
|
|
|
disabledBuilds[target.Name.Name] = true
|
|
|
|
} else {
|
|
|
|
delete(disabledBuilds, target.Name.Name)
|
|
|
|
}
|
2015-06-29 23:18:27 +02:00
|
|
|
} else {
|
|
|
|
return nil, fmt.Errorf("Unsupported target property %q", targetScopedProp.Name.Name)
|
2015-04-30 21:14:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(scopedProps) > 0 {
|
2015-06-11 23:05:01 +02:00
|
|
|
if conditional != "" {
|
|
|
|
computedProps = append(computedProps, conditional)
|
|
|
|
computedProps = append(computedProps, scopedProps...)
|
|
|
|
computedProps = append(computedProps, "endif")
|
|
|
|
} else {
|
|
|
|
computedProps = append(computedProps, scopedProps...)
|
|
|
|
}
|
2015-04-30 21:14:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-07-07 02:49:43 +02:00
|
|
|
var secondTargetReplacer = strings.NewReplacer("TARGET_", "TARGET_2ND_")
|
|
|
|
|
2015-04-30 21:14:34 +02:00
|
|
|
func translateSuffixProperties(suffixProps []*bpparser.Property,
|
2015-06-29 23:18:27 +02:00
|
|
|
suffixMap map[string]string) (computedProps []string, err error) {
|
2015-04-30 21:14:34 +02:00
|
|
|
for _, suffixProp := range suffixProps {
|
|
|
|
if suffix, ok := suffixMap[suffixProp.Name.Name]; ok {
|
|
|
|
for _, stdProp := range suffixProp.Value.MapValue {
|
2015-07-07 21:22:51 +02:00
|
|
|
if assignment, ok, err := translateSingleProperty(stdProp); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else if ok {
|
|
|
|
computedProps = append(computedProps, assignment.assignmentWithSuffix(suffix))
|
2015-04-30 21:14:34 +02:00
|
|
|
} else {
|
2015-06-29 23:18:27 +02:00
|
|
|
return nil, fmt.Errorf("Unsupported property %q", stdProp.Name.Name)
|
2015-04-30 21:14:34 +02:00
|
|
|
}
|
|
|
|
}
|
2015-07-07 02:49:43 +02:00
|
|
|
} else if variant, ok := cpuVariantConditionals[suffixProp.Name.Name]; ok {
|
|
|
|
var conditionalProps []propAssignment
|
|
|
|
for _, stdProp := range suffixProp.Value.MapValue {
|
|
|
|
if assignment, ok, err := translateSingleProperty(stdProp); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else if ok {
|
|
|
|
conditionalProps = append(conditionalProps, assignment)
|
|
|
|
} else {
|
|
|
|
return nil, fmt.Errorf("Unsupported property %q", stdProp.Name.Name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
appendComputedProps := func() {
|
|
|
|
computedProps = append(computedProps, variant.conditional)
|
|
|
|
for _, prop := range conditionalProps {
|
|
|
|
prop.assigner = "+="
|
|
|
|
computedProps = append(computedProps, prop.assignmentWithSuffix(variant.suffix))
|
|
|
|
}
|
|
|
|
computedProps = append(computedProps, "endif")
|
|
|
|
}
|
|
|
|
|
|
|
|
appendComputedProps()
|
|
|
|
if variant.secondArch {
|
|
|
|
variant.conditional = secondTargetReplacer.Replace(variant.conditional)
|
|
|
|
variant.suffix = secondTargetReplacer.Replace(variant.suffix)
|
|
|
|
appendComputedProps()
|
|
|
|
}
|
2015-06-29 23:18:27 +02:00
|
|
|
} else {
|
|
|
|
return nil, fmt.Errorf("Unsupported suffix property %q", suffixProp.Name.Name)
|
2015-04-30 21:14:34 +02:00
|
|
|
}
|
2015-04-29 21:46:49 +02:00
|
|
|
}
|
2015-04-30 21:14:34 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-07-07 21:22:51 +02:00
|
|
|
func translateSingleProperty(prop *bpparser.Property) (propAssignment, bool, error) {
|
|
|
|
var assignment propAssignment
|
|
|
|
if mkProp, ok := standardProperties[prop.Name.Name]; ok {
|
|
|
|
name := mkProp.string
|
|
|
|
val, err := valueToString(prop.Value)
|
|
|
|
if err != nil {
|
|
|
|
return propAssignment{}, false, err
|
|
|
|
}
|
|
|
|
assignment = propAssignment{name, ":=", val}
|
|
|
|
} else if rwProp, ok := rewriteProperties[prop.Name.Name]; ok {
|
|
|
|
val, err := valueToString(prop.Value)
|
|
|
|
if err != nil {
|
|
|
|
return propAssignment{}, false, err
|
|
|
|
}
|
|
|
|
assignment, err = rwProp.f(rwProp.string, prop, val)
|
|
|
|
if err != nil {
|
|
|
|
return propAssignment{}, false, err
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Unhandled, return false with no error to tell the caller to handle it
|
|
|
|
return propAssignment{}, false, nil
|
2015-06-30 21:19:47 +02:00
|
|
|
}
|
2015-07-07 21:22:51 +02:00
|
|
|
return assignment, true, nil
|
2015-06-30 21:19:47 +02:00
|
|
|
}
|
|
|
|
|
2015-07-07 21:22:51 +02:00
|
|
|
func appendAssign(name string, prop *bpparser.Property, val string) (propAssignment, error) {
|
|
|
|
return propAssignment{name, "+=", val}, nil
|
2015-06-11 01:20:14 +02:00
|
|
|
}
|
|
|
|
|
2015-07-07 21:22:51 +02:00
|
|
|
func prependLocalPath(name string, prop *bpparser.Property, val string) (propAssignment, error) {
|
|
|
|
return propAssignment{name, "+=", fmt.Sprintf("$(addprefix $(LOCAL_PATH)/,%s)", val)}, nil
|
2015-06-23 00:40:14 +02:00
|
|
|
}
|
|
|
|
|
2015-07-07 21:22:51 +02:00
|
|
|
func prependLocalModule(name string, prop *bpparser.Property, val string) (propAssignment, error) {
|
|
|
|
return propAssignment{name, ":=", "$(LOCAL_MODULE)" + val}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func versionScript(name string, prop *bpparser.Property, val string) (propAssignment, error) {
|
|
|
|
return propAssignment{name, "+=", "-Wl,--version-script,$(LOCAL_PATH)/" + val}, nil
|
2015-07-07 02:48:31 +02:00
|
|
|
}
|
|
|
|
|
2015-04-30 21:14:34 +02:00
|
|
|
func (w *androidMkWriter) writeModule(moduleRule string, props []string,
|
|
|
|
disabledBuilds map[string]bool, isHostRule bool) {
|
|
|
|
disabledConditionals := disabledTargetConditionals
|
|
|
|
if isHostRule {
|
|
|
|
disabledConditionals = disabledHostConditionals
|
2015-04-29 21:46:49 +02:00
|
|
|
}
|
2015-04-30 21:14:34 +02:00
|
|
|
for build, _ := range disabledBuilds {
|
|
|
|
if conditional, ok := disabledConditionals[build]; ok {
|
|
|
|
fmt.Fprintf(w, "%s\n", conditional)
|
|
|
|
defer fmt.Fprintf(w, "endif\n")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Fprintf(w, "include $(CLEAR_VARS)\n")
|
|
|
|
fmt.Fprintf(w, "%s\n", strings.Join(props, "\n"))
|
|
|
|
fmt.Fprintf(w, "include $(%s)\n\n", moduleRule)
|
2015-04-29 21:46:49 +02:00
|
|
|
}
|
|
|
|
|
2015-06-29 23:18:27 +02:00
|
|
|
func (w *androidMkWriter) parsePropsAndWriteModule(module *Module) error {
|
2015-06-25 00:37:17 +02:00
|
|
|
standardProps := make([]string, 0, len(module.bpmod.Properties))
|
2015-04-30 21:14:34 +02:00
|
|
|
disabledBuilds := make(map[string]bool)
|
2015-06-25 00:37:17 +02:00
|
|
|
for _, prop := range module.bpmod.Properties {
|
2015-07-07 21:22:51 +02:00
|
|
|
if assignment, ok, err := translateSingleProperty(prop); err != nil {
|
|
|
|
return err
|
|
|
|
} else if ok {
|
|
|
|
standardProps = append(standardProps, assignment.assignment())
|
2015-04-30 21:14:34 +02:00
|
|
|
} else if suffixMap, ok := suffixProperties[prop.Name.Name]; ok {
|
2015-07-01 01:27:57 +02:00
|
|
|
props, err := translateSuffixProperties(prop.Value.MapValue, suffixMap)
|
2015-06-29 23:18:27 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
standardProps = append(standardProps, props...)
|
2015-04-30 21:14:34 +02:00
|
|
|
} else if "target" == prop.Name.Name {
|
2015-07-01 01:27:57 +02:00
|
|
|
props, err := translateTargetConditionals(prop.Value.MapValue, disabledBuilds, module.isHostRule)
|
2015-06-29 23:18:27 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
standardProps = append(standardProps, props...)
|
2015-06-25 00:50:07 +02:00
|
|
|
} else if _, ok := ignoredProperties[prop.Name.Name]; ok {
|
2015-04-30 21:14:34 +02:00
|
|
|
} else {
|
2015-06-29 23:18:27 +02:00
|
|
|
return fmt.Errorf("Unsupported property %q", prop.Name.Name)
|
2015-04-29 21:46:49 +02:00
|
|
|
}
|
2015-04-30 21:14:34 +02:00
|
|
|
}
|
2015-04-29 21:46:49 +02:00
|
|
|
|
2015-06-25 00:37:17 +02:00
|
|
|
w.writeModule(module.mkname, standardProps, disabledBuilds, module.isHostRule)
|
2015-06-29 23:18:27 +02:00
|
|
|
|
|
|
|
return nil
|
2015-06-11 23:05:01 +02:00
|
|
|
}
|
|
|
|
|
2015-07-06 22:36:50 +02:00
|
|
|
func canUseWholeStaticLibrary(m *Module) (bool, error) {
|
|
|
|
ret := true
|
|
|
|
|
|
|
|
isCompatible := func(props Properties, prop *bpparser.Property) error {
|
|
|
|
for _, p := range prop.Value.MapValue {
|
|
|
|
if p.Name.Name == "cflags" {
|
|
|
|
ret = false
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
if prop.Name.Name == "static" {
|
|
|
|
if p.Name.Name == "srcs" {
|
|
|
|
ret = false
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
err := m.IterateArchPropertiesWithName("shared", isCompatible)
|
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
err = m.IterateArchPropertiesWithName("static", isCompatible)
|
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret, nil
|
|
|
|
}
|
|
|
|
|
2015-06-29 23:18:27 +02:00
|
|
|
func (w *androidMkWriter) mutateModule(module *Module) (modules []*Module, err error) {
|
2015-06-25 00:37:17 +02:00
|
|
|
modules = []*Module{module}
|
|
|
|
|
|
|
|
if module.bpname == "cc_library" {
|
|
|
|
modules = []*Module{
|
|
|
|
newModule(module.bpmod),
|
|
|
|
newModule(module.bpmod),
|
|
|
|
}
|
2015-06-27 02:40:54 +02:00
|
|
|
|
|
|
|
ccLinkageCopy := func(props Properties, prop *bpparser.Property) error {
|
|
|
|
for _, p := range prop.Value.MapValue {
|
|
|
|
err := props.AppendToProp(p.Name.Name, p)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
props.DeleteProp(prop.Name.Name)
|
|
|
|
return nil
|
|
|
|
}
|
2015-07-06 22:36:50 +02:00
|
|
|
deleteProp := func(props Properties, prop *bpparser.Property) error {
|
2015-06-27 02:40:54 +02:00
|
|
|
props.DeleteProp(prop.Name.Name)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-07-06 22:36:50 +02:00
|
|
|
if ok, err := canUseWholeStaticLibrary(module); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else if ok {
|
|
|
|
err = modules[0].IterateArchPropertiesWithName("srcs", deleteProp)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if nameProp, ok := modules[0].Properties().Prop("name"); !ok {
|
|
|
|
return nil, fmt.Errorf("Can't find name property")
|
|
|
|
} else {
|
|
|
|
modules[0].Properties().AppendToProp("whole_static_libs", &bpparser.Property{
|
|
|
|
Value: bpparser.Value{
|
|
|
|
Type: bpparser.List,
|
|
|
|
ListValue: []bpparser.Value{
|
|
|
|
nameProp.Value.Copy(),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-25 00:37:17 +02:00
|
|
|
modules[0].bpname = "cc_library_shared"
|
2015-06-27 02:40:54 +02:00
|
|
|
err := modules[0].IterateArchPropertiesWithName("shared", ccLinkageCopy)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2015-07-06 22:36:50 +02:00
|
|
|
err = modules[0].IterateArchPropertiesWithName("static", deleteProp)
|
2015-06-27 02:40:54 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2015-06-25 00:37:17 +02:00
|
|
|
modules[1].bpname = "cc_library_static"
|
2015-07-06 22:36:50 +02:00
|
|
|
err = modules[1].IterateArchPropertiesWithName("shared", deleteProp)
|
2015-06-27 02:40:54 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
err = modules[1].IterateArchPropertiesWithName("static", ccLinkageCopy)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2015-06-25 00:37:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, mod := range modules {
|
2015-06-29 23:18:27 +02:00
|
|
|
err := mod.translateRuleName()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2015-06-27 02:40:54 +02:00
|
|
|
if mod.isHostRule || !mod.PropBool("host_supported") {
|
2015-06-25 00:37:17 +02:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
m := &Module{
|
|
|
|
bpmod: mod.bpmod,
|
|
|
|
bpname: mod.bpname,
|
|
|
|
isHostRule: true,
|
|
|
|
}
|
2015-06-29 23:18:27 +02:00
|
|
|
err = m.translateRuleName()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2015-06-25 00:37:17 +02:00
|
|
|
modules = append(modules, m)
|
2015-06-11 23:05:01 +02:00
|
|
|
}
|
|
|
|
|
2015-06-24 23:56:00 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-06-29 23:18:27 +02:00
|
|
|
func (w *androidMkWriter) handleModule(inputModule *bpparser.Module) error {
|
2015-06-30 01:24:57 +02:00
|
|
|
comment := w.getCommentBlock(inputModule.Type.Pos)
|
|
|
|
if translation, translated, err := getCommentTranslation(comment); err != nil {
|
|
|
|
return err
|
|
|
|
} else if translated {
|
|
|
|
w.WriteString(translation)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-06-30 02:44:56 +02:00
|
|
|
if ignoredModuleType[inputModule.Type.Name] {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-06-29 23:18:27 +02:00
|
|
|
modules, err := w.mutateModule(newModule(inputModule))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2015-06-11 23:05:01 +02:00
|
|
|
|
2015-06-24 23:56:00 +02:00
|
|
|
for _, module := range modules {
|
2015-06-29 23:18:27 +02:00
|
|
|
err := w.parsePropsAndWriteModule(module)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2015-04-30 21:14:34 +02:00
|
|
|
}
|
2015-06-29 23:18:27 +02:00
|
|
|
|
|
|
|
return nil
|
2015-04-30 21:14:34 +02:00
|
|
|
}
|
2015-04-29 21:46:49 +02:00
|
|
|
|
2015-04-30 21:14:34 +02:00
|
|
|
func (w *androidMkWriter) handleSubdirs(value bpparser.Value) {
|
2015-05-11 21:26:07 +02:00
|
|
|
subdirs := make([]string, 0, len(value.ListValue))
|
|
|
|
for _, tok := range value.ListValue {
|
|
|
|
subdirs = append(subdirs, tok.StringValue)
|
2015-04-29 21:46:49 +02:00
|
|
|
}
|
2015-06-03 03:44:59 +02:00
|
|
|
// The current makefile may be generated to outside the source tree (such as the out directory), with a different structure.
|
|
|
|
fmt.Fprintf(w, "# Uncomment the following line if you really want to include subdir Android.mks.\n")
|
|
|
|
fmt.Fprintf(w, "# include $(wildcard $(addsuffix $(LOCAL_PATH)/%s/, Android.mk))\n", strings.Join(subdirs, " "))
|
2015-04-29 21:46:49 +02:00
|
|
|
}
|
|
|
|
|
2015-05-11 21:26:07 +02:00
|
|
|
func (w *androidMkWriter) handleLocalPath() error {
|
2015-07-01 01:27:57 +02:00
|
|
|
w.WriteString("LOCAL_PATH := " + w.path + "\n")
|
2015-06-11 01:18:58 +02:00
|
|
|
w.WriteString("LOCAL_MODULE_MAKEFILE := $(lastword $(MAKEFILE_LIST))\n\n")
|
2015-05-11 21:26:07 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-06-30 01:24:57 +02:00
|
|
|
// Returns any block comment on the line preceding pos as a string
|
|
|
|
func (w *androidMkWriter) getCommentBlock(pos scanner.Position) string {
|
|
|
|
var buf []byte
|
|
|
|
|
|
|
|
comments := w.blueprint.Comments
|
|
|
|
for i, c := range comments {
|
|
|
|
if c.EndLine() == pos.Line-1 {
|
|
|
|
line := pos.Line
|
|
|
|
for j := i; j >= 0; j-- {
|
|
|
|
c = comments[j]
|
|
|
|
if c.EndLine() == line-1 {
|
|
|
|
buf = append([]byte(c.Text()), buf...)
|
|
|
|
line = c.Pos.Line
|
|
|
|
} else {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return string(buf)
|
|
|
|
}
|
|
|
|
|
|
|
|
func getCommentTranslation(comment string) (string, bool, error) {
|
|
|
|
lines := strings.Split(comment, "\n")
|
|
|
|
|
|
|
|
if directive, i, err := getCommentDirective(lines); err != nil {
|
|
|
|
return "", false, err
|
|
|
|
} else if directive != "" {
|
|
|
|
switch directive {
|
|
|
|
case "ignore":
|
|
|
|
return "", true, nil
|
|
|
|
case "start":
|
|
|
|
return getCommentTranslationBlock(lines[i+1:])
|
|
|
|
case "end":
|
|
|
|
return "", false, fmt.Errorf("Unexpected Android.mk:end translation directive")
|
|
|
|
default:
|
|
|
|
return "", false, fmt.Errorf("Unknown Android.mk module translation directive %q", directive)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return "", false, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func getCommentTranslationBlock(lines []string) (string, bool, error) {
|
|
|
|
var buf []byte
|
|
|
|
|
|
|
|
for _, line := range lines {
|
|
|
|
if directive := getLineCommentDirective(line); directive != "" {
|
|
|
|
switch directive {
|
|
|
|
case "end":
|
|
|
|
return string(buf), true, nil
|
|
|
|
default:
|
|
|
|
return "", false, fmt.Errorf("Unexpected Android.mk translation directive %q inside start", directive)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
buf = append(buf, line...)
|
|
|
|
buf = append(buf, '\n')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return "", false, fmt.Errorf("Missing Android.mk:end translation directive")
|
|
|
|
}
|
|
|
|
|
|
|
|
func getCommentDirective(lines []string) (directive string, n int, err error) {
|
|
|
|
for i, line := range lines {
|
|
|
|
if directive := getLineCommentDirective(line); directive != "" {
|
|
|
|
return strings.ToLower(directive), i, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return "", -1, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func getLineCommentDirective(line string) string {
|
|
|
|
line = strings.TrimSpace(line)
|
|
|
|
if strings.HasPrefix(line, "Android.mk:") {
|
|
|
|
line = strings.TrimPrefix(line, "Android.mk:")
|
|
|
|
line = strings.TrimSpace(line)
|
|
|
|
return line
|
|
|
|
}
|
|
|
|
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2015-06-29 23:18:27 +02:00
|
|
|
func (w *androidMkWriter) write(writer io.Writer) (err error) {
|
|
|
|
w.Writer = writer
|
2015-04-29 21:46:49 +02:00
|
|
|
|
2015-06-29 23:18:27 +02:00
|
|
|
if err = w.handleLocalPath(); err != nil {
|
2015-06-29 22:46:00 +02:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, block := range w.blueprint.Defs {
|
2015-04-29 21:46:49 +02:00
|
|
|
switch block := block.(type) {
|
|
|
|
case *bpparser.Module:
|
2015-06-29 23:18:27 +02:00
|
|
|
err = w.handleModule(block)
|
2015-04-29 21:46:49 +02:00
|
|
|
case *bpparser.Assignment:
|
2015-07-01 01:27:57 +02:00
|
|
|
// Nothing
|
2015-06-29 23:18:27 +02:00
|
|
|
default:
|
|
|
|
return fmt.Errorf("Unhandled def %v", block)
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2015-04-29 21:46:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-03 03:44:59 +02:00
|
|
|
return nil
|
2015-04-29 21:46:49 +02:00
|
|
|
}
|
|
|
|
|
2015-07-01 01:27:57 +02:00
|
|
|
func translate(rootFile, androidBp, androidMk string) error {
|
|
|
|
|
|
|
|
ctx := blueprint.NewContext()
|
|
|
|
|
|
|
|
var blueprintFile *bpparser.File
|
2015-04-29 21:46:49 +02:00
|
|
|
|
2015-07-01 01:27:57 +02:00
|
|
|
_, errs := ctx.WalkBlueprintsFiles(rootFile, func(file *bpparser.File) {
|
|
|
|
if file.Name == androidBp {
|
|
|
|
blueprintFile = file
|
|
|
|
}
|
|
|
|
})
|
2015-04-29 21:46:49 +02:00
|
|
|
if len(errs) > 0 {
|
2015-06-29 23:18:27 +02:00
|
|
|
return errs[0]
|
2015-04-29 21:46:49 +02:00
|
|
|
}
|
|
|
|
|
2015-07-01 01:27:57 +02:00
|
|
|
if blueprintFile == nil {
|
|
|
|
return fmt.Errorf("File %q wasn't parsed from %q", androidBp, rootFile)
|
|
|
|
}
|
|
|
|
|
2015-04-29 21:46:49 +02:00
|
|
|
writer := &androidMkWriter{
|
2015-07-01 01:27:57 +02:00
|
|
|
blueprint: blueprintFile,
|
2015-06-03 03:44:59 +02:00
|
|
|
path: path.Dir(androidBp),
|
2015-04-29 21:46:49 +02:00
|
|
|
}
|
|
|
|
|
2015-06-29 23:18:27 +02:00
|
|
|
buf := &bytes.Buffer{}
|
|
|
|
|
2015-07-01 01:27:57 +02:00
|
|
|
err := writer.write(buf)
|
2015-06-29 23:18:27 +02:00
|
|
|
if err != nil {
|
|
|
|
os.Remove(androidMk)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
f, err := os.Create(androidMk)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
|
|
|
|
_, err = f.Write(buf.Bytes())
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
2015-07-01 01:27:57 +02:00
|
|
|
if len(os.Args) < 4 {
|
|
|
|
fmt.Fprintln(os.Stderr, "Expected root Android.bp, input and output filename arguments")
|
2015-06-29 23:18:27 +02:00
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
|
2015-07-01 01:27:57 +02:00
|
|
|
rootFile := os.Args[1]
|
|
|
|
androidBp, err := filepath.Rel(filepath.Dir(rootFile), os.Args[2])
|
|
|
|
if err != nil {
|
|
|
|
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]
|
2015-06-29 23:18:27 +02:00
|
|
|
|
2015-07-01 01:27:57 +02:00
|
|
|
err = translate(rootFile, androidBp, androidMk)
|
2015-06-03 03:44:59 +02:00
|
|
|
if err != nil {
|
2015-06-29 23:18:27 +02:00
|
|
|
fmt.Fprintf(os.Stderr, "Error translating %s: %s\n", androidBp, err.Error())
|
2015-06-03 03:44:59 +02:00
|
|
|
os.Exit(1)
|
|
|
|
}
|
2015-04-29 21:46:49 +02:00
|
|
|
}
|