Merge "Execute the blueprint wrapper"
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index c45b3f4..31eb6cc 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -80,6 +80,7 @@
 	"LOCAL_C_INCLUDES":            {localIncludeDirs},
 	"LOCAL_EXPORT_C_INCLUDE_DIRS": {exportIncludeDirs},
 	"LOCAL_MODULE_STEM":           {stem},
+	"LOCAL_MODULE_HOST_OS":        {hostOs},
 }
 
 func localAbsPath(value bpparser.Value) (*bpparser.Value, error) {
@@ -267,6 +268,46 @@
 	return setVariable(file, appendVariable, prefix, varName, val, true)
 }
 
+func hostOs(file *bpFile, prefix string, value *mkparser.MakeString, appendVariable bool) error {
+	val, err := makeVariableToBlueprint(file, value, bpparser.List)
+	if err != nil {
+		return err
+	}
+
+	inList := func(s string) bool {
+		for _, v := range val.ListValue {
+			if v.StringValue == s {
+				return true
+			}
+		}
+		return false
+	}
+
+	falseValue := &bpparser.Value{
+		Type:      bpparser.Bool,
+		BoolValue: false,
+	}
+
+	trueValue := &bpparser.Value{
+		Type:      bpparser.Bool,
+		BoolValue: true,
+	}
+
+	if inList("windows") {
+		err = setVariable(file, appendVariable, "target.windows", "enabled", trueValue, true)
+	}
+
+	if !inList("linux") && err == nil {
+		err = setVariable(file, appendVariable, "target.linux", "enabled", falseValue, true)
+	}
+
+	if !inList("darwin") && err == nil {
+		err = setVariable(file, appendVariable, "target.darwin", "enabled", falseValue, true)
+	}
+
+	return err
+}
+
 var deleteProperties = map[string]struct{}{
 	"LOCAL_CPP_EXTENSION": struct{}{},
 }
diff --git a/cc/arm64_device.go b/cc/arm64_device.go
index 8d773ed..157b273 100644
--- a/cc/arm64_device.go
+++ b/cc/arm64_device.go
@@ -61,6 +61,7 @@
 		"-Wl,-maarch64linux",
 		"-Wl,--hash-style=gnu",
 		"-Wl,--fix-cortex-a53-843419",
+		"-Wl,--no-undefined-version",
 
 		// Disable transitive dependency library symbol resolving.
 		"-Wl,--allow-shlib-undefined",
diff --git a/cc/arm_device.go b/cc/arm_device.go
index 5c91a82..d44787d 100644
--- a/cc/arm_device.go
+++ b/cc/arm_device.go
@@ -66,6 +66,7 @@
 		"-Wl,--fatal-warnings",
 		"-Wl,--icf=safe",
 		"-Wl,--hash-style=gnu",
+		"-Wl,--no-undefined-version",
 	}
 
 	armArmCflags = []string{
diff --git a/cc/cc.go b/cc/cc.go
index b497d66..312e42b 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -581,6 +581,10 @@
 				fmt.Sprintf("${%sGlobalCflags}", ctx.HostOrDevice()))
 		}
 
+		if Bool(ctx.AConfig().ProductVariables.Brillo) {
+			flags.GlobalFlags = append(flags.GlobalFlags, "-D__BRILLO__")
+		}
+
 		if ctx.Device() {
 			if Bool(c.Properties.Rtti) {
 				flags.CppFlags = append(flags.CppFlags, "-frtti")
@@ -736,7 +740,7 @@
 				return
 			}
 		})
-		if !found {
+		if !found && !inList(n, ctx.GetMissingDependencies()) {
 			ctx.ModuleErrorf("unsatisified dependency on %q", n)
 		}
 	}
diff --git a/cc/mips64_device.go b/cc/mips64_device.go
index 44ca4f8..a0e39a6 100644
--- a/cc/mips64_device.go
+++ b/cc/mips64_device.go
@@ -66,6 +66,7 @@
 		"-Wl,--warn-shared-textrel",
 		"-Wl,--fatal-warnings",
 		"-Wl,--allow-shlib-undefined",
