Support cross-compiling Windows binaries on Linux

This defines another mutator between HostOrDevice and Arch that will
expand host modules into a module for each host type
(Darwin/Linux/Windows) that is currently being built.

Change-Id: I4c8ac6b616c229f6bd45ad8a35902652fb6a4fff
diff --git a/Android.bp b/Android.bp
index 4d1d701..9a7beb8 100644
--- a/Android.bp
+++ b/Android.bp
@@ -130,6 +130,7 @@
 
         "cc/x86_darwin_host.go",
         "cc/x86_linux_host.go",
+        "cc/x86_windows_host.go",
     ],
     testSrcs: [
         "cc/cc_test.go",
diff --git a/cc/arm64_device.go b/cc/arm64_device.go
index 4acb218..9d58a80 100644
--- a/cc/arm64_device.go
+++ b/cc/arm64_device.go
@@ -155,5 +155,5 @@
 }
 
 func init() {
-	registerToolchainFactory(common.Device, common.Arm64, arm64ToolchainFactory)
+	registerDeviceToolchainFactory(common.Arm64, arm64ToolchainFactory)
 }
diff --git a/cc/arm_device.go b/cc/arm_device.go
index 746de2e..2d6d38c 100644
--- a/cc/arm_device.go
+++ b/cc/arm_device.go
@@ -362,5 +362,5 @@
 }
 
 func init() {
-	registerToolchainFactory(common.Device, common.Arm, armToolchainFactory)
+	registerDeviceToolchainFactory(common.Arm, armToolchainFactory)
 }
diff --git a/cc/builder.go b/cc/builder.go
index e3b9983..64437d2 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -33,7 +33,6 @@
 
 const (
 	objectExtension        = ".o"
-	sharedLibraryExtension = ".so"
 	staticLibraryExtension = ".a"
 )
 
