Add support for building on Darwin hosts

Add toolchain and build rules for building on Darwin.

Change-Id: I78e21f4051b2941182121b28c9ddfa24396ada41
This commit is contained in:
Colin Cross 2015-04-30 16:36:18 -07:00
parent 5e1efb5812
commit 0af4b8468b
7 changed files with 467 additions and 31 deletions

View File

@ -111,6 +111,7 @@ bootstrap_go_package {
"cc/arm_device.go",
"cc/arm64_device.go",
"cc/x86_darwin_host.go",
"cc/x86_linux_host.go",
],
}

View File

@ -53,7 +53,7 @@ rule g.bootstrap.link
# Variant:
# Type: bootstrap_go_binary
# Factory: github.com/google/blueprint/bootstrap.newGoBinaryModule
# Defined: build/soong/Blueprints:185:1
# Defined: build/soong/Blueprints:186:1
build .bootstrap/androidbp/obj/androidbp.a: g.bootstrap.gc $
${g.bootstrap.srcDir}/build/soong/androidbp/cmd/androidbp.go $
@ -77,7 +77,7 @@ default .bootstrap/bin/androidbp
# Variant:
# Type: bootstrap_go_binary
# Factory: github.com/google/blueprint/bootstrap.newGoBinaryModule
# Defined: build/soong/Blueprints:161:1
# Defined: build/soong/Blueprints:162:1
build .bootstrap/androidmk/obj/androidmk.a: g.bootstrap.gc $
${g.bootstrap.srcDir}/build/soong/androidmk/cmd/androidmk/android.go $
@ -103,7 +103,7 @@ default .bootstrap/bin/androidmk
# Variant:
# Type: bootstrap_go_package
# Factory: github.com/google/blueprint/bootstrap.newGoPackageModule
# Defined: build/soong/Blueprints:174:1
# Defined: build/soong/Blueprints:175:1
build .bootstrap/androidmk-parser/pkg/android/soong/androidmk/parser.a: $
g.bootstrap.gc $
@ -345,6 +345,7 @@ build .bootstrap/soong-cc/pkg/android/soong/cc.a: g.bootstrap.gc $
${g.bootstrap.srcDir}/build/soong/cc/util.go $
${g.bootstrap.srcDir}/build/soong/cc/arm_device.go $
${g.bootstrap.srcDir}/build/soong/cc/arm64_device.go $
${g.bootstrap.srcDir}/build/soong/cc/x86_darwin_host.go $
${g.bootstrap.srcDir}/build/soong/cc/x86_linux_host.go | $
${g.bootstrap.gcCmd} $
.bootstrap/blueprint-parser/pkg/github.com/google/blueprint/parser.a $
@ -408,7 +409,7 @@ default .bootstrap/soong-env/pkg/android/soong/env.a
# Variant:
# Type: bootstrap_go_package
# Factory: github.com/google/blueprint/bootstrap.newGoPackageModule
# Defined: build/soong/Blueprints:118:1
# Defined: build/soong/Blueprints:119:1
build .bootstrap/soong-genrule/pkg/android/soong/genrule.a: g.bootstrap.gc $
${g.bootstrap.srcDir}/build/soong/genrule/genrule.go | $
@ -446,7 +447,7 @@ default .bootstrap/soong-glob/pkg/android/soong/glob.a
# Variant:
# Type: bootstrap_go_package
# Factory: github.com/google/blueprint/bootstrap.newGoPackageModule
# Defined: build/soong/Blueprints:138:1
# Defined: build/soong/Blueprints:139:1
build .bootstrap/soong-java/pkg/android/soong/java.a: g.bootstrap.gc $
${g.bootstrap.srcDir}/build/soong/java/app_builder.go $
@ -559,7 +560,7 @@ default .bootstrap/bin/soong_glob
# Variant:
# Type: bootstrap_go_binary
# Factory: github.com/google/blueprint/bootstrap.newGoBinaryModule
# Defined: build/soong/Blueprints:131:1
# Defined: build/soong/Blueprints:132:1
build .bootstrap/soong_jar/obj/soong_jar.a: g.bootstrap.gc $
${g.bootstrap.srcDir}/build/soong/cmd/soong_jar/soong_jar.go | $

View File