+		"-Wl,--no-undefined-version",
 	}
 
 	mips64ArchVariantCflags = map[string][]string{
diff --git a/cc/mips_device.go b/cc/mips_device.go
index ba6b81a..f668f22 100644
--- a/cc/mips_device.go
+++ b/cc/mips_device.go
@@ -61,6 +61,7 @@
 		"-Wl,--warn-shared-textrel",
 		"-Wl,--fatal-warnings",
 		"-Wl,--allow-shlib-undefined",
+		"-Wl,--no-undefined-version",
 	}
 
 	mipsToolchainLdflags = []string{
diff --git a/cc/x86_64_device.go b/cc/x86_64_device.go
index b4f96b9..9c79d87 100644
--- a/cc/x86_64_device.go
+++ b/cc/x86_64_device.go
@@ -62,6 +62,7 @@
 		"-Wl,--fatal-warnings",
 		"-Wl,--gc-sections",
 		"-Wl,--hash-style=gnu",
+		"-Wl,--no-undefined-version",
 	}
 
 	x86_64ArchVariantCflags = map[string][]string{
diff --git a/cc/x86_device.go b/cc/x86_device.go
index a44b293..e5a8f66 100644
--- a/cc/x86_device.go
+++ b/cc/x86_device.go
@@ -57,6 +57,7 @@
 		"-Wl,--fatal-warnings",
 		"-Wl,--gc-sections",
 		"-Wl,--hash-style=gnu",
+		"-Wl,--no-undefined-version",
 	}
 
 	x86ArchVariantCflags = map[string][]string{
diff --git a/cc/x86_linux_host.go b/cc/x86_linux_host.go
index a3c50d1..3bf9671 100644
--- a/cc/x86_linux_host.go
+++ b/cc/x86_linux_host.go
@@ -37,6 +37,7 @@
 		"-Wl,-z,noexecstack",
 		"-Wl,-z,relro",
 		"-Wl,-z,now",
+		"-Wl,--no-undefined-version",
 	}
 
 	// Extended cflags
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 254f922..1bb8fcd 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -44,5 +44,7 @@
 	// Temporary hack
 	//ctx.SetIgnoreUnknownModuleTypes(true)
 
+	ctx.SetAllowMissingDependencies(configuration.AllowMissingDependencies())
+
 	bootstrap.Main(ctx, configuration, configuration.ConfigFileName, configuration.ProductVariablesFileName)
 }
diff --git a/common/androidmk.go b/common/androidmk.go
index 06aa30c..9bd3a19 100644
--- a/common/androidmk.go
+++ b/common/androidmk.go
@@ -55,6 +55,10 @@
 	hasBPDir := make(map[string]bool)
 	bpDirs := []string{}
 
+	if !ctx.Config().(Config).EmbeddedInMake() {
+		return
+	}
+
 	ctx.SetNinjaBuildDir(pctx, filepath.Join(ctx.Config().(Config).buildDir, ".."))
 
 	ctx.VisitAllModules(func(module blueprint.Module) {
@@ -95,6 +99,8 @@
 		}
 	}
 
+	sort.Sort(AndroidModulesByName{androidMkModulesList, ctx})
+
 	transMk := PathForOutput(ctx, "Android.mk")
 	if ctx.Failed() {
 		return
@@ -181,6 +187,10 @@
 		amod := m.(AndroidModule).base()
 		data := provider.AndroidMk()
 
+		if !amod.Enabled() {
+			return
+		}
+
 		arch := amod.commonProperties.CompileArch
 
 		prefix := ""
diff --git a/common/arch.go b/common/arch.go
index 37f7c38..1d7d0de 100644
--- a/common/arch.go
+++ b/common/arch.go
@@ -581,7 +581,7 @@
 	return m, allProperties
 }
 
-var dashToUnderscoreReplacer = strings.NewReplacer("-", "_")
+var variantReplacer = strings.NewReplacer("-", "_", ".", "_")
 
 func (a *AndroidModuleBase) appendProperties(ctx AndroidBottomUpMutatorContext,
 	dst, src interface{}, field, srcPrefix string) interface{} {
@@ -660,7 +660,7 @@
 		//         key: value,
 		//     },
 		// },
-		v := dashToUnderscoreReplacer.Replace(arch.ArchVariant)
+		v := variantReplacer.Replace(arch.ArchVariant)
 		if v != "" {
 			field := proptools.FieldNameForProperty(v)
 			prefix := "arch." + t.Name + "." + v
@@ -673,7 +673,7 @@
 		//         key: value,
 		//     },
 		// },
-		c := dashToUnderscoreReplacer.Replace(arch.CpuVariant)
+		c := variantReplacer.Replace(arch.CpuVariant)
 		if c != "" {
 			field := proptools.FieldNameForProperty(c)
 			prefix := "arch." + t.Name + "." + c
diff --git a/common/config.go b/common/config.go
index 7f6ee65..74e0660 100644
--- a/common/config.go
+++ b/common/config.go
@@ -22,8 +22,12 @@
 	"runtime"
 	"strings"
 	"sync"
+
+	"github.com/google/blueprint/proptools"
 )
 
+var Bool = proptools.Bool
+
 // The configuration file name
 const configFileName = "soong.config"
 const productVariablesFileName = "soong.variables"
@@ -58,6 +62,8 @@
 	envLock   sync.Mutex
 	envDeps   map[string]string
 	envFrozen bool
+
+	inMake bool
 }
 
 type jsonConfigurable interface {
@@ -163,6 +169,11 @@
 		return Config{}, err
 	}
 
+	inMakeFile := filepath.Join(buildDir, ".soong.in_make")
+	if _, err := os.Stat(inMakeFile); err == nil {
+		config.inMake = true
+	}
+
 	hostArches, deviceArches, err := decodeArchProductVariables(config.ProductVariables)
 	if err != nil {
 		return Config{}, err
@@ -228,6 +239,10 @@
 	return c.envDeps
 }
 
+func (c *config) EmbeddedInMake() bool {
+	return c.inMake
+}
+
 // DeviceName returns the name of the current device target
 // TODO: take an AndroidModuleContext to select the device name for multi-device builds
 func (c *config) DeviceName() string {
@@ -276,3 +291,7 @@
 func (c *config) DefaultAppCertificate(ctx PathContext) SourcePath {
 	return c.DefaultAppCertificateDir(ctx).Join(ctx, "testkey")
 }
+
+func (c *config) AllowMissingDependencies() bool {
+	return Bool(c.ProductVariables.Unbundled_build)
+}
diff --git a/common/defs.go b/common/defs.go
index 9e185e4..1250068 100644
--- a/common/defs.go
+++ b/common/defs.go
@@ -59,6 +59,13 @@
 			Description: "symlink $out",
 		},
 		"fromPath")