@@ -310,7 +309,7 @@
 	var libFlagsList []string
 
 	if len(wholeStaticLibs) > 0 {
-		if ctx.Host() && runtime.GOOS == "darwin" {
+		if ctx.Host() && ctx.Darwin() {
 			libFlagsList = append(libFlagsList, common.JoinWithPrefix(wholeStaticLibs, "-force_load "))
 		} else {
 			libFlagsList = append(libFlagsList, "-Wl,--whole-archive ")
@@ -334,11 +333,11 @@
 		if !strings.HasPrefix(file, "lib") {
 			panic("shared library " + lib + " does not start with lib")
 		}
-		if !strings.HasSuffix(file, sharedLibraryExtension) {
-			panic("shared library " + lib + " does not end with " + sharedLibraryExtension)
+		if !strings.HasSuffix(file, flags.toolchain.ShlibSuffix()) {
+			panic("shared library " + lib + " does not end with " + flags.toolchain.ShlibSuffix())
 		}
 		libFlagsList = append(libFlagsList,
-			"-l"+strings.TrimSuffix(strings.TrimPrefix(file, "lib"), sharedLibraryExtension))
+			"-l"+strings.TrimSuffix(strings.TrimPrefix(file, "lib"), flags.toolchain.ShlibSuffix()))
 		ldDirs = append(ldDirs, dir)
 	}
 
diff --git a/cc/cc.go b/cc/cc.go
index b1bc069..00a0908 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -21,7 +21,6 @@
 import (
 	"fmt"
 	"path/filepath"
-	"runtime"
 	"strings"
 
 	"github.com/google/blueprint"
@@ -82,7 +81,6 @@
 		"-Wno-unused",
 		"-Winit-self",
 		"-Wpointer-arith",
-		"-fdiagnostics-color",
 		"-fdebug-prefix-map=/proc/self/cwd=",
 
 		// COMMON_RELEASE_CFLAGS
@@ -91,6 +89,8 @@
 	}
 
 	deviceGlobalCflags = []string{
+		"-fdiagnostics-color",
+
 		// TARGET_ERROR_FLAGS
 		"-Werror=return-type",
 		"-Werror=non-virtual-dtor",
@@ -407,9 +407,10 @@
 func (c *CCBase) findToolchain(ctx common.AndroidModuleContext) Toolchain {
 	arch := ctx.Arch()
 	hod := ctx.HostOrDevice()
-	factory := toolchainFactories[hod][arch.ArchType]
+	ht := ctx.HostType()
+	factory := toolchainFactories[hod][ht][arch.ArchType]
 	if factory == nil {
-		ctx.ModuleErrorf("Toolchain not found for %s arch %q", hod.String(), arch.String())
+		ctx.ModuleErrorf("Toolchain not found for %s %s arch %q", hod.String(), ht.String(), arch.String())
 		return nil
 	}
 	return factory(arch)
@@ -512,6 +513,10 @@
 		}
 	}
 
+	if !toolchain.ClangSupported() {
+		flags.Clang = false
+	}
+
 	instructionSet := c.Properties.Instruction_set
 	instructionSetFlags, err := toolchain.InstructionSetFlags(instructionSet)
 	if flags.Clang {
@@ -826,33 +831,52 @@
 		}
 	}
 
-	switch c.Properties.Stl {
-	case "libc++", "libc++_static",
-		"libstdc++":
-		return c.Properties.Stl
-	case "none":
-		return ""
-	case "":
-		if c.static() {
-			return "libc++_static"
-		} else {
-			return "libc++" // TODO: mingw needs libstdc++
+	if ctx.HostType() == common.Windows {
+		switch c.Properties.Stl {
+		case "libc++", "libc++_static", "libstdc++", "":
+			// libc++ is not supported on mingw
+			return "libstdc++"
+		case "none":
+			return ""
+		default:
+			ctx.ModuleErrorf("stl: %q is not a supported STL", c.Properties.Stl)
+			return ""
 		}
-	default:
-		ctx.ModuleErrorf("stl: %q is not a supported STL", c.Properties.Stl)
-		return ""
+	} else {
+		switch c.Properties.Stl {
+		case "libc++", "libc++_static",
+			"libstdc++":
+			return c.Properties.Stl
+		case "none":
+			return ""
+		case "":
+			if c.static() {
+				return "libc++_static"
+			} else {
+				return "libc++"
+			}
+		default:
+			ctx.ModuleErrorf("stl: %q is not a supported STL", c.Properties.Stl)
+			return ""
+		}
 	}
 }
 
-var hostDynamicGccLibs, hostStaticGccLibs []string
+var hostDynamicGccLibs, hostStaticGccLibs map[common.HostType][]string
 
 func init() {
-	if runtime.GOOS == "darwin" {
-		hostDynamicGccLibs = []string{"-lc", "-lSystem"}
-		hostStaticGccLibs = []string{"NO_STATIC_HOST_BINARIES_ON_DARWIN"}
-	} else {
-		hostDynamicGccLibs = []string{"-lgcc_s", "-lgcc", "-lc", "-lgcc_s", "-lgcc"}
-		hostStaticGccLibs = []string{"-Wl,--start-group", "-lgcc", "-lgcc_eh", "-lc", "-Wl,--end-group"}
+	hostDynamicGccLibs = map[common.HostType][]string{
+		common.Linux:  []string{"-lgcc_s", "-lgcc", "-lc", "-lgcc_s", "-lgcc"},
+		common.Darwin: []string{"-lc", "-lSystem"},
+		common.Windows: []string{"-lmsvcr110", "-lmingw32", "-lgcc", "-lmoldname",
+			"-lmingwex", "-lmsvcrt", "-ladvapi32", "-lshell32", "-luser32",
+			"-lkernel32", "-lmingw32", "-lgcc", "-lmoldname", "-lmingwex",
+			"-lmsvcrt"},
+	}
+	hostStaticGccLibs = map[common.HostType][]string{
+		common.Linux:   []string{"-Wl,--start-group", "-lgcc", "-lgcc_eh", "-lc", "-Wl,--end-group"},
+		common.Darwin:  []string{"NO_STATIC_HOST_BINARIES_ON_DARWIN"},
+		common.Windows: []string{"NO_STATIC_HOST_BINARIES_ON_WINDOWS"},
 	}
 }
 
@@ -870,9 +894,9 @@
 			flags.LdFlags = append(flags.LdFlags, "-nodefaultlibs")
 			flags.LdFlags = append(flags.LdFlags, "-lm", "-lpthread")
 			if c.staticBinary() {
-				flags.LdFlags = append(flags.LdFlags, hostStaticGccLibs...)
+				flags.LdFlags = append(flags.LdFlags, hostStaticGccLibs[ctx.HostType()]...)
 			} else {
-				flags.LdFlags = append(flags.LdFlags, hostDynamicGccLibs...)
+				flags.LdFlags = append(flags.LdFlags, hostDynamicGccLibs[ctx.HostType()]...)
 			}
 		} else {
 			if ctx.Arch().ArchType == common.Arm {
@@ -900,9 +924,9 @@
 			flags.CppFlags = append(flags.CppFlags, "-nostdinc++")
 			flags.LdFlags = append(flags.LdFlags, "-nodefaultlibs")
 			if c.staticBinary() {
-				flags.LdFlags = append(flags.LdFlags, hostStaticGccLibs...)
+				flags.LdFlags = append(flags.LdFlags, hostStaticGccLibs[ctx.HostType()]...)
 			} else {
-				flags.LdFlags = append(flags.LdFlags, hostDynamicGccLibs...)
+				flags.LdFlags = append(flags.LdFlags, hostDynamicGccLibs[ctx.HostType()]...)
 			}
 		}
 	default:
@@ -1148,7 +1172,12 @@
 func (c *CCLibrary) flags(ctx common.AndroidModuleContext, flags CCFlags) CCFlags {
 	flags = c.CCLinked.flags(ctx, flags)
 
-	flags.CFlags = append(flags.CFlags, "-fPIC")
+	// MinGW spits out warnings about -fPIC even for -fpie?!) being ignored because
+	// all code is position independent, and then those warnings get promoted to
+	// errors.
+	if ctx.HostType() != common.Windows {
+		flags.CFlags = append(flags.CFlags, "-fPIC")
+	}
 
 	if c.static() {
 		flags.CFlags = append(flags.CFlags, c.LibraryProperties.Static.Cflags...)
@@ -1172,13 +1201,13 @@
 				"-dynamiclib",
 				"-single_module",
 				//"-read_only_relocs suppress",
-				"-install_name @rpath/"+libName+sharedLibraryExtension,
+				"-install_name @rpath/"+libName+flags.Toolchain.ShlibSuffix(),
 			)
 		} else {
 			flags.LdFlags = append(flags.LdFlags,
 				"-Wl,--gc-sections",
 				sharedFlag,
-				"-Wl,-soname,"+libName+sharedLibraryExtension,
+				"-Wl,-soname,"+libName+flags.Toolchain.ShlibSuffix(),
 			)
 		}
 	}
@@ -1224,7 +1253,7 @@
 
 	objFiles = append(objFiles, objFilesShared...)
 
-	outputFile := filepath.Join(common.ModuleOutDir(ctx), ctx.ModuleName()+sharedLibraryExtension)
+	outputFile := filepath.Join(common.ModuleOutDir(ctx), ctx.ModuleName()+flags.Toolchain.ShlibSuffix())
 
 	var linkerDeps []string
 
@@ -1448,7 +1477,19 @@
 func (c *CCBinary) flags(ctx common.AndroidModuleContext, flags CCFlags) CCFlags {
 	flags = c.CCLinked.flags(ctx, flags)
 
-	flags.CFlags = append(flags.CFlags, "-fpie")
+	if ctx.Host() {
+		flags.LdFlags = append(flags.LdFlags, "-pie")
+		if ctx.HostType() == common.Windows {
+			flags.LdFlags = append(flags.LdFlags, "-Wl,-e_mainCRTStartup")
+		}
+	}
+
+	// MinGW spits out warnings about -fPIC even for -fpie?!) being ignored because
+	// all code is position independent, and then those warnings get promoted to
+	// errors.
+	if ctx.HostType() != common.Windows {
+		flags.CFlags = append(flags.CFlags, "-fpie")
+	}
 
 	if ctx.Device() {
 		if Bool(c.BinaryProperties.Static_executable) {
@@ -1495,7 +1536,7 @@
 			"from static libs or set static_executable: true")
 	}
 
-	outputFile := filepath.Join(common.ModuleOutDir(ctx), c.getStem(ctx))
+	outputFile := filepath.Join(common.ModuleOutDir(ctx), c.getStem(ctx)+flags.Toolchain.ExecutableSuffix())
 	c.out = outputFile
 	if c.BinaryProperties.Prefix_symbols != "" {
 		afterPrefixSymbols := outputFile
@@ -1843,7 +1884,7 @@
 	includeDirs := pathtools.PrefixPaths(c.Properties.Export_include_dirs, common.ModuleSrcDir(ctx))
 	c.exportFlags = []string{common.JoinWithPrefix(includeDirs, "-isystem ")}
 
-	c.out = ndkPrebuiltModuleToPath(ctx, flags.Toolchain, sharedLibraryExtension,
+	c.out = ndkPrebuiltModuleToPath(ctx, flags.Toolchain, flags.Toolchain.ShlibSuffix(),
 		c.Properties.Sdk_version)
 }
 
@@ -1911,7 +1952,7 @@
 	c.exportFlags = []string{includeDirsToFlags(includeDirs)}
 
 	libName := strings.TrimPrefix(ctx.ModuleName(), "ndk_")
-	libExt := sharedLibraryExtension
+	libExt := flags.Toolchain.ShlibSuffix()
 	if c.LibraryProperties.BuildStatic {
 		libExt = staticLibraryExtension
 	}
diff --git a/cc/mips64_device.go b/cc/mips64_device.go
index d792d00..e0b6a89 100644
--- a/cc/mips64_device.go
+++ b/cc/mips64_device.go
@@ -195,5 +195,5 @@
 }
 
 func init() {
-	registerToolchainFactory(common.Device, common.Mips64, mips64ToolchainFactory)
+	registerDeviceToolchainFactory(common.Mips64, mips64ToolchainFactory)
 }
diff --git a/cc/mips_device.go b/cc/mips_device.go
index 52bc1ec..c3372fe 100644
--- a/cc/mips_device.go
+++ b/cc/mips_device.go
@@ -227,5 +227,5 @@
 }
 
 func init() {
-	registerToolchainFactory(common.Device, common.Mips, mipsToolchainFactory)
+	registerDeviceToolchainFactory(common.Mips, mipsToolchainFactory)
 }
diff --git a/cc/toolchain.go b/cc/toolchain.go
index 71a8979..5e4d02f 100644
--- a/cc/toolchain.go
+++ b/cc/toolchain.go
@@ -22,15 +22,23 @@
 
 type toolchainFactory func(arch common.Arch) Toolchain
 
-var toolchainFactories = map[common.HostOrDevice]map[common.ArchType]toolchainFactory{
-	common.Host:   make(map[common.ArchType]toolchainFactory),
-	common.Device: make(map[common.ArchType]toolchainFactory),
+var toolchainFactories = map[common.HostOrDevice]map[common.HostType]map[common.ArchType]toolchainFactory{
+	common.Host: map[common.HostType]map[common.ArchType]toolchainFactory{
+		common.Linux:   make(map[common.ArchType]toolchainFactory),
+		common.Darwin:  make(map[common.ArchType]toolchainFactory),
+		common.Windows: make(map[common.ArchType]toolchainFactory),
+	},
+	common.Device: map[common.HostType]map[common.ArchType]toolchainFactory{
+		common.NoHostType: make(map[common.ArchType]toolchainFactory),
+	},
 }
 
-func registerToolchainFactory(hod common.HostOrDevice, arch common.ArchType,
-	factory toolchainFactory) {
+func registerDeviceToolchainFactory(arch common.ArchType, factory toolchainFactory) {
+	toolchainFactories[common.Device][common.NoHostType][arch] = factory
+}
 
-	toolchainFactories[hod][arch] = factory
+func registerHostToolchainFactory(ht common.HostType, arch common.ArchType, factory toolchainFactory) {
+	toolchainFactories[common.Host][ht][arch] = factory
 }
 
 type Toolchain interface {
@@ -47,6 +55,7 @@
 	IncludeFlags() string
 	InstructionSetFlags(string) (string, error)
 
+	ClangSupported() bool
 	ClangTriple() string
 	ToolchainClangCflags() string
 	ClangCflags() string
@@ -55,6 +64,9 @@
 	ClangInstructionSetFlags(string) (string, error)
 
 	Is64Bit() bool
+
+	ShlibSuffix() string
+	ExecutableSuffix() string
 }
 
 type toolchainBase struct {
@@ -86,6 +98,18 @@
 	return ""
 }
 
+func (toolchainBase) ClangSupported() bool {
+	return true
+}
+
+func (toolchainBase) ShlibSuffix() string {
+	return ".so"
+}
+
+func (toolchainBase) ExecutableSuffix() string {
+	return ""
+}
+
 type toolchain64Bit struct {
 	toolchainBase
 }
diff --git a/cc/x86_64_device.go b/cc/x86_64_device.go
index bd68ca5..728442c 100644
--- a/cc/x86_64_device.go
+++ b/cc/x86_64_device.go
@@ -256,5 +256,5 @@
 }
 
 func init() {
-	registerToolchainFactory(common.Device, common.X86_64, x86_64ToolchainFactory)
+	registerDeviceToolchainFactory(common.X86_64, x86_64ToolchainFactory)
 }
diff --git a/cc/x86_darwin_host.go b/cc/x86_darwin_host.go
index 4195dae..9ca03ba 100644
--- a/cc/x86_darwin_host.go
+++ b/cc/x86_darwin_host.go
@@ -1,7 +1,6 @@
 package cc
 
 import (
-	"runtime"
 	"strings"
 
 	"android/soong/common"
@@ -12,6 +11,8 @@
 		"-fno-exceptions", // from build/core/combo/select.mk
 		"-Wno-multichar",  // from build/core/combo/select.mk
 
+		"-fdiagnostics-color",
+
 		"-fPIC",
 		"-funwind-tables",
 
@@ -195,6 +196,10 @@
 	return "${darwinClangLdflags} ${darwinX8664ClangLdflags}"
 }
 
+func (t *toolchainDarwin) ShlibSuffix() string {
+	return ".dylib"
+}
+
 var toolchainDarwinX86Singleton Toolchain = &toolchainDarwinX86{}
 var toolchainDarwinX8664Singleton Toolchain = &toolchainDarwinX8664{}
 
@@ -207,8 +212,6 @@
 }
 
 func init() {
-	if runtime.GOOS == "darwin" {
-		registerToolchainFactory(common.Host, common.X86, darwinX86ToolchainFactory)
-		registerToolchainFactory(common.Host, common.X86_64, darwinX8664ToolchainFactory)
-	}
+	registerHostToolchainFactory(common.Darwin, common.X86, darwinX86ToolchainFactory)
+	registerHostToolchainFactory(common.Darwin, common.X86_64, darwinX8664ToolchainFactory)
 }
diff --git a/cc/x86_device.go b/cc/x86_device.go
index df0c0ff..8543240 100644
--- a/cc/x86_device.go
+++ b/cc/x86_device.go
@@ -258,5 +258,5 @@
 }
 
 func init() {
-	registerToolchainFactory(common.Device, common.X86, x86ToolchainFactory)
+	registerDeviceToolchainFactory(common.X86, x86ToolchainFactory)
 }
diff --git a/cc/x86_linux_host.go b/cc/x86_linux_host.go
index f544476..09a0803 100644
--- a/cc/x86_linux_host.go
+++ b/cc/x86_linux_host.go
@@ -1,7 +1,6 @@
 package cc
 
 import (
-	"runtime"
 	"strings"
 
 	"android/soong/common"
@@ -12,6 +11,8 @@
 		"-fno-exceptions", // from build/core/combo/select.mk
 		"-Wno-multichar",  // from build/core/combo/select.mk
 
+		"-fdiagnostics-color",
+
 		"-Wa,--noexecstack",
 
 		"-fPIC",
@@ -233,8 +234,6 @@
 }
 
 func init() {
-	if runtime.GOOS == "linux" {
-		registerToolchainFactory(common.Host, common.X86, linuxX86ToolchainFactory)
-		registerToolchainFactory(common.Host, common.X86_64, linuxX8664ToolchainFactory)
-	}
+	registerHostToolchainFactory(common.Linux, common.X86, linuxX86ToolchainFactory)
+	registerHostToolchainFactory(common.Linux, common.X86_64, linuxX8664ToolchainFactory)
 }
diff --git a/cc/x86_windows_host.go b/cc/x86_windows_host.go
new file mode 100644
index 0000000..70ce74d
--- /dev/null
+++ b/cc/x86_windows_host.go
@@ -0,0 +1,150 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cc
+
+import (
+	"strings"
+
+	"android/soong/common"
+)
+
+var (
+	windowsCflags = []string{
+		"-fno-exceptions", // from build/core/combo/select.mk
+		"-Wno-multichar",  // from build/core/combo/select.mk
+
+		"-DUSE_MINGW",
+		"-DWIN32_LEAN_AND_MEAN",
+		"-Wno-unused-parameter",
+		"-m32",
+
+		// Workaround differences in inttypes.h between host and target.
+		//See bug 12708004.
+		"-D__STDC_FORMAT_MACROS",
+		"-D__STDC_CONSTANT_MACROS",
+
+		// Use C99-compliant printf functions (%zd).
+		"-D__USE_MINGW_ANSI_STDIO=1",
+		// Admit to using >= Win2K. Both are needed because of <_mingw.h>.
+		"-D_WIN32_WINNT=0x0500",
+		"-DWINVER=0x0500",
+		// Get 64-bit off_t and related functions.
+		"-D_FILE_OFFSET_BITS=64",
+
+		// HOST_RELEASE_CFLAGS
+		"-O2", // from build/core/combo/select.mk
+		"-g",  // from build/core/combo/select.mk
+		"-fno-strict-aliasing", // from build/core/combo/select.mk
+	}
+
+	windowsIncludeFlags = []string{
+		"-I${windowsGccRoot}/${windowsGccTriple}/include",
+		"-I${windowsGccRoot}/lib/gcc/${windowsGccTriple}/4.8.3/include",
+	}
+
+	windowsLdflags = []string{
+		"-m32",
+		"-L${windowsGccRoot}/${windowsGccTriple}",
+		"--enable-stdcall-fixup",
+	}
+)
+
+func init() {
+	pctx.StaticVariable("windowsGccVersion", "4.8")
+
+	pctx.StaticVariable("windowsGccRoot",
+		"${SrcDir}/prebuilts/gcc/${HostPrebuiltTag}/host/x86_64-w64-mingw32-${windowsGccVersion}")
+
+	pctx.StaticVariable("windowsGccTriple", "x86_64-w64-mingw32")
+
+	pctx.StaticVariable("windowsCflags", strings.Join(windowsCflags, " "))
+	pctx.StaticVariable("windowsLdflags", strings.Join(windowsLdflags, " "))
+}
+
+type toolchainWindows struct {
+	toolchain32Bit
+
+	cFlags, ldFlags string
+}
+
+func (t *toolchainWindows) Name() string {
+	return "x86"
+}
+
+func (t *toolchainWindows) GccRoot() string {
+	return "${windowsGccRoot}"
+}
+
+func (t *toolchainWindows) GccTriple() string {
+	return "${windowsGccTriple}"
+}
+
+func (t *toolchainWindows) GccVersion() string {
+	return "${windowsGccVersion}"
+}
+
+func (t *toolchainWindows) Cflags() string {
+	return "${windowsCflags}"
+}
+
+func (t *toolchainWindows) Cppflags() string {
+	return ""
+}
+
+func (t *toolchainWindows) Ldflags() string {
+	return "${windowsLdflags}"
+}
+
+func (t *toolchainWindows) IncludeFlags() string {
+	return ""
+}
+
+func (t *toolchainWindows) ClangSupported() bool {
+	return false
+}
+
+func (t *toolchainWindows) ClangTriple() string {
+	panic("Clang is not supported under mingw")
+}
+
+func (t *toolchainWindows) ClangCflags() string {
+	panic("Clang is not supported under mingw")
+}
+
+func (t *toolchainWindows) ClangCppflags() string {
+	panic("Clang is not supported under mingw")
+}
+
+func (t *toolchainWindows) ClangLdflags() string {
+	panic("Clang is not supported under mingw")
+}
+
+func (t *toolchainWindows) ShlibSuffix() string {
+	return ".dll"
+}
+
+func (t *toolchainWindows) ExecutableSuffix() string {
+	return ".exe"
+}
+
+var toolchainWindowsSingleton Toolchain = &toolchainWindows{}
+
+func windowsToolchainFactory(arch common.Arch) Toolchain {
+	return toolchainWindowsSingleton
+}
+
+func init() {
+	registerHostToolchainFactory(common.Windows, common.X86, windowsToolchainFactory)
+}
diff --git a/common/arch.go b/common/arch.go
index 8ac52e6..4cddc00 100644
--- a/common/arch.go
+++ b/common/arch.go
@@ -29,6 +29,7 @@
 	RegisterTopDownMutator("defaults", defaultsMutator)
 
 	RegisterBottomUpMutator("host_or_device", HostOrDeviceMutator)
+	RegisterBottomUpMutator("host_type", HostTypeMutator)
 	RegisterBottomUpMutator("arch", ArchMutator)
 }
 
