Add support for preferred arch symlinks

Add a symlink_preferred_arch property to binaries to allow compiling the
binary for multiple architectures and then creating a symlink to the
preferred archicture, for example dalvikvm32 and dalvikvm64, with
dalvikvm symlinked to dalvikvm64.

Test: mmma -j art/dalvikvm
Change-Id: Ied15f2be9d52c01006fe8ac207c175b78558eab1
diff --git a/android/config.go b/android/config.go
index 6c524e1..21a7233 100644
--- a/android/config.go
+++ b/android/config.go
@@ -75,6 +75,7 @@
 	envFrozen bool
 
 	inMake bool
+
 	OncePer
 }
 
@@ -332,6 +333,14 @@
 	return Bool(c.ProductVariables.Allow_missing_dependencies)
 }
 
+func (c *config) DevicePrefer32BitExecutables() bool {
+	return Bool(c.ProductVariables.DevicePrefer32BitExecutables)
+}
+
+func (c *config) HostPrefer32BitExecutables() bool {
+	return Bool(c.ProductVariables.HostPrefer32BitExecutables)
+}
+
 func (c *config) SkipDeviceInstall() bool {
 	return c.EmbeddedInMake() || Bool(c.Mega_device)
 }
diff --git a/android/module.go b/android/module.go
index fd37ca8..45afec1 100644
--- a/android/module.go
+++ b/android/module.go
@@ -63,6 +63,7 @@
 	Device() bool
 	Darwin() bool
 	Debug() bool
+	PrimaryArch() bool
 	AConfig() Config
 	DeviceConfig() DeviceConfig
 }
@@ -548,6 +549,10 @@
 	return a.debug
 }
 
+func (a *androidBaseContextImpl) PrimaryArch() bool {
+	return a.target.Arch.ArchType == a.config.Targets[a.target.Os.Class][0].Arch.ArchType
+}
+
 func (a *androidBaseContextImpl) AConfig() Config {
 	return a.config
 }
diff --git a/android/variable.go b/android/variable.go
index 531125d..be2407d 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -102,6 +102,9 @@
 	Schedboost                 *bool `json:",omitempty"`
 	Binder32bit                *bool `json:",omitempty"`
 
+	DevicePrefer32BitExecutables *bool `json:",omitempty"`
+	HostPrefer32BitExecutables   *bool `json:",omitempty"`
+
 	SanitizeHost   *[]string `json:",omitempty"`
 	SanitizeDevice *[]string `json:",omitempty"`
 }
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 283fe27..d4965d8 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -125,6 +125,7 @@
 }
 
 func (binary *binaryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+	ctx.subAndroidMk(ret, binary.baseInstaller)
 	ctx.subAndroidMk(ret, &binary.stripper)
 
 	ret.Class = "EXECUTABLES"
diff --git a/cc/binary.go b/cc/binary.go
index 2dbce66..38fc938 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -34,6 +34,9 @@
 
 	// if set, add an extra objcopy --prefix-symbols= step
 	Prefix_symbols string
+
+	// if set, install a symlink to the preferred architecture
+	Symlink_preferred_arch bool
 }
 
 func init() {
@@ -59,6 +62,7 @@
 
 type binaryDecorator struct {
 	*baseLinker
+	*baseInstaller
 	stripper
 
 	Properties BinaryLinkerProperties
@@ -137,11 +141,12 @@
 func NewBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) {
 	module := newModule(hod, android.MultilibFirst)
 	binary := &binaryDecorator{
-		baseLinker: NewBaseLinker(),
+		baseLinker:    NewBaseLinker(),
+		baseInstaller: NewBaseInstaller("bin", "", InstallInSystem),
 	}
 	module.compiler = NewBaseCompiler()
 	module.linker = binary
-	module.installer = NewBaseInstaller("bin", "", InstallInSystem)
+	module.installer = binary
 	return module, binary
 }
 
@@ -158,6 +163,22 @@
 			binary.Properties.Static_executable = nil
 		}
 	}
+
+	if binary.Properties.Symlink_preferred_arch {
+		if binary.Properties.Stem == "" && binary.Properties.Suffix == "" {
+			ctx.PropertyErrorf("symlink_preferred_arch", "must also specify stem or suffix")
+		}
+		var prefer bool
+		if ctx.Host() {
+			prefer = ctx.AConfig().HostPrefer32BitExecutables()
+		} else {
+			prefer = ctx.AConfig().DevicePrefer32BitExecutables()
+		}
+		if ctx.PrimaryArch() != prefer {
+			binary.baseInstaller.Properties.Symlinks = append(binary.baseInstaller.Properties.Symlinks,
+				ctx.ModuleName())
+		}
+	}
 }
 
 func (binary *binaryDecorator) static() bool {