Home | History | Annotate | Download | only in cc
      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