@@ -261,6 +262,8 @@
 		Darwin_x86_64 interface{} `blueprint:"filter(android:\"arch_variant\")"`
 		// Properties for module variants being built to run on windows hosts
 		Windows interface{} `blueprint:"filter(android:\"arch_variant\")"`
+		// Properties for module variants being built to run on windows x86 hosts
+		Windows_x86 interface{} `blueprint:"filter(android:\"arch_variant\")"`
 		// Properties for module variants being built to run on linux or darwin hosts
 		Not_windows interface{} `blueprint:"filter(android:\"arch_variant\")"`
 	}
@@ -383,6 +386,52 @@
 	Host:   "host",
 }
 
+type HostType int
+
+const (
+	NoHostType HostType = iota
+	Linux
+	Darwin
+	Windows
+)
+
+func CurrentHostType() HostType {
+	switch runtime.GOOS {
+	case "linux":
+		return Linux
+	case "darwin":
+		return Darwin
+	default:
+		panic(fmt.Sprintf("unsupported OS: %s", runtime.GOOS))
+	}
+}
+
+func (ht HostType) String() string {
+	switch ht {
+	case Linux:
+		return "linux"
+	case Darwin:
+		return "darwin"
+	case Windows:
+		return "windows"
+	default:
+		panic(fmt.Sprintf("unexpected HostType value %d", ht))
+	}
+}
+
+func (ht HostType) Field() string {
+	switch ht {
+	case Linux:
+		return "Linux"
+	case Darwin:
+		return "Darwin"
+	case Windows:
+		return "Windows"
+	default:
+		panic(fmt.Sprintf("unexpected HostType value %d", ht))
+	}
+}
+
 var (
 	commonArch = Arch{
 		ArchType: Common,
@@ -421,6 +470,34 @@
 	}
 }
 
