Separate cc.go

Split cc.go into files per module type, plus files for the compiler,
linker, and installer stages.

Change-Id: Id44c03f42fcd180950ccd008d4de0c144ea3597b
diff --git a/cc/test.go b/cc/test.go
new file mode 100644
index 0000000..9eb4e21
--- /dev/null
+++ b/cc/test.go
@@ -0,0 +1,256 @@
+// Copyright 2016 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 (
+	"path/filepath"
+	"strings"
+
+	"github.com/google/blueprint"
+
+	"android/soong"
+	"android/soong/android"
+)
+
+type TestLinkerProperties struct {
+	// if set, build against the gtest library. Defaults to true.
+	Gtest bool
+
+	// Create a separate binary for each source file.  Useful when there is
+	// global state that can not be torn down and reset between each test suite.
+	Test_per_src *bool
+}
+
+func init() {
+	soong.RegisterModuleType("cc_test", testFactory)
+	soong.RegisterModuleType("cc_test_library", testLibraryFactory)
+	soong.RegisterModuleType("cc_benchmark", benchmarkFactory)
+	soong.RegisterModuleType("cc_test_host", testHostFactory)
+	soong.RegisterModuleType("cc_benchmark_host", benchmarkHostFactory)
+}
+
+// Module factory for tests
+func testFactory() (blueprint.Module, []interface{}) {
+	module := NewTest(android.HostAndDeviceSupported)
+	return module.Init()
+}
+
+// Module factory for test libraries
+func testLibraryFactory() (blueprint.Module, []interface{}) {
+	module := NewTestLibrary(android.HostAndDeviceSupported)
+	return module.Init()
+}
+
+// Module factory for benchmarks
+func benchmarkFactory() (blueprint.Module, []interface{}) {
+	module := NewBenchmark(android.HostAndDeviceSupported)
+	return module.Init()
+}
+
+// Module factory for host tests
+func testHostFactory() (blueprint.Module, []interface{}) {
+	module := NewTest(android.HostSupported)
+	return module.Init()
+}
+
+// Module factory for host benchmarks
+func benchmarkHostFactory() (blueprint.Module, []interface{}) {
+	module := NewBenchmark(android.HostSupported)
+	return module.Init()
+}
+
+func testPerSrcMutator(mctx android.BottomUpMutatorContext) {
+	if m, ok := mctx.Module().(*Module); ok {
+		if test, ok := m.linker.(*testBinaryLinker); ok {
+			if Bool(test.testLinker.Properties.Test_per_src) {
+				testNames := make([]string, len(m.compiler.(*baseCompiler).Properties.Srcs))
+				for i, src := range m.compiler.(*baseCompiler).Properties.Srcs {
+					testNames[i] = strings.TrimSuffix(filepath.Base(src), filepath.Ext(src))
+				}
+				tests := mctx.CreateLocalVariations(testNames...)
+				for i, src := range m.compiler.(*baseCompiler).Properties.Srcs {
+					tests[i].(*Module).compiler.(*baseCompiler).Properties.Srcs = []string{src}
+					tests[i].(*Module).linker.(*testBinaryLinker).binaryLinker.Properties.Stem = testNames[i]
+				}
+			}
+		}
+	}
+}
+
+type testLinker struct {
+	Properties TestLinkerProperties
+}
+
+func (test *testLinker) flags(ctx ModuleContext, flags Flags) Flags {
+	if !test.Properties.Gtest {
+		return flags
+	}
+
+	flags.CFlags = append(flags.CFlags, "-DGTEST_HAS_STD_STRING")
+	if ctx.Host() {
+		flags.CFlags = append(flags.CFlags, "-O0", "-g")
+
+		switch ctx.Os() {
+		case android.Windows:
+			flags.CFlags = append(flags.CFlags, "-DGTEST_OS_WINDOWS")
+		case android.Linux:
+			flags.CFlags = append(flags.CFlags, "-DGTEST_OS_LINUX")
+			flags.LdFlags = append(flags.LdFlags, "-lpthread")
+		case android.Darwin:
+			flags.CFlags = append(flags.CFlags, "-DGTEST_OS_MAC")
+			flags.LdFlags = append(flags.LdFlags, "-lpthread")
+		}
+	} else {
+		flags.CFlags = append(flags.CFlags, "-DGTEST_OS_LINUX_ANDROID")
+	}
+
+	return flags
+}
+
+func (test *testLinker) deps(ctx BaseModuleContext, deps Deps) Deps {
+	if test.Properties.Gtest {
+		if ctx.sdk() && ctx.Device() {
+			switch ctx.selectedStl() {
+			case "ndk_libc++_shared", "ndk_libc++_static":
+				deps.StaticLibs = append(deps.StaticLibs, "libgtest_main_ndk_libcxx", "libgtest_ndk_libcxx")
+			case "ndk_libgnustl_static":
+				deps.StaticLibs = append(deps.StaticLibs, "libgtest_main_ndk_gnustl", "libgtest_ndk_gnustl")
+			default:
+				deps.StaticLibs = append(deps.StaticLibs, "libgtest_main_ndk", "libgtest_ndk")
+			}
+		} else {
+			deps.StaticLibs = append(deps.StaticLibs, "libgtest_main", "libgtest")
+		}
+	}
+	return deps
+}
+
+type testBinaryLinker struct {
+	testLinker
+	binaryLinker
+}
+
+func (test *testBinaryLinker) begin(ctx BaseModuleContext) {
+	test.binaryLinker.begin(ctx)
+	runpath := "../../lib"
+	if ctx.toolchain().Is64Bit() {
+		runpath += "64"
+	}
+	test.dynamicProperties.RunPaths = append([]string{runpath}, test.dynamicProperties.RunPaths...)
+}
+
+func (test *testBinaryLinker) props() []interface{} {
+	return append(test.binaryLinker.props(), &test.testLinker.Properties)
+}
+
+func (test *testBinaryLinker) flags(ctx ModuleContext, flags Flags) Flags {
+	flags = test.binaryLinker.flags(ctx, flags)
+	flags = test.testLinker.flags(ctx, flags)
+	return flags
+}
+
+func (test *testBinaryLinker) deps(ctx BaseModuleContext, deps Deps) Deps {
+	deps = test.testLinker.deps(ctx, deps)
+	deps = test.binaryLinker.deps(ctx, deps)
+	return deps
+}
+
+type testLibraryLinker struct {
+	testLinker
+	*libraryLinker
+}
+
+func (test *testLibraryLinker) props() []interface{} {
+	return append(test.libraryLinker.props(), &test.testLinker.Properties)
+}
+
+func (test *testLibraryLinker) flags(ctx ModuleContext, flags Flags) Flags {
+	flags = test.libraryLinker.flags(ctx, flags)
+	flags = test.testLinker.flags(ctx, flags)
+	return flags
+}
+
+func (test *testLibraryLinker) deps(ctx BaseModuleContext, deps Deps) Deps {
+	deps = test.testLinker.deps(ctx, deps)
+	deps = test.libraryLinker.deps(ctx, deps)
+	return deps
+}
+
+type testInstaller struct {
+	baseInstaller
+}
+
+func (installer *testInstaller) install(ctx ModuleContext, file android.Path) {
+	installer.dir = filepath.Join(installer.dir, ctx.ModuleName())
+	installer.dir64 = filepath.Join(installer.dir64, ctx.ModuleName())
+	installer.baseInstaller.install(ctx, file)
+}
+
+func NewTest(hod android.HostOrDeviceSupported) *Module {
+	module := newModule(hod, android.MultilibBoth)
+	module.compiler = &baseCompiler{}
+	linker := &testBinaryLinker{}
+	linker.testLinker.Properties.Gtest = true
+	module.linker = linker
+	module.installer = &testInstaller{
+		baseInstaller: baseInstaller{
+			dir:   "nativetest",
+			dir64: "nativetest64",
+			data:  true,
+		},
+	}
+	return module
+}
+
+func NewTestLibrary(hod android.HostOrDeviceSupported) *Module {
+	module := NewLibrary(android.HostAndDeviceSupported, false, true)
+	linker := &testLibraryLinker{
+		libraryLinker: module.linker.(*libraryLinker),
+	}
+	linker.testLinker.Properties.Gtest = true
+	module.linker = linker
+	module.installer = &testInstaller{
+		baseInstaller: baseInstaller{
+			dir:   "nativetest",
+			dir64: "nativetest64",
+			data:  true,
+		},
+	}
+	return module
+}
+
+type benchmarkLinker struct {
+	testBinaryLinker
+}
+
+func (benchmark *benchmarkLinker) deps(ctx BaseModuleContext, deps Deps) Deps {
+	deps = benchmark.testBinaryLinker.deps(ctx, deps)
+	deps.StaticLibs = append(deps.StaticLibs, "libgoogle-benchmark")
+	return deps
+}
+
+func NewBenchmark(hod android.HostOrDeviceSupported) *Module {
+	module := newModule(hod, android.MultilibFirst)
+	module.compiler = &baseCompiler{}
+	module.linker = &benchmarkLinker{}
+	module.installer = &testInstaller{
+		baseInstaller: baseInstaller{
+			dir:   "nativetest",
+			dir64: "nativetest64",
+			data:  true,
+		},
+	}
+	return module
+}