Add support for building on Darwin hosts

Add toolchain and build rules for building on Darwin.

Change-Id: I78e21f4051b2941182121b28c9ddfa24396ada41
diff --git a/cc/builder.go b/cc/builder.go
index e7c08b7..218c73b 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -20,6 +20,9 @@
 
 import (
 	"android/soong/common"
+	"fmt"
+	"runtime"
+	"strconv"
 
 	"path/filepath"
 	"strings"
@@ -72,6 +75,20 @@
 		},
 		"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 @@
 	})
 }
 
+// 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 @@
 	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 @@
 		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 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
+}