+func HostTypeMutator(mctx AndroidBottomUpMutatorContext) {
+	var module AndroidModule
+	var ok bool
+	if module, ok = mctx.Module().(AndroidModule); !ok {
+		return
+	}
+
+	if !module.base().HostSupported() || !module.base().HostOrDevice().Host() {
+		return
+	}
+
+	buildTypes, err := decodeHostTypesProductVariables(mctx.Config().(Config).ProductVariables)
+	if err != nil {
+		mctx.ModuleErrorf("%s", err.Error())
+		return
+	}
+
+	typeNames := []string{}
+	for _, ht := range buildTypes {
+		typeNames = append(typeNames, ht.String())
+	}
+
+	modules := mctx.CreateVariations(typeNames...)
+	for i, m := range modules {
+		m.(AndroidModule).base().SetHostType(buildTypes[i])
+	}
+}
+
 func ArchMutator(mctx AndroidBottomUpMutatorContext) {
 	var module AndroidModule
 	var ok bool
@@ -437,7 +514,7 @@
 	multilib := module.base().commonProperties.Compile_multilib
 
 	if module.base().HostSupported() && module.base().HostOrDevice().Host() {
-		hostModuleArches, err := decodeMultilib(multilib, hostArches)
+		hostModuleArches, err := decodeMultilib(multilib, hostArches[module.base().HostType()])
 		if err != nil {
 			mctx.ModuleErrorf("%s", err.Error())
 		}
@@ -560,6 +637,7 @@
 func (a *AndroidModuleBase) setArchProperties(ctx AndroidBottomUpMutatorContext) {
 	arch := a.commonProperties.CompileArch
 	hod := a.commonProperties.CompileHostOrDevice
+	ht := a.commonProperties.CompileHostType
 
 	if arch.ArchType == Common {
 		return
@@ -654,30 +732,21 @@
 		//         key: value,
 		//     },
 		// },
-		var osList = []struct {
-			goos  string
-			field string
-		}{
-			{"darwin", "Darwin"},
-			{"linux", "Linux"},
-			{"windows", "Windows"},
-		}
-
 		if hod.Host() {
-			for _, v := range osList {
-				if v.goos == runtime.GOOS {
-					field := v.field
-					prefix := "target." + v.goos
-					a.appendProperties(ctx, genProps, archProps.Target, field, prefix)
-					t := arch.ArchType
-					field = v.field + "_" + t.Name
-					prefix = "target." + v.goos + "_" + t.Name
-					a.appendProperties(ctx, genProps, archProps.Target, field, prefix)
-				}
-			}
-			field := "Not_windows"
-			prefix := "target.not_windows"
+			field := ht.Field()
+			prefix := "target." + ht.String()
 			a.appendProperties(ctx, genProps, archProps.Target, field, prefix)
+
+			t := arch.ArchType
+			field = ht.Field() + "_" + t.Name
+			prefix = "target." + ht.String() + "_" + t.Name
+			a.appendProperties(ctx, genProps, archProps.Target, field, prefix)
+
+			if ht != Windows {
+				field := "Not_windows"
+				prefix := "target.not_windows"
+				a.appendProperties(ctx, genProps, archProps.Target, field, prefix)
+			}
 		}
 
 		// Handle 64-bit device properties in the form:
@@ -742,8 +811,24 @@
 	}
 }
 
+// Get a list of HostTypes from the product variables
+func decodeHostTypesProductVariables(variables productVariables) ([]HostType, error) {
+	ret := []HostType{CurrentHostType()}
+
+	if variables.CrossHost != nil && *variables.CrossHost != "" {
+		switch *variables.CrossHost {
+		case "windows":
+			ret = append(ret, Windows)
+		default:
+			return nil, fmt.Errorf("Unsupported secondary host: %s", *variables.CrossHost)
+		}
+	}
+
+	return ret, nil
+}
+
 // Convert the arch product variables into a list of host and device Arch structs
-func decodeArchProductVariables(variables productVariables) ([]Arch, []Arch, error) {
+func decodeArchProductVariables(variables productVariables) (map[HostType][]Arch, []Arch, error) {
 	if variables.HostArch == nil {
 		return nil, nil, fmt.Errorf("No host primary architecture set")
 	}
@@ -763,6 +848,38 @@
 		hostArches = append(hostArches, hostSecondaryArch)
 	}
 
+	hostTypeArches := map[HostType][]Arch{
+		CurrentHostType(): hostArches,
+	}
+
+	if variables.CrossHost != nil && *variables.CrossHost != "" {
+		if variables.CrossHostArch == nil || *variables.CrossHostArch == "" {
+			return nil, nil, fmt.Errorf("No cross-host primary architecture set")
+		}
+
+		crossHostArch, err := decodeArch(*variables.CrossHostArch, nil, nil, nil)
+		if err != nil {
+			return nil, nil, err
+		}
+
+		crossHostArches := []Arch{crossHostArch}
+
+		if variables.CrossHostSecondaryArch != nil && *variables.CrossHostSecondaryArch != "" {
+			crossHostSecondaryArch, err := decodeArch(*variables.CrossHostSecondaryArch, nil, nil, nil)
+			if err != nil {
+				return nil, nil, err
+			}
+			crossHostArches = append(crossHostArches, crossHostSecondaryArch)
+		}
+
+		switch *variables.CrossHost {
+		case "windows":
+			hostTypeArches[Windows] = crossHostArches
+		default:
+			return nil, nil, fmt.Errorf("Unsupported cross-host: %s", *variables.CrossHost)
+		}
+	}
+
 	if variables.DeviceArch == nil {
 		return nil, nil, fmt.Errorf("No device primary architecture set")
 	}
@@ -785,7 +902,7 @@
 		deviceArches = append(deviceArches, deviceSecondaryArch)
 	}
 
-	return hostArches, deviceArches, nil
+	return hostTypeArches, deviceArches, nil
 }
 
 // Convert a set of strings from product variables into a single Arch struct
diff --git a/common/module.go b/common/module.go
index b64342f..7bb21a2 100644
--- a/common/module.go
+++ b/common/module.go
@@ -17,7 +17,6 @@
 import (
 	"android/soong"
 	"path/filepath"
-	"runtime"
 
 	"android/soong/glob"
 
@@ -37,6 +36,7 @@
 type androidBaseContext interface {
 	Arch() Arch
 	HostOrDevice() HostOrDevice
+	HostType() HostType
 	Host() bool
 	Device() bool
 	Darwin() bool
@@ -88,6 +88,9 @@
 	// Set by HostOrDeviceMutator
 	CompileHostOrDevice HostOrDevice `blueprint:"mutated"`
 
+	// Set by HostTypeMutator
+	CompileHostType HostType `blueprint:"mutated"`
+
 	// Set by ArchMutator
 	CompileArch Arch `blueprint:"mutated"`
 
@@ -208,6 +211,10 @@
 	a.commonProperties.CompileHostOrDevice = hod
 }
 
+func (a *AndroidModuleBase) SetHostType(ht HostType) {
+	a.commonProperties.CompileHostType = ht
+}
+
 func (a *AndroidModuleBase) SetArch(arch Arch) {
 	a.commonProperties.CompileArch = arch
 }
@@ -216,6 +223,10 @@
 	return a.commonProperties.CompileHostOrDevice
 }
 
+func (a *AndroidModuleBase) HostType() HostType {
+	return a.commonProperties.CompileHostType
+}
+
 func (a *AndroidModuleBase) HostSupported() bool {
 	return a.commonProperties.HostOrDeviceSupported == HostSupported ||
 		a.commonProperties.HostOrDeviceSupported == HostAndDeviceSupported &&
@@ -229,6 +240,12 @@
 }
 
 func (a *AndroidModuleBase) Disabled() bool {
+	if a.commonProperties.CompileHostOrDevice == Host &&
+		a.commonProperties.CompileHostType == Windows &&
+		a.commonProperties.Disabled == nil {
+
+		return true
+	}
 	return proptools.Bool(a.commonProperties.Disabled)
 }
 
@@ -308,6 +325,7 @@
 	return androidBaseContextImpl{
 		arch:   a.commonProperties.CompileArch,
 		hod:    a.commonProperties.CompileHostOrDevice,
+		ht:     a.commonProperties.CompileHostType,
 		config: ctx.Config().(Config),
 	}
 }