@ -20,6 +20,9 @@ package cc
import (
"android/soong/common"
"fmt"
"runtime"
"strconv"
"path/filepath"
"strings"
@ -72,6 +75,20 @@ var (
},
"arCmd", "arFlags")
darwinAr = pctx.StaticRule("darwinAr",
blueprint.RuleParams{
Command: "rm -f ${out} && $arCmd $arFlags $out $in",
Description: "ar $out",
},
"arCmd", "arFlags")
darwinAppendAr = pctx.StaticRule("darwinAppendAr",
blueprint.RuleParams{
Command: "cp -f ${inAr} ${out}.tmp && $arCmd $arFlags ${out}.tmp $in && mv ${out}.tmp ${out}",
Description: "ar $out",
},
"arCmd", "arFlags", "inAr")
prefixSymbols = pctx.StaticRule("prefixSymbols",
blueprint.RuleParams{
Command: "$objcopyCmd --prefix-symbols=${prefix} ${in} ${out}",
@ -207,6 +224,56 @@ func TransformObjToStaticLib(ctx common.AndroidModuleContext, objFiles []string,
})
}
// Generate a rule for compiling multiple .o files to a static library (.a) on
// darwin. The darwin ar tool doesn't support @file for list files, and has a
// very small command line length limit, so we have to split the ar into multiple
// steps, each appending to the previous one.
func TransformDarwinObjToStaticLib(ctx common.AndroidModuleContext, objFiles []string,
flags builderFlags, outputFile string) {
arCmd := "ar"
arFlags := "cqs"
// ARG_MAX on darwin is 262144, use half that to be safe
objFilesLists, err := splitListForSize(objFiles, 131072)
if err != nil {
ctx.ModuleErrorf("%s", err.Error())
}
var in, out string
for i, l := range objFilesLists {
in = out
out = outputFile
if i != len(objFilesLists)-1 {
out += "." + strconv.Itoa(i)
}
if in == "" {
ctx.Build(pctx, blueprint.BuildParams{
Rule: darwinAr,
Outputs: []string{out},
Inputs: l,
Args: map[string]string{
"arFlags": arFlags,
"arCmd": arCmd,
},
})
} else {
ctx.Build(pctx, blueprint.BuildParams{
Rule: darwinAppendAr,
Outputs: []string{out},
Inputs: l,
Implicits: []string{in},
Args: map[string]string{
"arFlags": arFlags,
"arCmd": arCmd,
"inAr": in,
},
})
}
}
}
// Generate a rule for compiling multiple .o files, plus static libraries, whole static libraries,
// and shared libraires, to a shared library (.so) or dynamic executable
func TransformObjToDynamicBinary(ctx common.AndroidModuleContext,
@ -224,10 +291,14 @@ func TransformObjToDynamicBinary(ctx common.AndroidModuleContext,
var libFlagsList []string
if len(wholeStaticLibs) > 0 {
if ctx.Host() && runtime.GOOS == "darwin" {
libFlagsList = append(libFlagsList, common.JoinWithPrefix(wholeStaticLibs, "-force_load "))
} else {
libFlagsList = append(libFlagsList, "-Wl,--whole-archive ")
libFlagsList = append(libFlagsList, wholeStaticLibs...)
libFlagsList = append(libFlagsList, "-Wl,--no-whole-archive ")
}
}
libFlagsList = append(libFlagsList, staticLibs...)
@ -244,11 +315,11 @@ func TransformObjToDynamicBinary(ctx common.AndroidModuleContext,
ldDirs = append(ldDirs, dir)
}
if groupLate {
if groupLate && len(lateStaticLibs) > 0 {
libFlagsList = append(libFlagsList, "-Wl,--start-group")
}
libFlagsList = append(libFlagsList, lateStaticLibs...)
if groupLate {
if groupLate && len(lateStaticLibs) > 0 {
libFlagsList = append(libFlagsList, "-Wl,--end-group")
}
@ -335,3 +406,33 @@ func CopyGccLib(ctx common.AndroidModuleContext, libName string,
func gccCmd(toolchain Toolchain, cmd string) string {
return filepath.Join(toolchain.GccRoot(), "bin", toolchain.GccTriple()+"-"+cmd)
}
func splitListForSize(list []string, limit int) (lists [][]string, err error) {
var i int
start := 0
bytes := 0
for i = range list {
l := len(list[i])
if l > limit {
return nil, fmt.Errorf("list element greater than size limit (%d)", limit)
}
if bytes+l > limit {
lists = append(lists, list[start:i])
start = i
bytes = 0
}
bytes += l + 1 // count a space between each list element
}
lists = append(lists, list[start:])
totalLen := 0
for _, l := range lists {
totalLen += len(l)
}
if totalLen != len(list) {
panic(fmt.Errorf("Failed breaking up list, %d != %d", len(list), totalLen))
}
return lists, nil
}

View File

@ -21,6 +21,7 @@ package cc
import (
"fmt"
"path/filepath"
"runtime"
"strings"
"github.com/google/blueprint"
@ -456,16 +457,6 @@ func (c *CCBase) collectFlags(ctx common.AndroidModuleContext, toolchain Toolcha
flags.CFlags = append(flags.CFlags, target, gccPrefix)
flags.AsFlags = append(flags.AsFlags, target, gccPrefix)
flags.LdFlags = append(flags.LdFlags, target, gccPrefix)
if ctx.Host() {
gccToolchain := "--gcc-toolchain=" + toolchain.GccRoot()
sysroot := "--sysroot=" + filepath.Join(toolchain.GccRoot(), "sysroot")
// TODO: also need more -B, -L flags to make host builds hermetic
flags.CFlags = append(flags.CFlags, gccToolchain, sysroot)
flags.AsFlags = append(flags.AsFlags, gccToolchain, sysroot)
flags.LdFlags = append(flags.LdFlags, gccToolchain, sysroot)
}
}
if !c.Properties.No_default_compiler_flags {
@ -744,10 +735,17 @@ func (c *CCLinked) stl(ctx common.AndroidBaseContext) string {
}
}
var (
var hostDynamicGccLibs, hostStaticGccLibs []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"}
)
}
}
func (c *CCLinked) flags(ctx common.AndroidModuleContext, flags CCFlags) CCFlags {
stl := c.stl(ctx)
@ -1058,12 +1056,21 @@ func (c *CCLibrary) flags(ctx common.AndroidModuleContext, flags CCFlags) CCFlag
flags.LdFlags = append(flags.LdFlags, "-nostdlib")
}
if ctx.Darwin() {
flags.LdFlags = append(flags.LdFlags,
"-dynamiclib",
"-single_module",
//"-read_only_relocs suppress",
"-install_name @rpath/"+libName+sharedLibraryExtension,
)
} else {
flags.LdFlags = append(flags.LdFlags,
"-Wl,--gc-sections",
sharedFlag,
"-Wl,-soname,"+libName+sharedLibraryExtension,
)
}
}
return flags
}
@ -1080,7 +1087,11 @@ func (c *CCLibrary) compileStaticLibrary(ctx common.AndroidModuleContext,
outputFile := filepath.Join(common.ModuleOutDir(ctx), ctx.ModuleName()+staticLibraryExtension)
if ctx.Darwin() {
TransformDarwinObjToStaticLib(ctx, objFiles, ccFlagsToBuilderFlags(flags), outputFile)
} else {
TransformObjToStaticLib(ctx, objFiles, ccFlagsToBuilderFlags(flags), outputFile)
}
c.objFiles = objFiles
c.out = outputFile
@ -1302,6 +1313,9 @@ func CCBinaryFactory() (blueprint.Module, []interface{}) {
}
func (c *CCBinary) ModifyProperties(ctx common.AndroidBaseContext) {
if ctx.Darwin() {
c.BinaryProperties.Static_executable = false
}
if c.BinaryProperties.Static_executable {
c.dynamicProperties.VariantIsStaticBinary = true
}
@ -1342,6 +1356,8 @@ func (c *CCBinary) flags(ctx common.AndroidModuleContext, flags CCFlags) CCFlags
"-Wl,-z,nocopyreloc",
)
}
} else if ctx.Darwin() {
flags.LdFlags = append(flags.LdFlags, "-Wl,-headerpad_max_install_names")
}
return flags

View File

@ -54,3 +54,101 @@ func TestLastUniqueElements(t *testing.T) {
}
}
}
var (
str11 = "01234567891"
str10 = str11[:10]
str9 = str11[:9]
str5 = str11[:5]
str4 = str11[:4]
)
var splitListForSizeTestCases = []struct {
in []string
out [][]string
size int
}{
{
in: []string{str10},
out: [][]string{{str10}},
size: 10,
},
{
in: []string{str9},
out: [][]string{{str9}},
size: 10,
},
{
in: []string{str5},
out: [][]string{{str5}},
size: 10,
},
{
in: []string{str11},
out: nil,
size: 10,
},
{
in: []string{str10, str10},
out: [][]string{{str10}, {str10}},
size: 10,
},
{
in: []string{str9, str10},
out: [][]string{{str9}, {str10}},
size: 10,
},
{
in: []string{str10, str9},
out: [][]string{{str10}, {str9}},
size: 10,
},
{
in: []string{str5, str4},
out: [][]string{{str5, str4}},
size: 10,
},
{
in: []string{str5, str4, str5},
out: [][]string{{str5, str4}, {str5}},
size: 10,
},
{
in: []string{str5, str4, str5, str4},
out: [][]string{{str5, str4}, {str5, str4}},
size: 10,
},
{
in: []string{str5, str4, str5, str5},
out: [][]string{{str5, str4}, {str5}, {str5}},
size: 10,
},
{
in: []string{str5, str5, str5, str4},
out: [][]string{{str5}, {str5}, {str5, str4}},
size: 10,
},
{
in: []string{str9, str11},
out: nil,
size: 10,
},
{
in: []string{str11, str9},
out: nil,
size: 10,
},
}
func TestSplitListForSize(t *testing.T) {
for _, testCase := range splitListForSizeTestCases {
out, _ := splitListForSize(testCase.in, testCase.size)
if !reflect.DeepEqual(out, testCase.out) {
t.Errorf("incorrect output:")
t.Errorf(" input: %#v", testCase.in)
t.Errorf(" size: %d", testCase.size)
t.Errorf(" expected: %#v", testCase.out)
t.Errorf(" got: %#v", out)
}
}
}

