diff --git a/Blueprints b/Blueprints index 0a66b431c..c9480c7b5 100644 --- a/Blueprints +++ b/Blueprints @@ -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", ], } diff --git a/build.ninja.in b/build.ninja.in index aac0cc622..50ee8108f 100644 --- a/build.ninja.in +++ b/build.ninja.in @@ -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 | $ diff --git a/cc/builder.go b/cc/builder.go index e7c08b78a..218c73b24 100644 --- a/cc/builder.go +++ b/cc/builder.go @@ -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,9 +291,13 @@ func TransformObjToDynamicBinary(ctx common.AndroidModuleContext, var libFlagsList []string if len(wholeStaticLibs) > 0 { - libFlagsList = append(libFlagsList, "-Wl,--whole-archive ") - libFlagsList = append(libFlagsList, wholeStaticLibs...) - libFlagsList = append(libFlagsList, "-Wl,--no-whole-archive ") + 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 +} diff --git a/cc/cc.go b/cc/cc.go index 3ab8a4764..8032fe3a7 100644 --- a/cc/cc.go +++ b/cc/cc.go @@ -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 ( - hostDynamicGccLibs = []string{"-lgcc_s", "-lgcc", "-lc", "-lgcc_s", "-lgcc"} - hostStaticGccLibs = []string{"-Wl,--start-group", "-lgcc", "-lgcc_eh", "-lc", "-Wl,--end-group"} -) +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,11 +1056,20 @@ func (c *CCLibrary) flags(ctx common.AndroidModuleContext, flags CCFlags) CCFlag flags.LdFlags = append(flags.LdFlags, "-nostdlib") } - flags.LdFlags = append(flags.LdFlags, - "-Wl,--gc-sections", - sharedFlag, - "-Wl,-soname,"+libName+sharedLibraryExtension, - ) + 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) - TransformObjToStaticLib(ctx, objFiles, ccFlagsToBuilderFlags(flags), outputFile) + 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 diff --git a/cc/cc_test.go b/cc/cc_test.go index 3bf0c658b..ec7da90bd 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -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) + } + } +} diff --git a/cc/x86_darwin_host.go b/cc/x86_darwin_host.go new file mode 100644 index 000000000..bed977d41 --- /dev/null +++ b/cc/x86_darwin_host.go @@ -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) + } +} diff --git a/common/module.go b/common/module.go index bafb583f2..d93378854 100644 --- a/common/module.go +++ b/common/module.go @@ -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 }