@@ -320,7 +338,7 @@
 		installFiles:           a.installFiles,
 	}
 
-	if proptools.Bool(a.commonProperties.Disabled) {
+	if a.Disabled() {
 		return
 	}
 
@@ -341,6 +359,7 @@
 type androidBaseContextImpl struct {
 	arch   Arch
 	hod    HostOrDevice
+	ht     HostType
 	debug  bool
 	config Config
 }
@@ -366,6 +385,10 @@
 	return a.hod
 }
 
+func (a *androidBaseContextImpl) HostType() HostType {
+	return a.ht
+}
+
 func (a *androidBaseContextImpl) Host() bool {
 	return a.hod.Host()
 }
@@ -375,7 +398,7 @@
 }
 
 func (a *androidBaseContextImpl) Darwin() bool {
-	return a.hod.Host() && runtime.GOOS == "darwin"
+	return a.hod.Host() && a.ht == Darwin
 }
 
 func (a *androidBaseContextImpl) Debug() bool {
@@ -396,7 +419,12 @@
 		fullInstallPath = filepath.Join(config.DeviceOut(), "system",
 			installPath, name)
 	} else {
-		fullInstallPath = filepath.Join(config.HostOut(), installPath, name)
+		// TODO
+		if a.ht == Windows {
+			fullInstallPath = filepath.Join(config.BuildDir(), "host", "windows-x86", installPath, name)
+		} else {
+			fullInstallPath = filepath.Join(config.HostOut(), installPath, name)
+		}
 	}
 
 	deps = append(deps, a.installDeps...)