213
cc/x86_darwin_host.go Normal file
View File

@ -0,0 +1,213 @@
package cc
import (
"runtime"
"strings"
"android/soong/common"
)
var (
darwinCflags = []string{
"-fno-exceptions", // from build/core/combo/select.mk
"-Wno-multichar", // from build/core/combo/select.mk
"-fPIC",
"-funwind-tables",
"-include ${SrcDir}/build/core/combo/include/arch/darwin-x86/AndroidConfig.h",
// Workaround differences in inttypes.h between host and target.
//See bug 12708004.
"-D__STDC_FORMAT_MACROS",
"-D__STDC_CONSTANT_MACROS",
// 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
"-isysroot ${macSdkRoot}",
"-mmacosx-version-min=10.9",
"-DMACOSX_DEPLOYMENT_TARGET=10.9",
}
darwinCppflags = []string{
"-isystem ${macSdkPath}/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1",
}
darwinLdflags = []string{
"-isysroot ${macSdkRoot}",
"-Wl,-syslibroot,${macSdkRoot}",
"-mmacosx-version-min=10.9",
}
// Extended cflags
darwinX86Cflags = []string{
"-m32",
}
darwinX8664Cflags = []string{
"-m64",
}
darwinX86Ldflags = []string{
"-m32",
"-Wl,-rpath,@loader_path/../lib",
}
darwinX8664Ldflags = []string{
"-m64",
"-Wl,-rpath,@loader_path/../lib64",
}
darwinClangCflags = append([]string{
"-integrated-as",
}, clangFilterUnknownCflags(darwinCflags)...)
darwinClangLdflags = clangFilterUnknownCflags(darwinLdflags)
darwinX86ClangLdflags = clangFilterUnknownCflags(darwinX86Ldflags)
darwinX8664ClangLdflags = clangFilterUnknownCflags(darwinX8664Ldflags)
darwinClangCppflags = clangFilterUnknownCflags(darwinCppflags)
)
func init() {
pctx.StaticVariable("macSdkPath", "/Applications/Xcode.app/Contents/Developer")
pctx.StaticVariable("macSdkRoot", "${macSdkPath}/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk")
pctx.StaticVariable("darwinGccVersion", "4.2.1")
pctx.StaticVariable("darwinGccRoot",
"${SrcDir}/prebuilts/gcc/${HostPrebuiltTag}/host/i686-apple-darwin-${darwinGccVersion}")
pctx.StaticVariable("darwinGccTriple", "i686-apple-darwin11")
pctx.StaticVariable("darwinCflags", strings.Join(darwinCflags, " "))
pctx.StaticVariable("darwinLdflags", strings.Join(darwinLdflags, " "))
pctx.StaticVariable("darwinCppflags", strings.Join(darwinCppflags, " "))
pctx.StaticVariable("darwinClangCflags", strings.Join(darwinClangCflags, " "))
pctx.StaticVariable("darwinClangLdflags", strings.Join(darwinClangLdflags, " "))
pctx.StaticVariable("darwinClangCppflags", strings.Join(darwinClangCppflags, " "))
// Extended cflags
pctx.StaticVariable("darwinX86Cflags", strings.Join(darwinX86Cflags, " "))
pctx.StaticVariable("darwinX8664Cflags", strings.Join(darwinX8664Cflags, " "))
pctx.StaticVariable("darwinX86Ldflags", strings.Join(darwinX86Ldflags, " "))
pctx.StaticVariable("darwinX8664Ldflags", strings.Join(darwinX8664Ldflags, " "))
pctx.StaticVariable("darwinX86ClangCflags",
strings.Join(clangFilterUnknownCflags(darwinX86Cflags), " "))
pctx.StaticVariable("darwinX8664ClangCflags",
strings.Join(clangFilterUnknownCflags(darwinX8664Cflags), " "))
pctx.StaticVariable("darwinX86ClangLdflags", strings.Join(darwinX86ClangLdflags, " "))
pctx.StaticVariable("darwinX8664ClangLdflags", strings.Join(darwinX8664ClangLdflags, " "))
}
type toolchainDarwin struct {
cFlags, ldFlags string
}
type toolchainDarwinX86 struct {
toolchain32Bit
toolchainDarwin
}
type toolchainDarwinX8664 struct {
toolchain64Bit
toolchainDarwin
}
func (t *toolchainDarwinX86) Name() string {
return "x86"
}
func (t *toolchainDarwinX8664) Name() string {
return "x86_64"
}
func (t *toolchainDarwin) GccRoot() string {
return "${darwinGccRoot}"
}
func (t *toolchainDarwin) GccTriple() string {
return "${darwinGccTriple}"
}
func (t *toolchainDarwin) GccVersion() string {
return "${darwinGccVersion}"
}
func (t *toolchainDarwin) Cflags() string {
return "${darwinCflags} ${darwinX86Cflags}"
}
func (t *toolchainDarwinX8664) Cflags() string {
return "${darwinCflags} ${darwinX8664Cflags}"
}
func (t *toolchainDarwin) Cppflags() string {
return "${darwinCppflags}"
}
func (t *toolchainDarwinX86) Ldflags() string {
return "${darwinLdflags} ${darwinX86Ldflags}"
}
func (t *toolchainDarwinX8664) Ldflags() string {
return "${darwinLdflags} ${darwinX8664Ldflags}"
}
func (t *toolchainDarwin) IncludeFlags() string {
return ""
}
func (t *toolchainDarwinX86) ClangTriple() string {
return "i686-darwin-gnu"
}
func (t *toolchainDarwinX86) ClangCflags() string {
return "${darwinClangCflags} ${darwinX86ClangCflags}"
}
func (t *toolchainDarwinX86) ClangCppflags() string {
return "${darwinClangCppflags}"
}
func (t *toolchainDarwinX8664) ClangTriple() string {
return "x86_64-darwin-gnu"
}
func (t *toolchainDarwinX8664) ClangCflags() string {
return "${darwinClangCflags} ${darwinX8664ClangCflags}"
}
func (t *toolchainDarwinX8664) ClangCppflags() string {
return "${darwinClangCppflags}"
}
func (t *toolchainDarwinX86) ClangLdflags() string {
return "${darwinClangLdflags} ${darwinX86ClangLdflags}"
}
func (t *toolchainDarwinX8664) ClangLdflags() string {
return "${darwinClangLdflags} ${darwinX8664ClangLdflags}"
}
var toolchainDarwinX86Singleton Toolchain = &toolchainDarwinX86{}
var toolchainDarwinX8664Singleton Toolchain = &toolchainDarwinX8664{}
func darwinX86ToolchainFactory(archVariant string, cpuVariant string) Toolchain {
return toolchainDarwinX86Singleton
}
func darwinX8664ToolchainFactory(archVariant string, cpuVariant string) Toolchain {
return toolchainDarwinX8664Singleton
}
func init() {
if runtime.GOOS == "darwin" {
registerToolchainFactory(common.Host, common.X86, darwinX86ToolchainFactory)
registerToolchainFactory(common.Host, common.X86_64, darwinX8664ToolchainFactory)
}
}

View File

@ -16,6 +16,7 @@ package common
import (
"path/filepath"
"runtime"
"github.com/google/blueprint"
)
@ -33,6 +34,7 @@ type androidBaseContext interface {
Arch() Arch
Host() bool
Device() bool
Darwin() bool
Debug() bool
AConfig() Config
}
@ -372,6 +374,10 @@ func (a *androidBaseContextImpl) Device() bool {
return a.arch.HostOrDevice.Device()
}
func (a *androidBaseContextImpl) Darwin() bool {
return a.arch.HostOrDevice.Host() && runtime.GOOS == "darwin"
}
func (a *androidBaseContextImpl) Debug() bool {
return a.debug
}