Merge "[androidbp] address comments aosp/149217" into master-soong
diff --git a/Blueprints b/Android.bp
similarity index 100%
rename from Blueprints
rename to Android.bp
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index 4d928b1..8d7025c 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -1,115 +1,320 @@
 package main
 
 import (
-	"android/soong/androidmk/parser"
+	mkparser "android/soong/androidmk/parser"
 	"fmt"
 	"strings"
+
+	bpparser "github.com/google/blueprint/parser"
 )
 
 const (
 	clear_vars = "__android_mk_clear_vars"
 )
 
-var stringProperties = map[string]string{
-	"LOCAL_MODULE":               "name",
-	"LOCAL_MODULE_STEM":          "stem",
-	"LOCAL_MODULE_CLASS":         "class",
-	"LOCAL_CXX_STL":              "stl",
-	"LOCAL_STRIP_MODULE":         "strip",
-	"LOCAL_MULTILIB":             "compile_multilib",
-	"LOCAL_ARM_MODE_HACK":        "instruction_set",
-	"LOCAL_SDK_VERSION":          "sdk_version",
-	"LOCAL_NDK_STL_VARIANT":      "stl",
-	"LOCAL_JAR_MANIFEST":         "manifest",
-	"LOCAL_JARJAR_RULES":         "jarjar_rules",
-	"LOCAL_CERTIFICATE":          "certificate",
-	"LOCAL_PACKAGE_NAME":         "name",
-	"LOCAL_MODULE_RELATIVE_PATH": "relative_install_path",
+var standardProperties = map[string]struct {
+	string
+	bpparser.ValueType
+}{
+	// String properties
+	"LOCAL_MODULE":               {"name", bpparser.String},
+	"LOCAL_MODULE_CLASS":         {"class", bpparser.String},
+	"LOCAL_CXX_STL":              {"stl", bpparser.String},
+	"LOCAL_STRIP_MODULE":         {"strip", bpparser.String},
+	"LOCAL_MULTILIB":             {"compile_multilib", bpparser.String},
+	"LOCAL_ARM_MODE_HACK":        {"instruction_set", bpparser.String},
+	"LOCAL_SDK_VERSION":          {"sdk_version", bpparser.String},
+	"LOCAL_NDK_STL_VARIANT":      {"stl", bpparser.String},
+	"LOCAL_JAR_MANIFEST":         {"manifest", bpparser.String},
+	"LOCAL_JARJAR_RULES":         {"jarjar_rules", bpparser.String},
+	"LOCAL_CERTIFICATE":          {"certificate", bpparser.String},
+	"LOCAL_PACKAGE_NAME":         {"name", bpparser.String},
+	"LOCAL_MODULE_RELATIVE_PATH": {"relative_install_path", bpparser.String},
+
+	// List properties
+	"LOCAL_SRC_FILES":               {"srcs", bpparser.List},
+	"LOCAL_SHARED_LIBRARIES":        {"shared_libs", bpparser.List},
+	"LOCAL_STATIC_LIBRARIES":        {"static_libs", bpparser.List},
+	"LOCAL_WHOLE_STATIC_LIBRARIES":  {"whole_static_libs", bpparser.List},
+	"LOCAL_SYSTEM_SHARED_LIBRARIES": {"system_shared_libs", bpparser.List},
+	"LOCAL_ASFLAGS":                 {"asflags", bpparser.List},
+	"LOCAL_CLANG_ASFLAGS":           {"clang_asflags", bpparser.List},
+	"LOCAL_CFLAGS":                  {"cflags", bpparser.List},
+	"LOCAL_CONLYFLAGS":              {"conlyflags", bpparser.List},
+	"LOCAL_CPPFLAGS":                {"cppflags", bpparser.List},
+	"LOCAL_LDFLAGS":                 {"ldflags", bpparser.List},
+	"LOCAL_REQUIRED_MODULES":        {"required", bpparser.List},
+	"LOCAL_MODULE_TAGS":             {"tags", bpparser.List},
+	"LOCAL_LDLIBS":                  {"host_ldlibs", bpparser.List},
+	"LOCAL_CLANG_CFLAGS":            {"clang_cflags", bpparser.List},
+	"LOCAL_YACCFLAGS":               {"yaccflags", bpparser.List},
+
+	"LOCAL_JAVA_RESOURCE_DIRS":    {"java_resource_dirs", bpparser.List},
+	"LOCAL_JAVACFLAGS":            {"javacflags", bpparser.List},
+	"LOCAL_DX_FLAGS":              {"dxflags", bpparser.List},
+	"LOCAL_JAVA_LIBRARIES":        {"java_libs", bpparser.List},
+	"LOCAL_STATIC_JAVA_LIBRARIES": {"java_static_libs", bpparser.List},
+	"LOCAL_AIDL_INCLUDES":         {"aidl_includes", bpparser.List},
+	"LOCAL_AAPT_FLAGS":            {"aaptflags", bpparser.List},
+	"LOCAL_PACKAGE_SPLITS":        {"package_splits", bpparser.List},
+
+	// Bool properties
+	"LOCAL_IS_HOST_MODULE":          {"host", bpparser.Bool},
+	"LOCAL_CLANG":                   {"clang", bpparser.Bool},
+	"LOCAL_FORCE_STATIC_EXECUTABLE": {"static", bpparser.Bool},
+	"LOCAL_ADDRESS_SANITIZER":       {"asan", bpparser.Bool},
+	"LOCAL_NATIVE_COVERAGE":         {"native_coverage", bpparser.Bool},
+	"LOCAL_NO_CRT":                  {"nocrt", bpparser.Bool},
+	"LOCAL_ALLOW_UNDEFINED_SYMBOLS": {"allow_undefined_symbols", bpparser.Bool},
+	"LOCAL_RTTI_FLAG":               {"rtti", bpparser.Bool},
+
+	"LOCAL_NO_STANDARD_LIBRARIES": {"no_standard_libraries", bpparser.Bool},
+
+	"LOCAL_EXPORT_PACKAGE_RESOURCES": {"export_package_resources", bpparser.Bool},
 }
 
-var listProperties = map[string]string{
-	"LOCAL_SRC_FILES":               "srcs",
-	"LOCAL_SHARED_LIBRARIES":        "shared_libs",
-	"LOCAL_STATIC_LIBRARIES":        "static_libs",
-	"LOCAL_WHOLE_STATIC_LIBRARIES":  "whole_static_libs",
-	"LOCAL_SYSTEM_SHARED_LIBRARIES": "system_shared_libs",
-	"LOCAL_C_INCLUDES":              "include_dirs",
-	"LOCAL_EXPORT_C_INCLUDE_DIRS":   "export_include_dirs",
-	"LOCAL_ASFLAGS":                 "asflags",
-	"LOCAL_CLANG_ASFLAGS":           "clang_asflags",
-	"LOCAL_CFLAGS":                  "cflags",
-	"LOCAL_CONLYFLAGS":              "conlyflags",
-	"LOCAL_CPPFLAGS":                "cppflags",
-	"LOCAL_LDFLAGS":                 "ldflags",
-	"LOCAL_REQUIRED_MODULES":        "required",
-	"LOCAL_MODULE_TAGS":             "tags",
-	"LOCAL_LDLIBS":                  "host_ldlibs",
-	"LOCAL_CLANG_CFLAGS":            "clang_cflags",
-	"LOCAL_YACCFLAGS":               "yaccflags",
-
-	"LOCAL_JAVA_RESOURCE_DIRS":    "java_resource_dirs",
-	"LOCAL_JAVACFLAGS":            "javacflags",
-	"LOCAL_DX_FLAGS":              "dxflags",
-	"LOCAL_JAVA_LIBRARIES":        "java_libs",
-	"LOCAL_STATIC_JAVA_LIBRARIES": "java_static_libs",
-	"LOCAL_AIDL_INCLUDES":         "aidl_includes",
-	"LOCAL_AAPT_FLAGS":            "aaptflags",
-	"LOCAL_PACKAGE_SPLITS":        "package_splits",
+var rewriteProperties = map[string]struct {
+	f func(file *bpFile, prefix string, value *mkparser.MakeString, append bool) error
+}{
+	"LOCAL_C_INCLUDES":            {localIncludeDirs},
+	"LOCAL_EXPORT_C_INCLUDE_DIRS": {exportIncludeDirs},
+	"LOCAL_MODULE_STEM":           {stem},
 }
 
-var boolProperties = map[string]string{
-	"LOCAL_IS_HOST_MODULE":          "host",
-	"LOCAL_CLANG":                   "clang",
-	"LOCAL_FORCE_STATIC_EXECUTABLE": "static",
-	"LOCAL_ADDRESS_SANITIZER":       "asan",
-	"LOCAL_NATIVE_COVERAGE":         "native_coverage",
-	"LOCAL_NO_CRT":                  "nocrt",
-	"LOCAL_ALLOW_UNDEFINED_SYMBOLS": "allow_undefined_symbols",
-	"LOCAL_RTTI_FLAG":               "rtti",
+func localAbsPath(value bpparser.Value) (*bpparser.Value, error) {
+	if value.Type != bpparser.String {
+		return nil, fmt.Errorf("isLocalAbsPath expected a string, got %d", value.Type)
+	}
 
-	"LOCAL_NO_STANDARD_LIBRARIES": "no_standard_libraries",
+	if value.Expression == nil {
+		if value.Variable == "LOCAL_PATH" {
+			return &bpparser.Value{
+				Type:        bpparser.String,
+				StringValue: ".",
+			}, nil
+		}
+		return nil, nil
+	}
 
-	"LOCAL_EXPORT_PACKAGE_RESOURCES": "export_package_resources",
+	if value.Expression.Operator != '+' {
+		return nil, nil
+	}
+
+	firstOperand := value.Expression.Args[0]
+	secondOperand := value.Expression.Args[1]
+	if firstOperand.Type != bpparser.String {
+		return nil, nil
+	}
+
+	if firstOperand.Expression != nil {
+		return nil, nil
+	}
+
+	if firstOperand.Variable != "LOCAL_PATH" {
+		return nil, nil
+	}
+
+	if secondOperand.Expression == nil && secondOperand.Variable == "" {
+		if strings.HasPrefix(secondOperand.StringValue, "/") {
+			secondOperand.StringValue = secondOperand.StringValue[1:]
+		}
+	}
+	return &secondOperand, nil
+}
+
+func emptyList(value *bpparser.Value) bool {
+	return value.Type == bpparser.List && value.Expression == nil && value.Variable == "" &&
+		len(value.ListValue) == 0
+}
+
+func splitLocalGlobal(file *bpFile, val *bpparser.Value) (local, global *bpparser.Value, err error) {
+	local = &bpparser.Value{
+		Type: bpparser.List,
+	}
+	global = &bpparser.Value{
+		Type: bpparser.List,
+	}
+
+	if val.Expression != nil {
+		localA, globalA, err := splitLocalGlobal(file, &val.Expression.Args[0])
+		if err != nil {
+			return nil, nil, err
+		}
+
+		localB, globalB, err := splitLocalGlobal(file, &val.Expression.Args[1])
+		if err != nil {
+			return nil, nil, err
+		}
+
+		if emptyList(localA) {
+			local = localB
+		} else if emptyList(localB) {
+			local = localA
+		} else {
+			localExpression := *val.Expression
+			local.Expression = &localExpression
+			local.Expression.Args = [2]bpparser.Value{*localA, *localB}
+		}
+
+		if emptyList(globalA) {
+			global = globalB
+		} else if emptyList(globalB) {
+			global = globalA
+		} else {
+			globalExpression := *val.Expression
+			global.Expression = &globalExpression
+			global.Expression.Args = [2]bpparser.Value{*globalA, *globalB}
+		}
+	} else if val.Variable != "" {
+		if val.Variable == "LOCAL_PATH" {
+			local.ListValue = append(local.ListValue, bpparser.Value{
+				Type:        bpparser.String,
+				StringValue: ".",
+			})
+		} else {
+			global.Variable = val.Variable
+		}
+	} else {
+		for _, v := range val.ListValue {
+			localPath, err := localAbsPath(v)
+			if err != nil {
+				return nil, nil, err
+			}
+			if localPath != nil {
+				local.ListValue = append(local.ListValue, *localPath)
+			} else {
+				global.ListValue = append(global.ListValue, v)
+			}
+		}
+	}
+
+	return local, global, nil
+}
+
+func localIncludeDirs(file *bpFile, prefix string, value *mkparser.MakeString, appendVariable bool) error {
+	val, err := makeVariableToBlueprint(file, value, bpparser.List)
+	if err != nil {
+		return err
+	}
+
+	local, global, err := splitLocalGlobal(file, val)
+	if err != nil {
+		return err
+	}
+
+	if len(global.ListValue) > 0 || global.Expression != nil || global.Variable != "" {
+		err = setVariable(file, appendVariable, prefix, "include_dirs", global, true)
+		if err != nil {
+			return err
+		}
+	}
+
+	if len(local.ListValue) > 0 || local.Expression != nil || local.Variable != "" {
+		err = setVariable(file, appendVariable, prefix, "local_include_dirs", local, true)
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func exportIncludeDirs(file *bpFile, prefix string, value *mkparser.MakeString, appendVariable bool) error {
+	val, err := makeVariableToBlueprint(file, value, bpparser.List)
+	if err != nil {
+		return err
+	}
+
+	local, global, err := splitLocalGlobal(file, val)
+	if err != nil {
+		return err
+	}
+
+	if len(local.ListValue) > 0 || local.Expression != nil || local.Variable != "" {
+		err = setVariable(file, appendVariable, prefix, "export_include_dirs", local, true)
+		if err != nil {
+			return err
+		}
+		appendVariable = true
+	}
+
+	// Add any paths that could not be converted to local relative paths to export_include_dirs
+	// anyways, they will cause an error if they don't exist and can be fixed manually.
+	if len(global.ListValue) > 0 || global.Expression != nil || global.Variable != "" {
+		err = setVariable(file, appendVariable, prefix, "export_include_dirs", global, true)
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func stem(file *bpFile, prefix string, value *mkparser.MakeString, appendVariable bool) error {
+	val, err := makeVariableToBlueprint(file, value, bpparser.String)
+	if err != nil {
+		return err
+	}
+	varName := "stem"
+
+	if val.Expression != nil && val.Expression.Operator == '+' &&
+		val.Expression.Args[0].Variable == "LOCAL_MODULE" {
+		varName = "suffix"
+		val = &val.Expression.Args[1]
+	}
+
+	return setVariable(file, appendVariable, prefix, varName, val, true)
 }
 
 var deleteProperties = map[string]struct{}{
 	"LOCAL_CPP_EXTENSION": struct{}{},
 }
 
-var propertySuffixes = []struct {
-	suffix string
-	class  string
-}{
-	{"arm", "arch"},
-	{"arm64", "arch"},
-	{"mips", "arch"},
-	{"mips64", "arch"},
-	{"x86", "arch"},
-	{"x86_64", "arch"},
-	{"32", "multilib"},
-	{"64", "multilib"},
+var propertyPrefixes = map[string]string{
+	"arm":    "arch.arm",
+	"arm64":  "arm.arm64",
+	"mips":   "arch.mips",
+	"mips64": "arch.mips64",
+	"x86":    "arch.x86",
+	"x86_64": "arch.x86_64",
+	"32":     "multilib.lib32",
+	"64":     "multilib.lib64",
 }
 
-var propertySuffixTranslations = map[string]string{
-	"32": "lib32",
-	"64": "lib64",
-}
-
-var conditionalTranslations = map[string]struct {
-	class  string
-	suffix string
-}{
-	"($(HOST_OS),darwin)":   {"target", "darwin"},
-	"($(HOST_OS), darwin)":  {"target", "darwin"},
-	"($(HOST_OS),windows)":  {"target", "windows"},
-	"($(HOST_OS), windows)": {"target", "windows"},
-	"($(HOST_OS),linux)":    {"target", "linux"},
-	"($(HOST_OS), linux)":   {"target", "linux"},
-	"($(BUILD_OS),darwin)":  {"target", "darwin"},
-	"($(BUILD_OS), darwin)": {"target", "darwin"},
-	"($(BUILD_OS),linux)":   {"target", "linux"},
-	"($(BUILD_OS), linux)":  {"target", "linux"},
-	"USE_MINGW":             {"target", "windows"},
+var conditionalTranslations = map[string]map[bool]string{
+	"($(HOST_OS),darwin)": {
+		true:  "target.darwin",
+		false: "target.not_darwin"},
+	"($(HOST_OS), darwin)": {
+		true:  "target.darwin",
+		false: "target.not_darwin"},
+	"($(HOST_OS),windows)": {
+		true:  "target.windows",
+		false: "target.not_windows"},
+	"($(HOST_OS), windows)": {
+		true:  "target.windows",
+		false: "target.not_windows"},
+	"($(HOST_OS),linux)": {
+		true:  "target.linux",
+		false: "target.not_linux"},
+	"($(HOST_OS), linux)": {
+		true:  "target.linux",
+		false: "target.not_linux"},
+	"($(BUILD_OS),darwin)": {
+		true:  "target.darwin",
+		false: "target.not_darwin"},
+	"($(BUILD_OS), darwin)": {
+		true:  "target.darwin",
+		false: "target.not_darwin"},
+	"($(BUILD_OS),linux)": {
+		true:  "target.linux",
+		false: "target.not_linux"},
+	"($(BUILD_OS), linux)": {
+		true:  "target.linux",
+		false: "target.not_linux"},
+	"USE_MINGW": {
+		true:  "target.windows",
+		false: "target.not_windows"},
 }
 
 func mydir(args []string) string {
@@ -130,16 +335,16 @@
 }
 
 var moduleTypes = map[string]string{
-	"BUILD_SHARED_LIBRARY":      "cc_library_shared",
-	"BUILD_STATIC_LIBRARY":      "cc_library_static",
-	"BUILD_HOST_SHARED_LIBRARY": "cc_library_host_shared",
-	"BUILD_HOST_STATIC_LIBRARY": "cc_library_host_static",
-	"BUILD_EXECUTABLE":          "cc_binary",
-	"BUILD_HOST_EXECUTABLE":     "cc_binary_host",
-	"BUILD_NATIVE_TEST":         "cc_test",
-	"BUILD_HOST_NATIVE_TEST":    "cc_test_host",
-	"BUILD_NATIVE_BENCHMARK":         "cc_benchmark",
-	"BUILD_HOST_NATIVE_BENCHMARK":    "cc_benchmark_host",
+	"BUILD_SHARED_LIBRARY":        "cc_library_shared",
+	"BUILD_STATIC_LIBRARY":        "cc_library_static",
+	"BUILD_HOST_SHARED_LIBRARY":   "cc_library_host_shared",
+	"BUILD_HOST_STATIC_LIBRARY":   "cc_library_host_static",
+	"BUILD_EXECUTABLE":            "cc_binary",
+	"BUILD_HOST_EXECUTABLE":       "cc_binary_host",
+	"BUILD_NATIVE_TEST":           "cc_test",
+	"BUILD_HOST_NATIVE_TEST":      "cc_test_host",
+	"BUILD_NATIVE_BENCHMARK":      "cc_benchmark",
+	"BUILD_HOST_NATIVE_BENCHMARK": "cc_benchmark_host",
 
 	"BUILD_JAVA_LIBRARY":             "java_library",
 	"BUILD_STATIC_JAVA_LIBRARY":      "java_library_static",
@@ -152,8 +357,8 @@
 
 var soongModuleTypes = map[string]bool{}
 
-func androidScope() parser.Scope {
-	globalScope := parser.NewScope(nil)
+func androidScope() mkparser.Scope {
+	globalScope := mkparser.NewScope(nil)
 	globalScope.Set("CLEAR_VARS", clear_vars)
 	globalScope.SetFunc("my-dir", mydir)
 	globalScope.SetFunc("all-java-files-under", allJavaFilesUnder)
diff --git a/androidmk/cmd/androidmk/androidmk.go b/androidmk/cmd/androidmk/androidmk.go
index 555e593..735a240 100644
--- a/androidmk/cmd/androidmk/androidmk.go
+++ b/androidmk/cmd/androidmk/androidmk.go
@@ -188,34 +188,23 @@
 	}
 
 	name := assignment.Name.Value(nil)
-	suffix := ""
-	class := ""
+	prefix := ""
 
 	if strings.HasPrefix(name, "LOCAL_") {
-		for _, v := range propertySuffixes {
-			s, c := v.suffix, v.class
-			if strings.HasSuffix(name, "_"+s) {
-				name = strings.TrimSuffix(name, "_"+s)
-				suffix = s
-				if s, ok := propertySuffixTranslations[s]; ok {
-					suffix = s
-				}
-				class = c
+		for k, v := range propertyPrefixes {
+			if strings.HasSuffix(name, "_"+k) {
+				name = strings.TrimSuffix(name, "_"+k)
+				prefix = v
 				break
 			}
 		}
 
 		if c != nil {
-			if class != "" {
-				file.errorf(assignment, "suffix assignment inside conditional, skipping conditional")
+			if prefix != "" {
+				file.errorf(assignment, "prefix assignment inside conditional, skipping conditional")
 			} else {
-				if v, ok := conditionalTranslations[c.cond]; ok {
-					class = v.class
-					suffix = v.suffix
-					if !c.eq {
-						suffix = "not_" + suffix
-					}
-				} else {
+				var ok bool
+				if prefix, ok = conditionalTranslations[c.cond][c.eq]; !ok {
 					panic("unknown conditional")
 				}
 			}
@@ -230,35 +219,38 @@
 		}
 	}
 
+	appendVariable := assignment.Type == "+="
+
 	var err error
-	if prop, ok := stringProperties[name]; ok {
-		err = setVariable(file, assignment.Value, assignment.Type == "+=", prop, bpparser.String, true, class, suffix)
-	} else if prop, ok := listProperties[name]; ok {
-		err = setVariable(file, assignment.Value, assignment.Type == "+=", prop, bpparser.List, true, class, suffix)
-	} else if prop, ok := boolProperties[name]; ok {
-		err = setVariable(file, assignment.Value, assignment.Type == "+=", prop, bpparser.Bool, true, class, suffix)
+	if prop, ok := standardProperties[name]; ok {
+		var val *bpparser.Value
+		val, err = makeVariableToBlueprint(file, assignment.Value, prop.ValueType)
+		if err == nil {
+			err = setVariable(file, appendVariable, prefix, prop.string, val, true)
+		}
+	} else if prop, ok := rewriteProperties[name]; ok {
+		err = prop.f(file, prefix, assignment.Value, appendVariable)
 	} else if _, ok := deleteProperties[name]; ok {
 		return
 	} else {
-		if name == "LOCAL_PATH" {
+		switch {
+		case name == "LOCAL_PATH":
 			// Nothing to do, except maybe avoid the "./" in paths?
-		} else if name == "LOCAL_ARM_MODE" {
+		case name == "LOCAL_ARM_MODE":
 			// This is a hack to get the LOCAL_ARM_MODE value inside
 			// of an arch: { arm: {} } block.
 			armModeAssign := assignment
 			armModeAssign.Name = mkparser.SimpleMakeString("LOCAL_ARM_MODE_HACK_arm", assignment.Name.Pos)
 			handleAssignment(file, armModeAssign, c)
-		} else if strings.HasPrefix(name, "LOCAL_") {
-			//setVariable(file, assignment, name, bpparser.String, true)
-			switch name {
-			case "LOCAL_ADDITIONAL_DEPENDENCIES":
-				// TODO: check for only .mk files?
-			default:
-				file.errorf(assignment, "unsupported assignment to %s", name)
-				return
-			}
-		} else {
-			err = setVariable(file, assignment.Value, assignment.Type == "+=", name, bpparser.List, false, class, suffix)
+		case name == "LOCAL_ADDITIONAL_DEPENDENCIES":
+			// TODO: check for only .mk files?
+		case strings.HasPrefix(name, "LOCAL_"):
+			file.errorf(assignment, "unsupported assignment to %s", name)
+			return
+		default:
+			var val *bpparser.Value
+			val, err = makeVariableToBlueprint(file, assignment.Value, bpparser.List)
+			err = setVariable(file, appendVariable, prefix, name, val, false)
 		}
 	}
 	if err != nil {
@@ -271,36 +263,38 @@
 		return
 	}
 
-	if v, ok := conditionalTranslations[c.cond]; ok {
-		class := v.class
-		suffix := v.suffix
-		disabledSuffix := v.suffix
-		if !c.eq {
-			suffix = "not_" + suffix
-		} else {
-			disabledSuffix = "not_" + disabledSuffix
-		}
+	if _, ok := conditionalTranslations[c.cond]; !ok {
+		panic("unknown conditional " + c.cond)
+	}
 
-		// Hoist all properties inside the condtional up to the top level
-		file.module.Properties = file.localAssignments[class+"___"+suffix].Value.MapValue
-		file.module.Properties = append(file.module.Properties, file.localAssignments[class])
-		file.localAssignments[class+"___"+suffix].Value.MapValue = nil
-		for i := range file.localAssignments[class].Value.MapValue {
-			if file.localAssignments[class].Value.MapValue[i].Name.Name == suffix {
-				file.localAssignments[class].Value.MapValue =
-					append(file.localAssignments[class].Value.MapValue[:i],
-						file.localAssignments[class].Value.MapValue[i+1:]...)
-			}
-		}
+	prefix := conditionalTranslations[c.cond][c.eq]
+	disabledPrefix := conditionalTranslations[c.cond][!c.eq]
 
-		// Create a fake assignment with enabled = false
-		err := setVariable(file, mkparser.SimpleMakeString("true", file.pos), false,
-			"disabled", bpparser.Bool, true, class, disabledSuffix)
-		if err != nil {
-			file.errorf(directive, err.Error())
+	names := strings.Split(prefix, ".")
+	if len(names) != 2 {
+		panic("expected class.type")
+	}
+	class := names[0]
+	typ := names[1]
+	classProp := file.localAssignments[class]
+
+	// Hoist all properties inside the condtional up to the top level
+	file.module.Properties = file.localAssignments[prefix].Value.MapValue
+	file.module.Properties = append(file.module.Properties, classProp)
+	file.localAssignments[prefix].Value.MapValue = nil
+	for i := range classProp.Value.MapValue {
+		if classProp.Value.MapValue[i].Name.Name == typ {
+			classProp.Value.MapValue = append(classProp.Value.MapValue[:i], classProp.Value.MapValue[i+1:]...)
 		}
-	} else {
-		panic("unknown conditional")
+	}
+
+	// Create a fake assignment with enabled = false
+	val, err := makeVariableToBlueprint(file, mkparser.SimpleMakeString("true", file.pos), bpparser.Bool)
+	if err == nil {
+		err = setVariable(file, false, disabledPrefix, "disabled", val, true)
+	}
+	if err != nil {
+		file.errorf(directive, err.Error())
 	}
 }
 
@@ -319,25 +313,8 @@
 	file.localAssignments = make(map[string]*bpparser.Property)
 }
 
-func setVariable(file *bpFile, val *mkparser.MakeString, plusequals bool, name string,
-	typ bpparser.ValueType, local bool, class string, suffix string) error {
-
-	pos := file.pos
-
-	var oldValue *bpparser.Value
-	if local {
-		var oldProp *bpparser.Property
-		if class != "" {
-			oldProp = file.localAssignments[name+"___"+class+"___"+suffix]
-		} else {
-			oldProp = file.localAssignments[name]
-		}
-		if oldProp != nil {
-			oldValue = &oldProp.Value
-		}
-	} else {
-		oldValue = file.globalAssignments[name]
-	}
+func makeVariableToBlueprint(file *bpFile, val *mkparser.MakeString,
+	typ bpparser.ValueType) (*bpparser.Value, error) {
 
 	var exp *bpparser.Value
 	var err error
@@ -353,61 +330,67 @@
 	}
 
 	if err != nil {
-		return err
+		return nil, err
+	}
+
+	return exp, nil
+}
+
+func setVariable(file *bpFile, plusequals bool, prefix, name string, value *bpparser.Value, local bool) error {
+
+	if prefix != "" {
+		name = prefix + "." + name
+	}
+
+	pos := file.pos
+
+	var oldValue *bpparser.Value
+	if local {
+		oldProp := file.localAssignments[name]
+		if oldProp != nil {
+			oldValue = &oldProp.Value
+		}
+	} else {
+		oldValue = file.globalAssignments[name]
 	}
 
 	if local {
 		if oldValue != nil && plusequals {
-			val, err := addValues(oldValue, exp)
+			val, err := addValues(oldValue, value)
 			if err != nil {
 				return fmt.Errorf("unsupported addition: %s", err.Error())
 			}
 			val.Expression.Pos = pos
 			*oldValue = *val
-		} else if class == "" {
+		} else {
+			names := strings.Split(name, ".")
+			container := &file.module.Properties
+
+			for i, n := range names[:len(names)-1] {
+				fqn := strings.Join(names[0:i+1], ".")
+				prop := file.localAssignments[fqn]
+				if prop == nil {
+					prop = &bpparser.Property{
+						Name: bpparser.Ident{Name: n, Pos: pos},
+						Pos:  pos,
+						Value: bpparser.Value{
+							Type:     bpparser.Map,
+							MapValue: []*bpparser.Property{},
+						},
+					}
+					file.localAssignments[fqn] = prop
+					*container = append(*container, prop)
+				}
+				container = &prop.Value.MapValue
+			}
+
 			prop := &bpparser.Property{
-				Name:  bpparser.Ident{Name: name, Pos: pos},
+				Name:  bpparser.Ident{Name: names[len(names)-1], Pos: pos},
 				Pos:   pos,
-				Value: *exp,
+				Value: *value,
 			}
 			file.localAssignments[name] = prop
-			file.module.Properties = append(file.module.Properties, prop)
-		} else {
-			classProp := file.localAssignments[class]
-			if classProp == nil {
-				classProp = &bpparser.Property{
-					Name: bpparser.Ident{Name: class, Pos: pos},
-					Pos:  pos,
-					Value: bpparser.Value{
-						Type:     bpparser.Map,
-						MapValue: []*bpparser.Property{},
-					},
-				}
-				file.localAssignments[class] = classProp
-				file.module.Properties = append(file.module.Properties, classProp)
-			}
-
-			suffixProp := file.localAssignments[class+"___"+suffix]
-			if suffixProp == nil {
-				suffixProp = &bpparser.Property{
-					Name: bpparser.Ident{Name: suffix, Pos: pos},
-					Pos:  pos,
-					Value: bpparser.Value{
-						Type:     bpparser.Map,
-						MapValue: []*bpparser.Property{},
-					},
-				}
-				file.localAssignments[class+"___"+suffix] = suffixProp
-				classProp.Value.MapValue = append(classProp.Value.MapValue, suffixProp)
-			}
-
-			prop := &bpparser.Property{
-				Name:  bpparser.Ident{Name: name, Pos: pos},
-				Pos:   pos,
-				Value: *exp,
-			}
-			file.localAssignments[class+"___"+suffix+"___"+name] = prop
-			suffixProp.Value.MapValue = append(suffixProp.Value.MapValue, prop)
+			*container = append(*container, prop)
 		}
 	} else {
 		if oldValue != nil && plusequals {
@@ -416,8 +399,8 @@
 					Name: name,
 					Pos:  pos,
 				},
-				Value:     *exp,
-				OrigValue: *exp,
+				Value:     *value,
+				OrigValue: *value,
 				Pos:       pos,
 				Assigner:  "+=",
 			}
@@ -428,8 +411,8 @@
 					Name: name,
 					Pos:  pos,
 				},
-				Value:     *exp,
-				OrigValue: *exp,
+				Value:     *value,
+				OrigValue: *value,
 				Pos:       pos,
 				Assigner:  "=",
 			}
diff --git a/build.ninja.in b/build.ninja.in
index 50ee810..988b2f9 100644
--- a/build.ninja.in
+++ b/build.ninja.in
@@ -53,7 +53,7 @@
 # Variant:
 # Type:    bootstrap_go_binary
 # Factory: github.com/google/blueprint/bootstrap.newGoBinaryModule
-# Defined: build/soong/Blueprints:186:1
+# Defined: build/soong/Android.bp:186:1
 
 build .bootstrap/androidbp/obj/androidbp.a: g.bootstrap.gc $
         ${g.bootstrap.srcDir}/build/soong/androidbp/cmd/androidbp.go $
@@ -77,7 +77,7 @@
 # Variant:
 # Type:    bootstrap_go_binary
 # Factory: github.com/google/blueprint/bootstrap.newGoBinaryModule
-# Defined: build/soong/Blueprints:162:1
+# Defined: build/soong/Android.bp:162:1
 
 build .bootstrap/androidmk/obj/androidmk.a: g.bootstrap.gc $
         ${g.bootstrap.srcDir}/build/soong/androidmk/cmd/androidmk/android.go $
@@ -103,7 +103,7 @@
 # Variant:
 # Type:    bootstrap_go_package
 # Factory: github.com/google/blueprint/bootstrap.newGoPackageModule
-# Defined: build/soong/Blueprints:175:1
+# Defined: build/soong/Android.bp:175:1
 
 build .bootstrap/androidmk-parser/pkg/android/soong/androidmk/parser.a: $
         g.bootstrap.gc $
@@ -310,7 +310,7 @@
 # Variant:
 # Type:    bootstrap_go_package
 # Factory: github.com/google/blueprint/bootstrap.newGoPackageModule
-# Defined: art/build/Blueprints:13:1
+# Defined: art/build/Android.bp:13:1
 
 build .bootstrap/soong-art/pkg/android/soong/art.a: g.bootstrap.gc $
         ${g.bootstrap.srcDir}/art/build/art.go | ${g.bootstrap.gcCmd} $
@@ -334,7 +334,7 @@
 # Variant:
 # Type:    bootstrap_go_package
 # Factory: github.com/google/blueprint/bootstrap.newGoPackageModule
-# Defined: build/soong/Blueprints:94:1
+# Defined: build/soong/Android.bp:94:1
 
 build .bootstrap/soong-cc/pkg/android/soong/cc.a: g.bootstrap.gc $
         ${g.bootstrap.srcDir}/build/soong/cc/builder.go $
@@ -367,7 +367,7 @@
 # Variant:
 # Type:    bootstrap_go_package
 # Factory: github.com/google/blueprint/bootstrap.newGoPackageModule
-# Defined: build/soong/Blueprints:72:1
+# Defined: build/soong/Android.bp:72:1
 
 build .bootstrap/soong-common/pkg/android/soong/common.a: g.bootstrap.gc $
         ${g.bootstrap.srcDir}/build/soong/common/arch.go $
@@ -397,7 +397,7 @@
 # Variant:
 # Type:    bootstrap_go_package
 # Factory: github.com/google/blueprint/bootstrap.newGoPackageModule
-# Defined: build/soong/Blueprints:41:1
+# Defined: build/soong/Android.bp:41:1
 
 build .bootstrap/soong-env/pkg/android/soong/env.a: g.bootstrap.gc $
         ${g.bootstrap.srcDir}/build/soong/env/env.go | ${g.bootstrap.gcCmd}
@@ -409,7 +409,7 @@
 # Variant:
 # Type:    bootstrap_go_package
 # Factory: github.com/google/blueprint/bootstrap.newGoPackageModule
-# Defined: build/soong/Blueprints:119:1
+# Defined: build/soong/Android.bp:119:1
 
 build .bootstrap/soong-genrule/pkg/android/soong/genrule.a: g.bootstrap.gc $
         ${g.bootstrap.srcDir}/build/soong/genrule/genrule.go | $
@@ -432,7 +432,7 @@
 # Variant:
 # Type:    bootstrap_go_package
 # Factory: github.com/google/blueprint/bootstrap.newGoPackageModule
-# Defined: build/soong/Blueprints:60:1
+# Defined: build/soong/Android.bp:60:1
 
 build .bootstrap/soong-glob/pkg/android/soong/glob.a: g.bootstrap.gc $
         ${g.bootstrap.srcDir}/build/soong/glob/glob.go | ${g.bootstrap.gcCmd} $
@@ -447,7 +447,7 @@
 # Variant:
 # Type:    bootstrap_go_package
 # Factory: github.com/google/blueprint/bootstrap.newGoPackageModule
-# Defined: build/soong/Blueprints:139:1
+# Defined: build/soong/Android.bp:139:1
 
 build .bootstrap/soong-java/pkg/android/soong/java.a: g.bootstrap.gc $
         ${g.bootstrap.srcDir}/build/soong/java/app_builder.go $
@@ -476,7 +476,7 @@
 # Variant:
 # Type:    bootstrap_go_binary
 # Factory: github.com/google/blueprint/bootstrap.newGoBinaryModule
-# Defined: build/soong/Blueprints:13:1
+# Defined: build/soong/Android.bp:13:1
 
 build .bootstrap/soong_build/obj/soong_build.a: g.bootstrap.gc $
         ${g.bootstrap.srcDir}/build/soong/cmd/soong_build/main.go | $
@@ -512,7 +512,7 @@
 # Variant:
 # Type:    bootstrap_go_binary
 # Factory: github.com/google/blueprint/bootstrap.newGoBinaryModule
-# Defined: build/soong/Blueprints:31:1
+# Defined: build/soong/Android.bp:31:1
 
 build .bootstrap/soong_env/obj/soong_env.a: g.bootstrap.gc $
         ${g.bootstrap.srcDir}/build/soong/cmd/soong_env/soong_env.go | $
@@ -534,7 +534,7 @@
 # Variant:
 # Type:    bootstrap_go_binary
 # Factory: github.com/google/blueprint/bootstrap.newGoBinaryModule
-# Defined: build/soong/Blueprints:50:1
+# Defined: build/soong/Android.bp:50:1
 
 build .bootstrap/soong_glob/obj/soong_glob.a: g.bootstrap.gc $
         ${g.bootstrap.srcDir}/build/soong/cmd/soong_glob/soong_glob.go | $
@@ -560,7 +560,7 @@
 # Variant:
 # Type:    bootstrap_go_binary
 # Factory: github.com/google/blueprint/bootstrap.newGoBinaryModule
-# Defined: build/soong/Blueprints:132:1
+# Defined: build/soong/Android.bp:132:1
 
 build .bootstrap/soong_jar/obj/soong_jar.a: g.bootstrap.gc $
         ${g.bootstrap.srcDir}/build/soong/cmd/soong_jar/soong_jar.go | $
@@ -590,7 +590,7 @@
     generator = true
 
 build .bootstrap/main.ninja.in: s.bootstrap.bigbp $
-        ${g.bootstrap.srcDir}/Blueprints | .bootstrap/bin/androidbp $
+        ${g.bootstrap.srcDir}/Android.bp | .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 $
@@ -603,7 +603,7 @@
         .bootstrap/bootstrap.ninja.in
 default build.ninja
 build .bootstrap/bootstrap.ninja.in: s.bootstrap.minibp $
-        ${g.bootstrap.srcDir}/Blueprints | .bootstrap/bin/minibp
+        ${g.bootstrap.srcDir}/Android.bp | .bootstrap/bin/minibp
     checkFile = ${g.bootstrap.bootstrapManifest}
 default .bootstrap/bootstrap.ninja.in
 
diff --git a/cc/builder.go b/cc/builder.go
index 218c73b..ab0e40c 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -188,13 +188,13 @@
 			ccCmd = gccCmd(flags.toolchain, ccCmd)
 		}
 
-		deps = append([]string{ccCmd}, deps...)
+		objDeps := append([]string{ccCmd}, deps...)
 
 		ctx.Build(pctx, blueprint.BuildParams{
 			Rule:      cc,
 			Outputs:   []string{objFile},
 			Inputs:    []string{srcFile},
-			Implicits: deps,
+			Implicits: objDeps,
 			Args: map[string]string{
 				"cFlags": moduleCflags,
 				"ccCmd":  ccCmd,
diff --git a/cc/cc.go b/cc/cc.go
index a928312..61e2568 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -404,6 +404,9 @@
 	}
 
 	// Include dir cflags
+	common.CheckSrcDirsExist(ctx, c.Properties.Include_dirs, "include_dirs")
+	common.CheckModuleSrcDirsExist(ctx, c.Properties.Local_include_dirs, "local_include_dirs")
+
 	rootIncludeDirs := pathtools.PrefixPaths(c.Properties.Include_dirs, ctx.AConfig().SrcDir())
 	localIncludeDirs := pathtools.PrefixPaths(c.Properties.Local_include_dirs, common.ModuleSrcDir(ctx))
 	flags.GlobalFlags = append(flags.GlobalFlags,
@@ -1096,6 +1099,8 @@
 
 	c.objFiles = objFiles
 	c.out = outputFile
+
+	common.CheckModuleSrcDirsExist(ctx, c.Properties.Export_include_dirs, "export_include_dirs")
 	includeDirs := pathtools.PrefixPaths(c.Properties.Export_include_dirs, common.ModuleSrcDir(ctx))
 	c.exportFlags = []string{includeDirsToFlags(includeDirs)}
 
diff --git a/common/arch.go b/common/arch.go
index 2a09ae9..4ea0f26 100644
--- a/common/arch.go
+++ b/common/arch.go
@@ -377,8 +377,7 @@
 
 		archProperties := &archProperties{}
 		forEachInterface(reflect.ValueOf(archProperties), func(v reflect.Value) {
-			newValue := proptools.CloneProperties(propertiesValue)
-			proptools.ZeroProperties(newValue.Elem())
+			newValue := proptools.CloneEmptyProperties(propertiesValue)
 			v.Set(newValue)
 		})
 
diff --git a/common/paths.go b/common/paths.go
index bcd6d8c..070662a 100644
--- a/common/paths.go
+++ b/common/paths.go
@@ -16,6 +16,7 @@
 
 import (
 	"path/filepath"
+	"os"
 )
 
 // ModuleOutDir returns the path to the module-specific output directory.
@@ -74,3 +75,33 @@
 func ModuleJSCompiledDir(ctx AndroidModuleContext) string {
 	return filepath.Join(ModuleOutDir(ctx), "js")
 }
+
+// CheckModuleSrcDirsExist logs an error on a property if any of the directories relative to the
+// Blueprints file don't exist.
+func CheckModuleSrcDirsExist(ctx AndroidModuleContext, dirs []string, prop string) {
+	for _, dir := range dirs {
+		fullDir := filepath.Join(ModuleSrcDir(ctx), dir)
+		if _, err := os.Stat(fullDir); err != nil {
+			if os.IsNotExist(err) {
+				ctx.PropertyErrorf(prop, "module source directory %q does not exist", dir)
+			} else {
+				ctx.PropertyErrorf(prop, "%s", err.Error())
+			}
+		}
+	}
+}
+
+// CheckModuleSrcDirsExist logs an error on a property if any of the directories relative to the
+// top of the source tree don't exist.
+func CheckSrcDirsExist(ctx AndroidModuleContext, dirs []string, prop string) {
+	for _, dir := range dirs {
+		fullDir := filepath.Join(ctx.AConfig().SrcDir(), dir)
+		if _, err := os.Stat(fullDir); err != nil {
+			if os.IsNotExist(err) {
+				ctx.PropertyErrorf(prop, "top-level source directory %q does not exist", dir)
+			} else {
+				ctx.PropertyErrorf(prop, "%s", err.Error())
+			}
+		}
+	}
+}
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 0f276d0..42ab047 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -77,7 +77,8 @@
 
 func (g *generator) AndroidDynamicDependencies(ctx common.AndroidDynamicDependerModuleContext) []string {
 	if g.properties.Tool != "" {
-		return []string{g.properties.Tool}
+		ctx.AddFarVariationDependencies([]blueprint.Variation{{"hostordevice", common.Host.String()}},
+			g.properties.Tool)
 	}
 	return nil
 }
diff --git a/root.bp b/root.bp
index c8a3ce2..ea17db3 100644
--- a/root.bp
+++ b/root.bp
@@ -1,3 +1,5 @@
+subname = "Android.bp"
+
 subdirs = [
     "art",
     "build/blueprint",