+
+	ErrorRule = pctx.StaticRule("Error",
+		blueprint.RuleParams{
+			Command:     `echo "$error" && false`,
+			Description: "error building $out",
+		},
+		"error")
 )
 
 func init() {
diff --git a/common/module.go b/common/module.go
index 36710c5..a2b2efa 100644
--- a/common/module.go
+++ b/common/module.go
@@ -15,7 +15,9 @@
 package common
 
 import (
+	"fmt"
 	"path/filepath"
+	"strings"
 
 	"android/soong"
 	"android/soong/glob"
@@ -313,6 +315,7 @@
 			Rule:      blueprint.Phony,
 			Outputs:   []string{name},
 			Implicits: allInstalledFiles.Strings(),
+			Optional:  ctx.Config().(Config).EmbeddedInMake(),
 		})
 		deps = append(deps, name)
 		a.installTarget = name
@@ -331,9 +334,14 @@
 	}
 
 	if len(deps) > 0 {
+		suffix := ""
+		if ctx.Config().(Config).EmbeddedInMake() {
+			suffix = "-soong"
+		}
+
 		ctx.Build(pctx, blueprint.BuildParams{
 			Rule:      blueprint.Phony,
-			Outputs:   []string{ctx.ModuleName() + "-soong"},
+			Outputs:   []string{ctx.ModuleName() + suffix},
 			Implicits: deps,
 			Optional:  true,
 		})
@@ -357,6 +365,7 @@
 		androidBaseContextImpl: a.androidBaseContextFactory(ctx),
 		installDeps:            a.computeInstallDeps(ctx),
 		installFiles:           a.installFiles,
+		missingDeps:            ctx.GetMissingDependencies(),
 	}
 
 	if !a.Enabled() {
@@ -391,9 +400,28 @@
 	installDeps     Paths
 	installFiles    Paths
 	checkbuildFiles Paths
+	missingDeps     []string
+}
+
+func (a *androidModuleContext) ninjaError(outputs []string, err error) {
+	a.ModuleContext.Build(pctx, blueprint.BuildParams{
+		Rule:     ErrorRule,
+		Outputs:  outputs,
+		Optional: true,
+		Args: map[string]string{
+			"error": err.Error(),
+		},
+	})
+	return
 }
 
 func (a *androidModuleContext) Build(pctx blueprint.PackageContext, params blueprint.BuildParams) {
+	if a.missingDeps != nil {
+		a.ninjaError(params.Outputs, fmt.Errorf("module %s missing dependencies: %s\n",
+			a.ModuleName(), strings.Join(a.missingDeps, ", ")))
+		return
+	}
+
 	params.Optional = true
 	a.ModuleContext.Build(pctx, params)
 }
@@ -419,9 +447,19 @@
 		bparams.Implicits = append(bparams.Implicits, params.Implicit.String())
 	}
 
+	if a.missingDeps != nil {
+		a.ninjaError(bparams.Outputs, fmt.Errorf("module %s missing dependencies: %s\n",
+			a.ModuleName(), strings.Join(a.missingDeps, ", ")))
+		return
+	}
+
 	a.ModuleContext.Build(pctx, bparams)
 }
 
+func (a *androidModuleContext) GetMissingDependencies() []string {
+	return a.missingDeps
+}
+
 func (a *androidBaseContextImpl) Arch() Arch {
 	return a.arch
 }
