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