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/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