@@ -466,7 +504,7 @@
 		Output:    fullInstallPath,
 		Input:     srcPath,
 		OrderOnly: Paths(deps),
-		Default:   true,
+		Default:   !a.AConfig().EmbeddedInMake(),
 	})
 
 	a.installFiles = append(a.installFiles, fullInstallPath)
@@ -568,10 +606,15 @@
 		}
 	})
 
+	suffix := ""
+	if ctx.Config().(Config).EmbeddedInMake() {
+		suffix = "-soong"
+	}
+
 	// Create a top-level checkbuild target that depends on all modules
 	ctx.Build(pctx, blueprint.BuildParams{
 		Rule:      blueprint.Phony,
-		Outputs:   []string{"checkbuild-soong"},
+		Outputs:   []string{"checkbuild" + suffix},
 		Implicits: checkbuildDeps,
 		Optional:  true,
 	})
@@ -583,7 +626,30 @@
 			Rule:      blueprint.Phony,
 			Outputs:   []string{filepath.Join("mm", dir)},
 			Implicits: dirModules[dir],
-			Optional:  true,
+			// HACK: checkbuild should be an optional build, but force it
+			// enabled for now in standalone builds
+			Optional: ctx.Config().(Config).EmbeddedInMake(),
 		})
 	}
 }
+
+type AndroidModulesByName struct {
+	slice []AndroidModule
+	ctx   interface {
+		ModuleName(blueprint.Module) string
+		ModuleSubDir(blueprint.Module) string
+	}
+}
+
+func (s AndroidModulesByName) Len() int { return len(s.slice) }
+func (s AndroidModulesByName) Less(i, j int) bool {
+	mi, mj := s.slice[i], s.slice[j]
+	ni, nj := s.ctx.ModuleName(mi), s.ctx.ModuleName(mj)
+
+	if ni != nj {
+		return ni < nj
+	} else {
+		return s.ctx.ModuleSubDir(mi) < s.ctx.ModuleSubDir(mj)
+	}
+}
+func (s AndroidModulesByName) Swap(i, j int) { s.slice[i], s.slice[j] = s.slice[j], s.slice[i] }
diff --git a/common/variable.go b/common/variable.go
index 2c0e0a6..fa40661 100644
--- a/common/variable.go
+++ b/common/variable.go
@@ -82,6 +82,7 @@
 	CrossHostSecondaryArch *string `json:",omitempty"`
 
 	Unbundled_build *bool `json:",omitempty"`
+	Brillo          *bool `json:",omitempty"`
 }
 
 func boolPtr(v bool) *bool {
@@ -162,9 +163,7 @@
 func (a *AndroidModuleBase) setVariableProperties(ctx AndroidBottomUpMutatorContext,
 	prefix string, productVariablePropertyValue reflect.Value, variableValue interface{}) {
 
-	if variableValue != nil {
-		printfIntoProperties(productVariablePropertyValue, variableValue)
-	}
+	printfIntoProperties(productVariablePropertyValue, variableValue)
 
 	err := proptools.AppendMatchingProperties(a.generalProperties,
 		productVariablePropertyValue.Addr().Interface(), nil)
@@ -180,6 +179,13 @@
 func printfIntoProperties(productVariablePropertyValue reflect.Value, variableValue interface{}) {
 	for i := 0; i < productVariablePropertyValue.NumField(); i++ {
 		propertyValue := productVariablePropertyValue.Field(i)
+		kind := propertyValue.Kind()
+		if kind == reflect.Ptr {
+			if propertyValue.IsNil() {
+				continue
+			}
+			propertyValue = propertyValue.Elem()
+		}
 		switch propertyValue.Kind() {
 		case reflect.String:
 			printfIntoProperty(propertyValue, variableValue)
@@ -187,6 +193,8 @@
 			for j := 0; j < propertyValue.Len(); j++ {
 				printfIntoProperty(propertyValue.Index(j), variableValue)
 			}
+		case reflect.Bool:
+			// Nothing
 		case reflect.Struct:
 			printfIntoProperties(propertyValue, variableValue)
 		default:
diff --git a/genrule/genrule.go b/genrule/genrule.go
index b554357..8291d5b 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -86,9 +86,9 @@
 	if g, ok := ctx.Module().(*generator); ok {
 		if g.properties.Tool != "" {
 			ctx.AddFarVariationDependencies([]blueprint.Variation{
-					{"host_or_device", common.Host.String()},
-					{"host_type", common.CurrentHostType().String()},
-				}, g.properties.Tool)
+				{"host_or_device", common.Host.String()},
+				{"host_type", common.CurrentHostType().String()},
+			}, g.properties.Tool)
 		}
 	}
 }