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/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)
+}