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 "runtime" 20 "strings" 21 22 "android/soong/android" 23 ) 24 25 type TestProperties struct { 26 // if set, build against the gtest library. Defaults to true. 27 Gtest *bool 28 } 29 30 type TestBinaryProperties struct { 31 // Create a separate binary for each source file. Useful when there is 32 // global state that can not be torn down and reset between each test suite. 33 Test_per_src *bool 34 35 // Disables the creation of a test-specific directory when used with 36 // relative_install_path. Useful if several tests need to be in the same 37 // directory, but test_per_src doesn't work. 38 No_named_install_directory *bool 39 40 // list of files or filegroup modules that provide data that should be installed alongside 41 // the test 42 Data []string 43 44 // list of compatibility suites (for example "cts", "vts") that the module should be 45 // installed into. 46 Test_suites []string 47 } 48 49 func init() { 50 android.RegisterModuleType("cc_test", testFactory) 51 android.RegisterModuleType("cc_test_library", testLibraryFactory) 52 android.RegisterModuleType("cc_benchmark", benchmarkFactory) 53 android.RegisterModuleType("cc_test_host", testHostFactory) 54 android.RegisterModuleType("cc_benchmark_host", benchmarkHostFactory) 55 } 56 57 // Module factory for tests 58 func testFactory() android.Module { 59 module := NewTest(android.HostAndDeviceSupported) 60 return module.Init() 61 } 62 63 // Module factory for test libraries 64 func testLibraryFactory() android.Module { 65 module := NewTestLibrary(android.HostAndDeviceSupported) 66 return module.Init() 67 } 68 69 // Module factory for benchmarks 70 func benchmarkFactory() android.Module { 71 module := NewBenchmark(android.HostAndDeviceSupported) 72 return module.Init() 73 } 74 75 // Module factory for host tests 76 func testHostFactory() android.Module { 77 module := NewTest(android.HostSupported) 78 return module.Init() 79 } 80 81 // Module factory for host benchmarks 82 func benchmarkHostFactory() android.Module { 83 module := NewBenchmark(android.HostSupported) 84 return module.Init() 85 } 86 87 type testPerSrc interface { 88 testPerSrc() bool 89 srcs() []string 90 setSrc(string, string) 91 } 92 93 func (test *testBinary) testPerSrc() bool { 94 return Bool(test.Properties.Test_per_src) 95 } 96 97 func (test *testBinary) srcs() []string { 98 return test.baseCompiler.Properties.Srcs 99 } 100 101 func (test *testBinary) setSrc(name, src string) { 102 test.baseCompiler.Properties.Srcs = []string{src} 103 test.binaryDecorator.Properties.Stem = name 104 } 105 106 var _ testPerSrc = (*testBinary)(nil) 107 108 func testPerSrcMutator(mctx android.BottomUpMutatorContext) { 109 if m, ok := mctx.Module().(*Module); ok { 110 if test, ok := m.linker.(testPerSrc); ok { 111 if test.testPerSrc() && len(test.srcs()) > 0 { 112 testNames := make([]string, len(test.srcs())) 113 for i, src := range test.srcs() { 114 testNames[i] = strings.TrimSuffix(filepath.Base(src), filepath.Ext(src)) 115 } 116 tests := mctx.CreateLocalVariations(testNames...) 117 for i, src := range test.srcs() { 118 tests[i].(*Module).linker.(testPerSrc).setSrc(testNames[i], src) 119 } 120 } 121 } 122 } 123 } 124 125 type testDecorator struct { 126 Properties TestProperties 127 linker *baseLinker 128 } 129 130 func (test *testDecorator) gtest() bool { 131 return test.Properties.Gtest == nil || *test.Properties.Gtest == true 132 } 133 134 func (test *testDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags { 135 if !test.gtest() { 136 return flags 137 } 138 139 flags.CFlags = append(flags.CFlags, "-DGTEST_HAS_STD_STRING") 140 if ctx.Host() { 141 flags.CFlags = append(flags.CFlags, "-O0", "-g") 142 143 switch ctx.Os() { 144 case android.Windows: 145 flags.CFlags = append(flags.CFlags, "-DGTEST_OS_WINDOWS") 146 case android.Linux: 147 flags.CFlags = append(flags.CFlags, "-DGTEST_OS_LINUX") 148 flags.LdFlags = append(flags.LdFlags, "-lpthread") 149 case android.Darwin: 150 flags.CFlags = append(flags.CFlags, "-DGTEST_OS_MAC") 151 flags.LdFlags = append(flags.LdFlags, "-lpthread") 152 } 153 } else { 154 flags.CFlags = append(flags.CFlags, "-DGTEST_OS_LINUX_ANDROID") 155 } 156 157 return flags 158 } 159 160 func (test *testDecorator) linkerDeps(ctx BaseModuleContext, deps Deps) Deps { 161 if test.gtest() { 162 if ctx.sdk() && ctx.Device() { 163 switch ctx.selectedStl() { 164 case "ndk_libc++_shared", "ndk_libc++_static": 165 deps.StaticLibs = append(deps.StaticLibs, "libgtest_main_ndk_libcxx", "libgtest_ndk_libcxx") 166 case "ndk_libgnustl_static": 167 deps.StaticLibs = append(deps.StaticLibs, "libgtest_main_ndk_gnustl", "libgtest_ndk_gnustl") 168 default: 169 deps.StaticLibs = append(deps.StaticLibs, "libgtest_main_ndk", "libgtest_ndk") 170 } 171 } else { 172 deps.StaticLibs = append(deps.StaticLibs, "libgtest_main", "libgtest") 173 } 174 } 175 176 return deps 177 } 178 179 func (test *testDecorator) linkerInit(ctx BaseModuleContext, linker *baseLinker) { 180 runpath := "../../lib" 181 if ctx.toolchain().Is64Bit() { 182 runpath += "64" 183 } 184 linker.dynamicProperties.RunPaths = append(linker.dynamicProperties.RunPaths, runpath) 185 } 186 187 func (test *testDecorator) linkerProps() []interface{} { 188 return []interface{}{&test.Properties} 189 } 190 191 func NewTestInstaller() *baseInstaller { 192 return NewBaseInstaller("nativetest", "nativetest64", InstallInData) 193 } 194 195 type testBinary struct { 196 testDecorator 197 *binaryDecorator 198 *baseCompiler 199 Properties TestBinaryProperties 200 data android.Paths 201 } 202 203 func (test *testBinary) linkerProps() []interface{} { 204 props := append(test.testDecorator.linkerProps(), test.binaryDecorator.linkerProps()...) 205 props = append(props, &test.Properties) 206 return props 207 } 208 209 func (test *testBinary) linkerInit(ctx BaseModuleContext) { 210 test.testDecorator.linkerInit(ctx, test.binaryDecorator.baseLinker) 211 test.binaryDecorator.linkerInit(ctx) 212 } 213 214 func (test *testBinary) linkerDeps(ctx DepsContext, deps Deps) Deps { 215 android.ExtractSourcesDeps(ctx, test.Properties.Data) 216 217 deps = test.testDecorator.linkerDeps(ctx, deps) 218 deps = test.binaryDecorator.linkerDeps(ctx, deps) 219 return deps 220 } 221 222 func (test *testBinary) linkerFlags(ctx ModuleContext, flags Flags) Flags { 223 flags = test.binaryDecorator.linkerFlags(ctx, flags) 224 flags = test.testDecorator.linkerFlags(ctx, flags) 225 return flags 226 } 227 228 func (test *testBinary) install(ctx ModuleContext, file android.Path) { 229 test.data = ctx.ExpandSources(test.Properties.Data, nil) 230 231 test.binaryDecorator.baseInstaller.dir = "nativetest" 232 test.binaryDecorator.baseInstaller.dir64 = "nativetest64" 233 234 if !Bool(test.Properties.No_named_install_directory) { 235 test.binaryDecorator.baseInstaller.relative = ctx.ModuleName() 236 } else if test.binaryDecorator.baseInstaller.Properties.Relative_install_path == "" { 237 ctx.PropertyErrorf("no_named_install_directory", "Module install directory may only be disabled if relative_install_path is set") 238 } 239 240 test.binaryDecorator.baseInstaller.install(ctx, file) 241 } 242 243 func NewTest(hod android.HostOrDeviceSupported) *Module { 244 module, binary := NewBinary(hod) 245 module.multilib = android.MultilibBoth 246 binary.baseInstaller = NewTestInstaller() 247 248 test := &testBinary{ 249 testDecorator: testDecorator{ 250 linker: binary.baseLinker, 251 }, 252 binaryDecorator: binary, 253 baseCompiler: NewBaseCompiler(), 254 } 255 module.compiler = test 256 module.linker = test 257 module.installer = test 258 return module 259 } 260 261 type testLibrary struct { 262 testDecorator 263 *libraryDecorator 264 } 265 266 func (test *testLibrary) linkerProps() []interface{} { 267 return append(test.testDecorator.linkerProps(), test.libraryDecorator.linkerProps()...) 268 } 269 270 func (test *testLibrary) linkerInit(ctx BaseModuleContext) { 271 test.testDecorator.linkerInit(ctx, test.libraryDecorator.baseLinker) 272 test.libraryDecorator.linkerInit(ctx) 273 } 274 275 func (test *testLibrary) linkerDeps(ctx DepsContext, deps Deps) Deps { 276 deps = test.testDecorator.linkerDeps(ctx, deps) 277 deps = test.libraryDecorator.linkerDeps(ctx, deps) 278 return deps 279 } 280 281 func (test *testLibrary) linkerFlags(ctx ModuleContext, flags Flags) Flags { 282 flags = test.libraryDecorator.linkerFlags(ctx, flags) 283 flags = test.testDecorator.linkerFlags(ctx, flags) 284 return flags 285 } 286 287 func NewTestLibrary(hod android.HostOrDeviceSupported) *Module { 288 module, library := NewLibrary(android.HostAndDeviceSupported) 289 library.baseInstaller = NewTestInstaller() 290 test := &testLibrary{ 291 testDecorator: testDecorator{ 292 linker: library.baseLinker, 293 }, 294 libraryDecorator: library, 295 } 296 module.linker = test 297 return module 298 } 299 300 type BenchmarkProperties struct { 301 // list of files or filegroup modules that provide data that should be installed alongside 302 // the test 303 Data []string 304 305 // list of compatibility suites (for example "cts", "vts") that the module should be 306 // installed into. 307 Test_suites []string 308 } 309 310 type benchmarkDecorator struct { 311 *binaryDecorator 312 Properties BenchmarkProperties 313 data android.Paths 314 } 315 316 func (benchmark *benchmarkDecorator) linkerInit(ctx BaseModuleContext) { 317 runpath := "../../lib" 318 if ctx.toolchain().Is64Bit() { 319 runpath += "64" 320 } 321 benchmark.baseLinker.dynamicProperties.RunPaths = append(benchmark.baseLinker.dynamicProperties.RunPaths, runpath) 322 benchmark.binaryDecorator.linkerInit(ctx) 323 } 324 325 func (benchmark *benchmarkDecorator) linkerProps() []interface{} { 326 props := benchmark.binaryDecorator.linkerProps() 327 props = append(props, &benchmark.Properties) 328 return props 329 } 330 331 func (benchmark *benchmarkDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps { 332 android.ExtractSourcesDeps(ctx, benchmark.Properties.Data) 333 deps = benchmark.binaryDecorator.linkerDeps(ctx, deps) 334 deps.StaticLibs = append(deps.StaticLibs, "libgoogle-benchmark") 335 return deps 336 } 337 338 func (benchmark *benchmarkDecorator) install(ctx ModuleContext, file android.Path) { 339 benchmark.data = ctx.ExpandSources(benchmark.Properties.Data, nil) 340 benchmark.binaryDecorator.baseInstaller.dir = filepath.Join("nativetest", ctx.ModuleName()) 341 benchmark.binaryDecorator.baseInstaller.dir64 = filepath.Join("nativetest64", ctx.ModuleName()) 342 benchmark.binaryDecorator.baseInstaller.install(ctx, file) 343 } 344 345 func NewBenchmark(hod android.HostOrDeviceSupported) *Module { 346 // Benchmarks aren't supported on Darwin 347 if runtime.GOOS == "darwin" { 348 switch hod { 349 case android.HostAndDeviceSupported: 350 hod = android.DeviceSupported 351 case android.HostSupported: 352 hod = android.NeitherHostNorDeviceSupported 353 } 354 } 355 356 module, binary := NewBinary(hod) 357 module.multilib = android.MultilibBoth 358 binary.baseInstaller = NewTestInstaller() 359 360 benchmark := &benchmarkDecorator{ 361 binaryDecorator: binary, 362 } 363 module.linker = benchmark 364 module.installer = benchmark 365 return module 366 } 367