| Colin Cross | 4d9c2d1 | 2016-07-29 12:48:20 -0700 | [diff] [blame] | 1 | // Copyright 2016 Google Inc. All rights reserved. | 
|  | 2 | // | 
|  | 3 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | 4 | // you may not use this file except in compliance with the License. | 
|  | 5 | // You may obtain a copy of the License at | 
|  | 6 | // | 
|  | 7 | //     http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 8 | // | 
|  | 9 | // Unless required by applicable law or agreed to in writing, software | 
|  | 10 | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 12 | // See the License for the specific language governing permissions and | 
|  | 13 | // limitations under the License. | 
|  | 14 |  | 
|  | 15 | package cc | 
|  | 16 |  | 
|  | 17 | import ( | 
|  | 18 | "path/filepath" | 
|  | 19 | "strings" | 
|  | 20 |  | 
|  | 21 | "github.com/google/blueprint" | 
|  | 22 |  | 
|  | 23 | "android/soong" | 
|  | 24 | "android/soong/android" | 
|  | 25 | ) | 
|  | 26 |  | 
| Colin Cross | b916a38 | 2016-07-29 17:28:03 -0700 | [diff] [blame] | 27 | type TestProperties struct { | 
| Colin Cross | 4d9c2d1 | 2016-07-29 12:48:20 -0700 | [diff] [blame] | 28 | // if set, build against the gtest library. Defaults to true. | 
|  | 29 | Gtest bool | 
| Colin Cross | b916a38 | 2016-07-29 17:28:03 -0700 | [diff] [blame] | 30 | } | 
| Colin Cross | 4d9c2d1 | 2016-07-29 12:48:20 -0700 | [diff] [blame] | 31 |  | 
| Colin Cross | b916a38 | 2016-07-29 17:28:03 -0700 | [diff] [blame] | 32 | type TestBinaryProperties struct { | 
| Colin Cross | 4d9c2d1 | 2016-07-29 12:48:20 -0700 | [diff] [blame] | 33 | // Create a separate binary for each source file.  Useful when there is | 
|  | 34 | // global state that can not be torn down and reset between each test suite. | 
|  | 35 | Test_per_src *bool | 
|  | 36 | } | 
|  | 37 |  | 
|  | 38 | func init() { | 
|  | 39 | soong.RegisterModuleType("cc_test", testFactory) | 
|  | 40 | soong.RegisterModuleType("cc_test_library", testLibraryFactory) | 
|  | 41 | soong.RegisterModuleType("cc_benchmark", benchmarkFactory) | 
|  | 42 | soong.RegisterModuleType("cc_test_host", testHostFactory) | 
|  | 43 | soong.RegisterModuleType("cc_benchmark_host", benchmarkHostFactory) | 
|  | 44 | } | 
|  | 45 |  | 
|  | 46 | // Module factory for tests | 
|  | 47 | func testFactory() (blueprint.Module, []interface{}) { | 
|  | 48 | module := NewTest(android.HostAndDeviceSupported) | 
|  | 49 | return module.Init() | 
|  | 50 | } | 
|  | 51 |  | 
|  | 52 | // Module factory for test libraries | 
|  | 53 | func testLibraryFactory() (blueprint.Module, []interface{}) { | 
|  | 54 | module := NewTestLibrary(android.HostAndDeviceSupported) | 
|  | 55 | return module.Init() | 
|  | 56 | } | 
|  | 57 |  | 
|  | 58 | // Module factory for benchmarks | 
|  | 59 | func benchmarkFactory() (blueprint.Module, []interface{}) { | 
|  | 60 | module := NewBenchmark(android.HostAndDeviceSupported) | 
|  | 61 | return module.Init() | 
|  | 62 | } | 
|  | 63 |  | 
|  | 64 | // Module factory for host tests | 
|  | 65 | func testHostFactory() (blueprint.Module, []interface{}) { | 
|  | 66 | module := NewTest(android.HostSupported) | 
|  | 67 | return module.Init() | 
|  | 68 | } | 
|  | 69 |  | 
|  | 70 | // Module factory for host benchmarks | 
|  | 71 | func benchmarkHostFactory() (blueprint.Module, []interface{}) { | 
|  | 72 | module := NewBenchmark(android.HostSupported) | 
|  | 73 | return module.Init() | 
|  | 74 | } | 
|  | 75 |  | 
| Colin Cross | b916a38 | 2016-07-29 17:28:03 -0700 | [diff] [blame] | 76 | type testPerSrc interface { | 
|  | 77 | testPerSrc() bool | 
|  | 78 | srcs() []string | 
|  | 79 | setSrc(string, string) | 
|  | 80 | } | 
|  | 81 |  | 
|  | 82 | func (test *testBinary) testPerSrc() bool { | 
|  | 83 | return Bool(test.Properties.Test_per_src) | 
|  | 84 | } | 
|  | 85 |  | 
|  | 86 | func (test *testBinary) srcs() []string { | 
|  | 87 | return test.baseCompiler.Properties.Srcs | 
|  | 88 | } | 
|  | 89 |  | 
|  | 90 | func (test *testBinary) setSrc(name, src string) { | 
|  | 91 | test.baseCompiler.Properties.Srcs = []string{src} | 
|  | 92 | test.binaryDecorator.Properties.Stem = name | 
|  | 93 | } | 
|  | 94 |  | 
|  | 95 | var _ testPerSrc = (*testBinary)(nil) | 
|  | 96 |  | 
| Colin Cross | 4d9c2d1 | 2016-07-29 12:48:20 -0700 | [diff] [blame] | 97 | func testPerSrcMutator(mctx android.BottomUpMutatorContext) { | 
|  | 98 | if m, ok := mctx.Module().(*Module); ok { | 
| Colin Cross | b916a38 | 2016-07-29 17:28:03 -0700 | [diff] [blame] | 99 | if test, ok := m.linker.(testPerSrc); ok { | 
|  | 100 | if test.testPerSrc() && len(test.srcs()) > 0 { | 
|  | 101 | testNames := make([]string, len(test.srcs())) | 
|  | 102 | for i, src := range test.srcs() { | 
| Colin Cross | 4d9c2d1 | 2016-07-29 12:48:20 -0700 | [diff] [blame] | 103 | testNames[i] = strings.TrimSuffix(filepath.Base(src), filepath.Ext(src)) | 
|  | 104 | } | 
|  | 105 | tests := mctx.CreateLocalVariations(testNames...) | 
| Colin Cross | b916a38 | 2016-07-29 17:28:03 -0700 | [diff] [blame] | 106 | for i, src := range test.srcs() { | 
|  | 107 | tests[i].(*Module).linker.(testPerSrc).setSrc(testNames[i], src) | 
| Colin Cross | 4d9c2d1 | 2016-07-29 12:48:20 -0700 | [diff] [blame] | 108 | } | 
|  | 109 | } | 
|  | 110 | } | 
|  | 111 | } | 
|  | 112 | } | 
|  | 113 |  | 
| Colin Cross | b916a38 | 2016-07-29 17:28:03 -0700 | [diff] [blame] | 114 | type testDecorator struct { | 
|  | 115 | Properties TestProperties | 
|  | 116 | linker     *baseLinker | 
| Colin Cross | 4d9c2d1 | 2016-07-29 12:48:20 -0700 | [diff] [blame] | 117 | } | 
|  | 118 |  | 
| Colin Cross | b916a38 | 2016-07-29 17:28:03 -0700 | [diff] [blame] | 119 | func (test *testDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags { | 
| Colin Cross | 4d9c2d1 | 2016-07-29 12:48:20 -0700 | [diff] [blame] | 120 | if !test.Properties.Gtest { | 
|  | 121 | return flags | 
|  | 122 | } | 
|  | 123 |  | 
|  | 124 | flags.CFlags = append(flags.CFlags, "-DGTEST_HAS_STD_STRING") | 
|  | 125 | if ctx.Host() { | 
|  | 126 | flags.CFlags = append(flags.CFlags, "-O0", "-g") | 
|  | 127 |  | 
|  | 128 | switch ctx.Os() { | 
|  | 129 | case android.Windows: | 
|  | 130 | flags.CFlags = append(flags.CFlags, "-DGTEST_OS_WINDOWS") | 
|  | 131 | case android.Linux: | 
|  | 132 | flags.CFlags = append(flags.CFlags, "-DGTEST_OS_LINUX") | 
|  | 133 | flags.LdFlags = append(flags.LdFlags, "-lpthread") | 
|  | 134 | case android.Darwin: | 
|  | 135 | flags.CFlags = append(flags.CFlags, "-DGTEST_OS_MAC") | 
|  | 136 | flags.LdFlags = append(flags.LdFlags, "-lpthread") | 
|  | 137 | } | 
|  | 138 | } else { | 
|  | 139 | flags.CFlags = append(flags.CFlags, "-DGTEST_OS_LINUX_ANDROID") | 
|  | 140 | } | 
|  | 141 |  | 
|  | 142 | return flags | 
|  | 143 | } | 
|  | 144 |  | 
| Colin Cross | b916a38 | 2016-07-29 17:28:03 -0700 | [diff] [blame] | 145 | func (test *testDecorator) linkerDeps(ctx BaseModuleContext, deps Deps) Deps { | 
| Colin Cross | 4d9c2d1 | 2016-07-29 12:48:20 -0700 | [diff] [blame] | 146 | if test.Properties.Gtest { | 
|  | 147 | if ctx.sdk() && ctx.Device() { | 
|  | 148 | switch ctx.selectedStl() { | 
|  | 149 | case "ndk_libc++_shared", "ndk_libc++_static": | 
|  | 150 | deps.StaticLibs = append(deps.StaticLibs, "libgtest_main_ndk_libcxx", "libgtest_ndk_libcxx") | 
|  | 151 | case "ndk_libgnustl_static": | 
|  | 152 | deps.StaticLibs = append(deps.StaticLibs, "libgtest_main_ndk_gnustl", "libgtest_ndk_gnustl") | 
|  | 153 | default: | 
|  | 154 | deps.StaticLibs = append(deps.StaticLibs, "libgtest_main_ndk", "libgtest_ndk") | 
|  | 155 | } | 
|  | 156 | } else { | 
|  | 157 | deps.StaticLibs = append(deps.StaticLibs, "libgtest_main", "libgtest") | 
|  | 158 | } | 
|  | 159 | } | 
| Colin Cross | b916a38 | 2016-07-29 17:28:03 -0700 | [diff] [blame] | 160 |  | 
| Colin Cross | 4d9c2d1 | 2016-07-29 12:48:20 -0700 | [diff] [blame] | 161 | return deps | 
|  | 162 | } | 
|  | 163 |  | 
| Colin Cross | b916a38 | 2016-07-29 17:28:03 -0700 | [diff] [blame] | 164 | func (test *testDecorator) linkerInit(ctx BaseModuleContext, linker *baseLinker) { | 
| Colin Cross | 4d9c2d1 | 2016-07-29 12:48:20 -0700 | [diff] [blame] | 165 | runpath := "../../lib" | 
|  | 166 | if ctx.toolchain().Is64Bit() { | 
|  | 167 | runpath += "64" | 
|  | 168 | } | 
| Colin Cross | b916a38 | 2016-07-29 17:28:03 -0700 | [diff] [blame] | 169 | linker.dynamicProperties.RunPaths = append(linker.dynamicProperties.RunPaths, runpath) | 
| Colin Cross | 4d9c2d1 | 2016-07-29 12:48:20 -0700 | [diff] [blame] | 170 | } | 
|  | 171 |  | 
| Colin Cross | b916a38 | 2016-07-29 17:28:03 -0700 | [diff] [blame] | 172 | func (test *testDecorator) linkerProps() []interface{} { | 
|  | 173 | return []interface{}{&test.Properties} | 
| Colin Cross | 4d9c2d1 | 2016-07-29 12:48:20 -0700 | [diff] [blame] | 174 | } | 
|  | 175 |  | 
| Colin Cross | b916a38 | 2016-07-29 17:28:03 -0700 | [diff] [blame] | 176 | func NewTestInstaller() *baseInstaller { | 
|  | 177 | return NewBaseInstaller("nativetest", "nativetest64", InstallInData) | 
| Colin Cross | 4d9c2d1 | 2016-07-29 12:48:20 -0700 | [diff] [blame] | 178 | } | 
|  | 179 |  | 
| Colin Cross | b916a38 | 2016-07-29 17:28:03 -0700 | [diff] [blame] | 180 | type testBinary struct { | 
|  | 181 | testDecorator | 
|  | 182 | *binaryDecorator | 
|  | 183 | *baseCompiler | 
| Colin Cross | b916a38 | 2016-07-29 17:28:03 -0700 | [diff] [blame] | 184 | Properties TestBinaryProperties | 
|  | 185 | } | 
|  | 186 |  | 
|  | 187 | func (test *testBinary) linkerProps() []interface{} { | 
|  | 188 | props := append(test.testDecorator.linkerProps(), test.binaryDecorator.linkerProps()...) | 
|  | 189 | props = append(props, &test.Properties) | 
|  | 190 | return props | 
|  | 191 | } | 
|  | 192 |  | 
|  | 193 | func (test *testBinary) linkerInit(ctx BaseModuleContext) { | 
|  | 194 | test.testDecorator.linkerInit(ctx, test.binaryDecorator.baseLinker) | 
|  | 195 | test.binaryDecorator.linkerInit(ctx) | 
|  | 196 | } | 
|  | 197 |  | 
|  | 198 | func (test *testBinary) linkerDeps(ctx BaseModuleContext, deps Deps) Deps { | 
|  | 199 | deps = test.testDecorator.linkerDeps(ctx, deps) | 
|  | 200 | deps = test.binaryDecorator.linkerDeps(ctx, deps) | 
| Colin Cross | 4d9c2d1 | 2016-07-29 12:48:20 -0700 | [diff] [blame] | 201 | return deps | 
|  | 202 | } | 
|  | 203 |  | 
| Colin Cross | b916a38 | 2016-07-29 17:28:03 -0700 | [diff] [blame] | 204 | func (test *testBinary) linkerFlags(ctx ModuleContext, flags Flags) Flags { | 
|  | 205 | flags = test.binaryDecorator.linkerFlags(ctx, flags) | 
|  | 206 | flags = test.testDecorator.linkerFlags(ctx, flags) | 
| Colin Cross | 4d9c2d1 | 2016-07-29 12:48:20 -0700 | [diff] [blame] | 207 | return flags | 
|  | 208 | } | 
|  | 209 |  | 
| Colin Cross | b916a38 | 2016-07-29 17:28:03 -0700 | [diff] [blame] | 210 | func (test *testBinary) install(ctx ModuleContext, file android.Path) { | 
| Dan Willemsen | 1d577e2 | 2016-08-29 15:53:15 -0700 | [diff] [blame] | 211 | test.binaryDecorator.baseInstaller.dir = filepath.Join("nativetest", ctx.ModuleName()) | 
|  | 212 | test.binaryDecorator.baseInstaller.dir64 = filepath.Join("nativetest64", ctx.ModuleName()) | 
|  | 213 | test.binaryDecorator.baseInstaller.install(ctx, file) | 
| Colin Cross | 4d9c2d1 | 2016-07-29 12:48:20 -0700 | [diff] [blame] | 214 | } | 
|  | 215 |  | 
|  | 216 | func NewTest(hod android.HostOrDeviceSupported) *Module { | 
| Colin Cross | b916a38 | 2016-07-29 17:28:03 -0700 | [diff] [blame] | 217 | module, binary := NewBinary(hod) | 
|  | 218 | module.multilib = android.MultilibBoth | 
| Dan Willemsen | 1d577e2 | 2016-08-29 15:53:15 -0700 | [diff] [blame] | 219 | binary.baseInstaller = NewTestInstaller() | 
| Colin Cross | b916a38 | 2016-07-29 17:28:03 -0700 | [diff] [blame] | 220 |  | 
|  | 221 | test := &testBinary{ | 
|  | 222 | testDecorator: testDecorator{ | 
|  | 223 | linker: binary.baseLinker, | 
| Colin Cross | 4d9c2d1 | 2016-07-29 12:48:20 -0700 | [diff] [blame] | 224 | }, | 
| Colin Cross | b916a38 | 2016-07-29 17:28:03 -0700 | [diff] [blame] | 225 | binaryDecorator: binary, | 
|  | 226 | baseCompiler:    NewBaseCompiler(), | 
| Colin Cross | 4d9c2d1 | 2016-07-29 12:48:20 -0700 | [diff] [blame] | 227 | } | 
| Colin Cross | b916a38 | 2016-07-29 17:28:03 -0700 | [diff] [blame] | 228 | test.testDecorator.Properties.Gtest = true | 
|  | 229 | module.compiler = test | 
|  | 230 | module.linker = test | 
|  | 231 | module.installer = test | 
| Colin Cross | 4d9c2d1 | 2016-07-29 12:48:20 -0700 | [diff] [blame] | 232 | return module | 
|  | 233 | } | 
|  | 234 |  | 
| Colin Cross | b916a38 | 2016-07-29 17:28:03 -0700 | [diff] [blame] | 235 | type testLibrary struct { | 
|  | 236 | testDecorator | 
|  | 237 | *libraryDecorator | 
|  | 238 | } | 
|  | 239 |  | 
|  | 240 | func (test *testLibrary) linkerProps() []interface{} { | 
|  | 241 | return append(test.testDecorator.linkerProps(), test.libraryDecorator.linkerProps()...) | 
|  | 242 | } | 
|  | 243 |  | 
|  | 244 | func (test *testLibrary) linkerInit(ctx BaseModuleContext) { | 
|  | 245 | test.testDecorator.linkerInit(ctx, test.libraryDecorator.baseLinker) | 
|  | 246 | test.libraryDecorator.linkerInit(ctx) | 
|  | 247 | } | 
|  | 248 |  | 
|  | 249 | func (test *testLibrary) linkerDeps(ctx BaseModuleContext, deps Deps) Deps { | 
|  | 250 | deps = test.testDecorator.linkerDeps(ctx, deps) | 
|  | 251 | deps = test.libraryDecorator.linkerDeps(ctx, deps) | 
|  | 252 | return deps | 
|  | 253 | } | 
|  | 254 |  | 
|  | 255 | func (test *testLibrary) linkerFlags(ctx ModuleContext, flags Flags) Flags { | 
|  | 256 | flags = test.libraryDecorator.linkerFlags(ctx, flags) | 
|  | 257 | flags = test.testDecorator.linkerFlags(ctx, flags) | 
|  | 258 | return flags | 
|  | 259 | } | 
|  | 260 |  | 
| Colin Cross | 4d9c2d1 | 2016-07-29 12:48:20 -0700 | [diff] [blame] | 261 | func NewTestLibrary(hod android.HostOrDeviceSupported) *Module { | 
| Dan Willemsen | 28bda51 | 2016-08-31 16:32:55 -0700 | [diff] [blame] | 262 | module, library := NewLibrary(android.HostAndDeviceSupported, true, true) | 
|  | 263 | library.baseInstaller = NewTestInstaller() | 
| Colin Cross | b916a38 | 2016-07-29 17:28:03 -0700 | [diff] [blame] | 264 | test := &testLibrary{ | 
|  | 265 | testDecorator: testDecorator{ | 
|  | 266 | linker: library.baseLinker, | 
| Colin Cross | 4d9c2d1 | 2016-07-29 12:48:20 -0700 | [diff] [blame] | 267 | }, | 
| Colin Cross | b916a38 | 2016-07-29 17:28:03 -0700 | [diff] [blame] | 268 | libraryDecorator: library, | 
| Colin Cross | 4d9c2d1 | 2016-07-29 12:48:20 -0700 | [diff] [blame] | 269 | } | 
| Colin Cross | b916a38 | 2016-07-29 17:28:03 -0700 | [diff] [blame] | 270 | test.testDecorator.Properties.Gtest = true | 
|  | 271 | module.linker = test | 
| Colin Cross | 4d9c2d1 | 2016-07-29 12:48:20 -0700 | [diff] [blame] | 272 | return module | 
|  | 273 | } | 
|  | 274 |  | 
| Colin Cross | b916a38 | 2016-07-29 17:28:03 -0700 | [diff] [blame] | 275 | type benchmarkDecorator struct { | 
|  | 276 | *binaryDecorator | 
| Colin Cross | 4d9c2d1 | 2016-07-29 12:48:20 -0700 | [diff] [blame] | 277 | } | 
|  | 278 |  | 
| Colin Cross | b916a38 | 2016-07-29 17:28:03 -0700 | [diff] [blame] | 279 | func (benchmark *benchmarkDecorator) linkerInit(ctx BaseModuleContext) { | 
|  | 280 | runpath := "../../lib" | 
|  | 281 | if ctx.toolchain().Is64Bit() { | 
|  | 282 | runpath += "64" | 
|  | 283 | } | 
|  | 284 | benchmark.baseLinker.dynamicProperties.RunPaths = append(benchmark.baseLinker.dynamicProperties.RunPaths, runpath) | 
|  | 285 | benchmark.binaryDecorator.linkerInit(ctx) | 
|  | 286 | } | 
|  | 287 |  | 
|  | 288 | func (benchmark *benchmarkDecorator) linkerDeps(ctx BaseModuleContext, deps Deps) Deps { | 
|  | 289 | deps = benchmark.binaryDecorator.linkerDeps(ctx, deps) | 
| Colin Cross | 4d9c2d1 | 2016-07-29 12:48:20 -0700 | [diff] [blame] | 290 | deps.StaticLibs = append(deps.StaticLibs, "libgoogle-benchmark") | 
|  | 291 | return deps | 
|  | 292 | } | 
|  | 293 |  | 
| Colin Cross | b916a38 | 2016-07-29 17:28:03 -0700 | [diff] [blame] | 294 | func (benchmark *benchmarkDecorator) install(ctx ModuleContext, file android.Path) { | 
| Dan Willemsen | 1d577e2 | 2016-08-29 15:53:15 -0700 | [diff] [blame] | 295 | benchmark.binaryDecorator.baseInstaller.dir = filepath.Join("nativetest", ctx.ModuleName()) | 
|  | 296 | benchmark.binaryDecorator.baseInstaller.dir64 = filepath.Join("nativetest64", ctx.ModuleName()) | 
|  | 297 | benchmark.binaryDecorator.baseInstaller.install(ctx, file) | 
| Colin Cross | b916a38 | 2016-07-29 17:28:03 -0700 | [diff] [blame] | 298 | } | 
|  | 299 |  | 
| Colin Cross | 4d9c2d1 | 2016-07-29 12:48:20 -0700 | [diff] [blame] | 300 | func NewBenchmark(hod android.HostOrDeviceSupported) *Module { | 
| Colin Cross | b916a38 | 2016-07-29 17:28:03 -0700 | [diff] [blame] | 301 | module, binary := NewBinary(hod) | 
|  | 302 | module.multilib = android.MultilibBoth | 
| Dan Willemsen | 1d577e2 | 2016-08-29 15:53:15 -0700 | [diff] [blame] | 303 | binary.baseInstaller = NewTestInstaller() | 
| Colin Cross | b916a38 | 2016-07-29 17:28:03 -0700 | [diff] [blame] | 304 |  | 
|  | 305 | benchmark := &benchmarkDecorator{ | 
|  | 306 | binaryDecorator: binary, | 
| Colin Cross | 4d9c2d1 | 2016-07-29 12:48:20 -0700 | [diff] [blame] | 307 | } | 
| Colin Cross | b916a38 | 2016-07-29 17:28:03 -0700 | [diff] [blame] | 308 | module.linker = benchmark | 
|  | 309 | module.installer = benchmark | 
| Colin Cross | 4d9c2d1 | 2016-07-29 12:48:20 -0700 | [diff] [blame] | 310 | return module | 
|  | 311 | } |