diff --git a/common/variable.go b/common/variable.go
index 9a5998f..5b9092f 100644
--- a/common/variable.go
+++ b/common/variable.go
@@ -17,6 +17,7 @@
 import (
 	"fmt"
 	"reflect"
+	"runtime"
 	"strings"
 
 	"github.com/google/blueprint/proptools"
@@ -69,6 +70,10 @@
 
 	HostArch          *string `json:",omitempty"`
 	HostSecondaryArch *string `json:",omitempty"`
+
+	CrossHost              *string `json:",omitempty"`
+	CrossHostArch          *string `json:",omitempty"`
+	CrossHostSecondaryArch *string `json:",omitempty"`
 }
 
 func boolPtr(v bool) *bool {
@@ -99,6 +104,11 @@
 		DeviceSecondaryCpuVariant:  stringPtr("denver"),
 		DeviceSecondaryAbi:         &[]string{"armeabi-v7a"},
 	}
+
+	if runtime.GOOS == "linux" {
+		v.CrossHost = stringPtr("windows")
+		v.CrossHostArch = stringPtr("x86")
+	}
 }
 
 func variableMutator(mctx AndroidBottomUpMutatorContext) {
diff --git a/genrule/genrule.go b/genrule/genrule.go
index fb0dafc..76b4f16 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -88,8 +88,10 @@
 func genruleDepsMutator(ctx common.AndroidBottomUpMutatorContext) {
 	if g, ok := ctx.Module().(*generator); ok {
 		if g.properties.Tool != "" {
-			ctx.AddFarVariationDependencies([]blueprint.Variation{{"hostordevice", common.Host.String()}},
-				g.properties.Tool)
+			ctx.AddFarVariationDependencies([]blueprint.Variation{
+					{"host_or_device", common.Host.String()},
+					{"host_type", common.CurrentHostType().String()},
+				}, g.properties.Tool)
 		}
 	}
 }